{"id":50425476,"url":"https://github.com/pmarreck/llm_security_review","last_synced_at":"2026-05-31T10:03:49.495Z","repository":{"id":357949462,"uuid":"1239212100","full_name":"pmarreck/llm_security_review","owner":"pmarreck","description":"LLM-driven per-file security review: a pattern and a Bash tool that runs language-specific security audits (Zig/Elixir today, OWASP-generic fallback) via claude/codex/gemini CLIs","archived":false,"fork":false,"pushed_at":"2026-05-14T23:56:46.000Z","size":41,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"yolo","last_synced_at":"2026-05-15T01:39:42.297Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","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/pmarreck.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-14T21:50:48.000Z","updated_at":"2026-05-14T23:56:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pmarreck/llm_security_review","commit_stats":null,"previous_names":["pmarreck/llm_security_review"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/pmarreck/llm_security_review","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmarreck%2Fllm_security_review","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmarreck%2Fllm_security_review/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmarreck%2Fllm_security_review/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmarreck%2Fllm_security_review/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pmarreck","download_url":"https://codeload.github.com/pmarreck/llm_security_review/tar.gz/refs/heads/yolo","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmarreck%2Fllm_security_review/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33726722,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2026-05-31T10:03:48.842Z","updated_at":"2026-05-31T10:03:49.486Z","avatar_url":"https://github.com/pmarreck.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# llm_security_review\n\nA pattern and a tool for running per-file security reviews against a source\ntree by shelling out to a local LLM CLI (Claude Code, Codex, Gemini).\n\nThe pattern is simple: each source file is sent to the LLM with a prompt that\nencodes a senior application-security engineer's review methodology — an\ninventory of sinks first, then a per-sink trace / boundary / validate /\nimpact pass, with an OWASP Top 10 sweep at the end. Findings get spliced into\na master Markdown doc, one section per file, with HTML-comment markers\ncarrying the review timestamp and the source file's mtime so reruns only\nre-review files that have changed since.\n\nThis repo contains three things:\n\n- `elixir_reviewer.ex` — the original Elixir module that this pattern grew\n  from. Useful as a reference if you want to embed the same prompts inside a\n  larger Elixir/BEAM agent pipeline.\n- `secreview` — a single-file Bash script that orchestrates the same idea\n  from the shell. Walks a path, filters by extension, picks the right prompt\n  variant per language, shells out to claude / codex / gemini, and manages\n  the master findings doc.\n- `bin/llm-security-review` — symlink to `secreview` with a PATH-friendly,\n  unambiguous name. If you keep a `bin/` directory on `PATH` (a common\n  dotfile pattern), cloning the repo and pointing your `PATH` at this\n  `bin/` is the fastest way to get the tool everywhere. Standard probes\n  work through the symlink: `--help`, `--version`, `--about`.\n\n## Supported languages\n\nCurrently:\n\n| Extension | Prompt variant | Focus |\n|-----------|----------------|-------|\n| `.ex`, `.exs` | Elixir / Erlang | BEAM sinks: `binary_to_term`, dynamic dispatch, ETS, NIF FFI, metaprogramming gadgets, etc. |\n| `.zig` | Zig | Memory + error discipline, integer / UB / casting, `@enumFromInt` / `@ptrCast` on untrusted input, FFI boundary, `catch unreachable`, comptime sinks, etc. |\n| `.py` | Python | `pickle` / `yaml.load` / `eval` / `subprocess(shell=True)`, XXE, SSTI, ORM injection, Django/Flask/FastAPI misconfig, `random` for tokens, etc. |\n| `.rs` | Rust | `unsafe` blocks (transmute, raw pointers, `from_raw_parts`), FFI panics, panic-as-DoS via `.unwrap()`/indexing, integer wrap in release, `serde` deserialization without size caps, async cancel safety, `unsafe impl Send/Sync`, etc. |\n| `.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.tsx` | JavaScript / TypeScript | `eval`/`Function`, `child_process.exec`, prototype pollution via deep-merge, `dangerouslySetInnerHTML` / `v-html` / `innerHTML`, JWT `alg: none`, `rejectUnauthorized: false`, ReDoS, CORS misconfig, `Math.random()` for secrets, etc. |\n| `.c`, `.h`, `.cc`, `.cpp`, `.cxx`, `.hpp`, `.hh`, `.hxx` | C / C++ | Unbounded string ops (`strcpy`, `sprintf`, `gets`), format-string injection, integer overflow in size math, `memcpy`/`malloc` with attacker length, TOCTOU, `system`/`popen`, UB (signed overflow, strict aliasing, `reinterpret_cast`), C++ iterator invalidation, `std::regex` ReDoS, throwing across `extern \"C\"`, etc. CWE/CERT-flavored. |\n| anything else | Generic, OWASP-aware | Language-agnostic sinks tagged with OWASP Top 10 categories. Fallback for languages without a dedicated prompt (Go, Ruby, Swift, …). |\n\nEach variant carries its own sink-class inventory and \"always-flag\" list\n(things dangerous enough on sight that no trace/boundary check is needed —\ne.g. `:erlang.binary_to_term/1` without `:safe`, `catch unreachable` on\nattacker-supplied input, `eval`/`exec` of computed strings).\n\n**Adding a new language** is mostly a matter of writing two more heredocs in\n`secreview` (sink classes + always-flag list) and adding one branch to\n`language_for()`. The shared methodology / output sections are reused.\n\n## Quick start\n\n```bash\n# Detect a CLI on PATH (claude \u003e codex \u003e gemini); review every .zig/.ex/.exs\n# file under ./src into SECURITY_FINDINGS.md.\n./secreview ./src\n\n# Preview what would be reviewed (post-filter, one path per line on stdout):\n./secreview --list ./src\n\n# Cap the run; useful for dipping a toe in or budgeting credits:\n./secreview --max-files 5 ./src\n\n# Skip insubstantial files (default: \u003c10 non-blank lines):\n./secreview --min-loc 30 ./src\n\n# Override CLI selection:\nSECREVIEW_LLM_CLI=codex ./secreview ./src\n# or: ./secreview --cli codex ./src\n\n# Strip \"No findings\" / ruled-out-only sections for a clean deliverable:\n./secreview --extract-actionable --actionable-out review.md\n```\n\nRun `./secreview --help` for the full flag list.\n\n## How resume works\n\nEach reviewed file gets a section in the findings doc bounded by:\n\n```html\n\u003c!-- secreview:begin file=\"REL/PATH\" reviewed_at=\"ISO8601\" file_mtime=\"ISO8601\" --\u003e\n## REL/PATH\n\n_Reviewed … · file mtime at review … · CLI claude · style deep_\n\n…findings…\n\n\u003c!-- secreview:end file=\"REL/PATH\" --\u003e\n```\n\nOn rerun:\n\n- File has no entry → review it.\n- Source mtime \u003e recorded → re-review (replace section).\n- Source mtime == recorded → skip (override with `--force`).\n\nLarge trees are resumable: kill the run, restart, and only the unreviewed\nand modified files are re-processed.\n\n## Defaults\n\n| Flag | Default |\n|------|---------|\n| `--out` | `SECURITY_FINDINGS.md` |\n| `--style` | `deep` (the full inventory + per-sink methodology). `--style simple` skims with the sink list in mind. |\n| `--ext` | `zig,ex,exs,py,rs,js,mjs,cjs,jsx,ts,tsx,c,h,cc,cpp,cxx,hpp,hh,hxx` |\n| `--min-loc` | `10` non-blank lines |\n| `--max-files` | `0` (no cap) |\n| Default excluded dirs | `.git`, `.jj`, `.hg`, `.svn`, `.claude`, `.serena`, `.codescan`, `.cursor`, `.idea`, `.vscode`, `.worktrees`, `.zig-cache`, `zig-out`, `_build`, `.elixir_ls`, `.lexical`, `node_modules`, `dist`, `target`, `vendor`, `deps`, `__pycache__`, `.pytest_cache`, `.tox`, `.next`, `.nuxt`, `cover`, `coverage`. Disable with `--no-default-excludes`; add more with `--exclude NAME` (repeatable). |\n\n## CLI invocation details\n\n`secreview` shells out, capturing the LLM's stdout response and splicing it\ninto the findings doc. Per CLI:\n\n- **claude** — `claude -p` reading the prompt from stdin (Claude Code's\n  non-interactive \"print\" mode).\n- **codex** — `codex exec --skip-git-repo-check --ephemeral --color never\n  -o \u003ctmpfile\u003e -` reading the prompt from stdin. `-o` writes only the\n  agent's final message to a tempfile so the captured output isn't polluted\n  by status events.\n- **gemini** — `gemini -p -` (best-guess; verify the exact flags for your\n  install).\n\nThe selected CLI is reported in the startup banner and recorded in each\nsection's header line.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpmarreck%2Fllm_security_review","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpmarreck%2Fllm_security_review","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpmarreck%2Fllm_security_review/lists"}