Loophole is a static security scanner that ships as one Python file with zero dependencies. Point it at a codebase and it finds hardcoded secrets, injection flaws, XSS and more — then tells you why each one matters and how to fix it.
DOGFOODED — LOOPHOLE SCANS ITS OWN CODEBASE CLEAN · GITHUB ACTION VERIFIED IN CI · SARIF → GITHUB SECURITY TAB
Loophole follows user input from source to sink — req.query.cmd → cmd → exec — so findings are real, reachable flows instead of keyword noise.
Each result explains the risk in plain English and ships the concrete fix. No cryptic rule codes that send you to a wiki — the answer is in the output.
No SaaS onboarding, no config files, no telemetry, no API keys. If Python 3 runs — laptop, CI runner, air-gapped box — Loophole runs. Offline, in seconds.
Thirty-five checks across the vulnerability classes that actually ship to production. A sample of the catalog — severities and titles below are verbatim from real scans.
| Rule | Severity | What it catches | Language |
|---|---|---|---|
| SEC001 | CRITICAL | Hardcoded API key / token / secret | ALL |
| SEC003 | CRITICAL | Private key in source code | ALL |
| SEC002 | HIGH | Hardcoded password | ALL |
| SEC004 | CRITICAL | Hardcoded AWS access key ID | ALL |
| CMD001–004 | CRITICAL | Command injection — child_process, os.system, exec.Command, system() | JS · PY · GO · PHP |
| SQLI001–004 | HIGH | SQL injection via string building, formatting and concatenation | JS · PY · GO · PHP |
| EVAL001 | CRITICAL | eval() with dynamic input | JS · PY · PHP |
| XSS001 | HIGH | Dynamic HTML via innerHTML | JS/TS |
| XSS003 | MEDIUM | dangerouslySetInnerHTML used | REACT |
| XSS004 | HIGH | Unescaped echo of user input | PHP |
| SSRF001 | HIGH | SSRF: user-influenced URL in outbound request | ALL |
| PATH001 | HIGH | File access with user-influenced path | ALL |
| TLS001 | HIGH | TLS verification disabled | ALL |
| JWT001 | HIGH | JWT decoded without verification | JS/TS |
| CRY001 | HIGH | MD5 used for password hashing | ALL |
+ CRY002–004 · RAND001–003 · AUTH001 · CORS001 · DBG001 · ERR001 · PATH002 · XSS002 · SEC005 — FULL CATALOG IN THE REPO
Clone it, run it. Machine-readable output for pipelines, human output for people, and --fix-dry prints mechanical fix suggestions as diffs — it never touches your files uninvited.
# clone — that's the entire install git clone https://github.com/rootsiemen/loophole cd loophole # scan a project python3 loophole.py scan ./your-project # only criticals and highs, specific folder python3 loophole.py scan ./src \ --severity critical,high # preview fixes as diffs (dry run) python3 loophole.py scan . --fix-dry
# JSON for your own tooling python3 loophole.py scan . --json # SARIF 2.1.0 for code scanning UIs python3 loophole.py scan . --sarif # exit code 1 on critical/high findings, # so CI fails the build exactly when it should python3 loophole.py scan . ; echo $?
The official Action runs Loophole on every push and pull request and uploads SARIF results to your repository's Security tab — findings show up where your team already reviews code.
name: Security scan on: [push, pull_request] permissions: security-events: write jobs: loophole: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: rootsiemen/loophole@v1
| Input | What it does |
|---|---|
| path | Directory to scan (default: repo root) |
| severity | Minimum severity to report |
| upload-sarif | Publish results to code scanning |
| fail-on-findings | Fail the workflow on critical/high |
PINNED AS @v1 · SELF-TESTED IN CI ON EVERY PUSH
Loophole is MIT-licensed and maintained in public. A new rule is one focused function plus fixtures — the codebase is a single readable file, so your first contribution is an afternoon, not a week.
Start with a good first issue — three new-rule proposals are already scoped and waiting.
CONTRIBUTING.md documents the rule anatomy, the families, and the fixture workflow.
Small PR, tests included, self-scan clean. Reviews land the same day — that's a promise kept so far on every PR.