{"id":13758514,"url":"https://github.com/simonkowallik/irulescan","last_synced_at":"2025-04-22T20:25:05.348Z","repository":{"id":145419531,"uuid":"579633280","full_name":"simonkowallik/irulescan","owner":"simonkowallik","description":":shield: irulescan - security analyzer for iRules","archived":false,"fork":false,"pushed_at":"2024-12-29T15:16:43.000Z","size":127,"stargazers_count":6,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-18T20:22:54.824Z","etag":null,"topics":["dast","docker","docker-image","f5","f5-bigip","f5networks","irules","sast","security","security-tools","static-code-analysis","tcl"],"latest_commit_sha":null,"homepage":"https://simonkowallik.github.io/irulescan/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simonkowallik.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-18T11:05:18.000Z","updated_at":"2024-12-29T12:28:57.000Z","dependencies_parsed_at":null,"dependency_job_id":"2217db96-62db-4cc3-b106-eca118d89f02","html_url":"https://github.com/simonkowallik/irulescan","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonkowallik%2Firulescan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonkowallik%2Firulescan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonkowallik%2Firulescan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonkowallik%2Firulescan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simonkowallik","download_url":"https://codeload.github.com/simonkowallik/irulescan/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250317113,"owners_count":21410687,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dast","docker","docker-image","f5","f5-bigip","f5networks","irules","sast","security","security-tools","static-code-analysis","tcl"],"created_at":"2024-08-03T13:00:31.609Z","updated_at":"2025-04-22T20:25:05.323Z","avatar_url":"https://github.com/simonkowallik.png","language":"Rust","funding_links":[],"categories":["DevOps / CICD","MCP Servers \u0026 Protocol"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003ca href=\"https://github.com/simonkowallik/irulescan\"\u003e\n    \u003cimg src=\"https://github.com/simonkowallik/hosted_content/raw/main/images/irulescan.png\" alt=\"irulescan\"\u003e\n\u003c/a\u003e\n\u003cbr/\u003e\n    \u003cem\u003esecurity analyzer for iRules\u003c/em\u003e\n\u003c/p\u003e\n\n---\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://github.com/simonkowallik/irulescan/actions/workflows/test.yaml\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/simonkowallik/irulescan/test.yaml\" alt=\"build\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://hub.docker.com/r/simonkowallik/irulescan\"\u003e\n    \u003cimg src=\"https://img.shields.io/docker/image-size/simonkowallik/irulescan\" alt=\"container image size\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/simonkowallik/irulescan/releases\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/v/release/simonkowallik/irulescan\" alt=\"releases\"\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\n`irulescan` is a tool to scan iRules for unexpected/unsafe expressions that may have undesirable effects like double substitution and additional issues.\n\n`irulescan` would not exist without [tclscan](https://github.com/aidanhs/tclscan).\n\nIt is available as a docker/container image as well as a Github Action [`irulescan-action`](https://github.com/marketplace/actions/irules-security-scan).\n\n## Usage\n\nIt is easiest to use the irulescan container to scan your iRules, available via [docker hub](https://hub.docker.com/r/simonkowallik/irulescan) as well as [ghcr.io](https://github.com/simonkowallik/irulescan/pkgs/container/irulescan).\n\nThe container will recursively scan files in the `/scandir` directory within the container and return results in JSON format.\nOnly files with the (case insensitive) extensions `.tcl`, `.irul` and `.irule` will be scanned.\n\n### Command line\n\nScanning all iRules in a directory recursively (`$PWD/tests/basic`):\n\n```shell\ndocker run --rm -v \"$PWD/tests/basic:/scandir\" simonkowallik/irulescan\n```\n\n```json\n[\n  {\n    \"filepath\": \"dangerous.tcl\",\n    \"warning\": [\n      \"Unquoted expr at `1` in `expr 1 + $one`\",\n      \"Unquoted expr at `+` in `expr 1 + $one`\"\n    ],\n    \"dangerous\": [\"Dangerous unquoted expr at `$one` in `expr 1 + $one`\"]\n  },\n  {\n    \"filepath\": \"ok.tcl\",\n    \"warning\": [],\n    \"dangerous\": []\n  },\n  {\n    \"filepath\": \"warning.tcl\",\n    \"warning\": [\n      \"Unquoted expr at `1` in `expr 1 + 1`\",\n      \"Unquoted expr at `+` in `expr 1 + 1`\",\n      \"Unquoted expr at `1` in `expr 1 + 1`\"\n    ],\n    \"dangerous\": []\n  }\n]\n```\n\nIf you plan to use irulescan frequently, consider adding a shell function to wrap the container execution and add it in your shell, eg. in your `.bashrc` or similar.\n\n```shell\nirulescan(){ docker run --rm -i -v \"$PWD:$PWD\" -w \"$PWD\" simonkowallik/irulescan:latest \"${@:--help}\"; }\n# invoke ephemeral (--rm) container interactively (-i)\n# bind mount (-v) PWD to the same path and use it as workdir (-w)\n# pass any parameters, if none/empty, pass \"help\" (\"${@:--help}\")\n```\n\n```console\nirulescan check --exclude-empty-findings ./tests/basic/ | jq\n```\n\n```json\n[\n  {\n    \"filepath\": \"tests/basic/dangerous.tcl\",\n    \"warning\": [\n      \"Unquoted expr at `1` in `expr 1 + $one`\",\n      \"Unquoted expr at `+` in `expr 1 + $one`\"\n    ],\n    \"dangerous\": [\"Dangerous unquoted expr at `$one` in `expr 1 + $one`\"]\n  },\n  {\n    \"filepath\": \"tests/basic/warning.tcl\",\n    \"warning\": [\n      \"Unquoted expr at `1` in `expr 1 + 1`\",\n      \"Unquoted expr at `+` in `expr 1 + 1`\",\n      \"Unquoted expr at `1` in `expr 1 + 1`\"\n    ],\n    \"dangerous\": []\n  }\n]\n```\n\n\u003e[!NOTE]\n\u003e Please note the differences in `\"filepath\"` between the two invocation methods.\n\u003e This is important to consider when comparing a new scan to existing results.\n\u003e `--exclude-empty-findings` removes the entry for the file `\"ok.tcl\"` as it has no findings.\n\u003e `cd tests/basic; irulescan check . | jq` would have provided the same results as the docker command from the previous example.\n\nWhen specifying a file, irulescan will try to scan the file regardless of the file extension.\n\n```console\nirulescan check --no-warn tests/basic/dangerous.txt\n```\n\n```json\n[{\"filepath\":\"tests/basic/dangerous.txt\",\"warning\":[],\"dangerous\":[\"Dangerous unquoted expr at `$one` in `expr 1 + $one`\"]}]\n```\n\n```console\nirulescan --help\n```\n\n```console\nirulescan is a tool to scan iRules for unexpected/unsafe expressions that may have undesirable effects like double substitution.\nhome: https://github.com/simonkowallik/irulescan\n\nUsage: irulescan \u003cCOMMAND\u003e\n\nCommands:\n  check     Scan all iRules in a directory (recursively) or the specified file\n  checkref  Scan all iRules in reference file (JSON) and compare to reference\n  parsestr  Parse given string or stdin\n  help      Print this message or the help of the given subcommand(s)\n\nOptions:\n  -h, --help\n          Print help (see a summary with '-h')\n\n  -V, --version\n          Print version\n```\n\n## Using irulescan in CI\n\nThe container uses `irulescan` as the entry point with the default CMD set to `check .` which will scan `/scandir` recursively.\n\nWhen using a CI system with custom mount points (eg. `/custom/path`), this can be easily supported by passing a new CMD like below. Note that, like outlined above, this will change the prefix of `\"filepath\"` for each iRule file.\n\n```shell\ndocker run --rm \\\n  -v \"$PWD/tests/tcl/:/custom/path\" \\\n  simonkowallik/irulescan check /custom/path\n```\n\nAlso have a look at [GitHub Action: irulescan-action](https://github.com/simonkowallik/irulescan-action), which can be used when using GitHub.\n\nAlternatives are using the API Server (see below) or invoke the irulescan container as outlined above. Consider creating a scan result file to compare against known findings and known iRules. Any change in findings could then be used to fail the CI run.\n\n## Check results against a reference (previous scan result)\n\nThe `checkref` command can be used to check each file listed in that reference file. The reference file is just a saved scan. See examples below.\n\n```console\nirulescan/ $ cd ./tests/basic\n```\n\nUsing a previous scan result (`irulescan.json`) and passing it to `checkref` via STDIN. If the check is successful, the exist code will be 0.\n\n```console\n$ cat irulescan.json | irulescan checkref -\nOK\n\n$ echo $?\n0\n```\n\nRe-checking `irulescan_nowarn.json` with no additional options.\n\n```console\n$ irulescan checkref irulescan_nowarn.json\nFailed reference check!\nExtra in scan_results: .[0].warning.[0].(\"Unquoted expr at `+` in `expr 1 + $one`\")\nExtra in scan_results: .[0].warning.[1].(\"Unquoted expr at `1` in `expr 1 + $one`\")\n\n$ echo $?\n1\n```\n\nThe above example produces a failed check as the scan results produce additional findings. The exit code is 1.\n\nThe previous scan result `irulescan_nowarn.json` does not contain any warnings, using the `--no-warn` option the check succeeds.\n\n```console\n$ irulescan checkref --no-warn irulescan_nowarn.json\nOK\n\n$ echo $?\n0\n```\n\n### CLI exit codes\n\nWhen using the `irulescan check` command:\n\n- Always exits with code `0` no matter what findings are produced\n- Errors lead to a non-zero exit code (eg. a crash)\n\nWhen using the `irulescan checkref` command:\n\n- Exits with code `0` when the reference scan matches the current results\n- Exits with code `1` when the reference scan does NOT match the current results\n- Errors lead to a non-zero exit code (eg. a crash)\n\n### API Server\n\nThe irulescan container tag `:apiserver` provides a simple Swagger / OpenAPI server for scanning iRule code or multiple files.\n\nStart the API server:\n\n```shell\ndocker run -t --rm -p 8000:8000 simonkowallik/irulescan:apiserver\n```\n\nScanning a single file / iRule code:\n\n```shell\ncurl -s http://localhost/scan/ \\\n  --data-binary '@tests/basic/dangerous.tcl' | jq\n```\n\n```json\n{\n  \"warning\": [\n    \"Unquoted expr at `1` in `expr 1 + $one`\",\n    \"Unquoted expr at `+` in `expr 1 + $one`\"\n  ],\n  \"dangerous\": [\n    \"Dangerous unquoted expr at `$one` in `expr 1 + $one`\"\n  ]\n}\n```\n\nScanning multiple files:\n\n```shell\ncurl -s http://localhost/scanfiles/ \\\n  -F 'file=@tests/basic/warning.tcl' \\\n  -F 'file=@tests/basic/ok.tcl' \\\n  | jq\n```\n\n```json\n[\n  {\n    \"filepath\": \"ok.tcl\",\n    \"warning\": [],\n    \"dangerous\": []\n  },\n  {\n    \"filepath\": \"warning.tcl\",\n    \"warning\": [\n      \"Unquoted expr at `1` in `expr 1 + 1`\",\n      \"Unquoted expr at `+` in `expr 1 + 1`\",\n      \"Unquoted expr at `1` in `expr 1 + 1`\"\n    ],\n    \"dangerous\": []\n  }\n]\n```\n\nHere is a demo of the Swagger UI:\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://github.com/simonkowallik/irulescan\"\u003e\n\u003cimg src=\"https://github.com/simonkowallik/hosted_content/raw/main/images/irulescan_apiserver.gif\" alt=\"simonkowallik/irulescan:apiserver\"\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\n## Additional resources\n\nFor safer authoring the VS Code iRules Extension is highly recommended:\n\n- [F5 Networks iRules by bitwisecook](https://marketplace.visualstudio.com/items?itemName=bitwisecook.iRule) [on github](https://github.com/bitwisecook/vscode-iRule)\n\n- [Avoiding Common iRules Security Pitfalls on F5 DevCentral](https://community.f5.com/t5/technical-articles/avoiding-common-irules-security-pitfalls/ta-p/306623)\n\n- [iRules Style Guide on F5 DevCentral](https://community.f5.com/t5/technical-articles/irules-style-guide/ta-p/305921)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonkowallik%2Firulescan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimonkowallik%2Firulescan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonkowallik%2Firulescan/lists"}