// SAST · SECRETS · ZERO DEPENDENCIES

Find the security holes in your code — before someone else does.

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.

MIT LICENSE·PYTHON 3.8+·NO PIP INSTALL·RUNS OFFLINE
zsh — loophole scan
➜ ~ python3 loophole.py scan ./api-server Loophole found 55 issue(s): 9 critical, 29 high, 17 medium CRITICAL CMD001 Command injection via child_process (JS/TS) src/run.js:33 › exec(cmd, (err, out) => res.send(out)); taint: req.query.cmd → cmd → exec why: user input reaching a shell lets attackers append commands that run with the app's privileges — full server compromise. fix: use execFile/spawn with an argument array — never build shell strings from input. CRITICAL SEC003 Private key in source code config.py:6 › PRIVATE_KEY = """-----BEGIN RSA PRIVATE KEY----- why: a committed private key is a fully compromised identity — anyone who clones the repo owns it. fix: revoke the keypair, purge it from git history, load keys from a secrets manager. HIGH SQLI002 SQL injection via string formatting (Python) db.py:16 › cur.execute("SELECT * FROM users WHERE id = %s" % uid) fix: parameterized queries — let the driver separate code from data. … 52 more findings ➜ ~
35
security checks
5
languages covered
0
dependencies
1
file — that's the install

DOGFOODED — LOOPHOLE SCANS ITS OWN CODEBASE CLEAN · GITHUB ACTION VERIFIED IN CI · SARIF → GITHUB SECURITY TAB

Fig. 01

Built like a tool developers actually keep

TAINT TRACKING

Data-flow, not grep

Loophole follows user input from source to sink — req.query.cmd → cmd → exec — so findings are real, reachable flows instead of keyword noise.

WHY + FIX

Every finding teaches

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.

ZERO SETUP

No platform. No account.

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.

Fig. 02

The rule catalog

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.

RuleSeverityWhat it catchesLanguage
SEC001CRITICALHardcoded API key / token / secretALL
SEC003CRITICALPrivate key in source codeALL
SEC002HIGHHardcoded passwordALL
SEC004CRITICALHardcoded AWS access key IDALL
CMD001–004CRITICALCommand injection — child_process, os.system, exec.Command, system()JS · PY · GO · PHP
SQLI001–004HIGHSQL injection via string building, formatting and concatenationJS · PY · GO · PHP
EVAL001CRITICALeval() with dynamic inputJS · PY · PHP
XSS001HIGHDynamic HTML via innerHTMLJS/TS
XSS003MEDIUMdangerouslySetInnerHTML usedREACT
XSS004HIGHUnescaped echo of user inputPHP
SSRF001HIGHSSRF: user-influenced URL in outbound requestALL
PATH001HIGHFile access with user-influenced pathALL
TLS001HIGHTLS verification disabledALL
JWT001HIGHJWT decoded without verificationJS/TS
CRY001HIGHMD5 used for password hashingALL

+ CRY002–004 · RAND001–003 · AUTH001 · CORS001 · DBG001 · ERR001 · PATH002 · XSS002 · SEC005 — FULL CATALOG IN THE REPO

Fig. 03

Up and running in one command

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.

  terminal
# 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
  pipeline output
# 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 $?
Fig. 04

First-class in GitHub Actions

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.

  .github/workflows/security.yml
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
InputWhat it does
pathDirectory to scan (default: repo root)
severityMinimum severity to report
upload-sarifPublish results to code scanning
fail-on-findingsFail the workflow on critical/high

PINNED AS @v1 · SELF-TESTED IN CI ON EVERY PUSH

Fig. 05

Open source, built in the open

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.

STEP 1

Pick an issue

Start with a good first issue — three new-rule proposals are already scoped and waiting.

STEP 2

Read the guide

CONTRIBUTING.md documents the rule anatomy, the families, and the fixture workflow.

STEP 3

Ship a rule

Small PR, tests included, self-scan clean. Reviews land the same day — that's a promise kept so far on every PR.