Skip to main content

PyPI version Python versions Build Status License: MIT

secchecker

Static checks for risky context-to-action flows in AI applications.

Prompts, RAG results, MCP tool output, and model responses often reach a shell, an API call, a SQL query, or agent memory with no validation in between. secchecker finds those transitions.

A pattern reaching a sink is not the same as a safe one. The same function, one line different, is the whole difference between a finding and a clean scan:

# flagged — user input concatenated straight into the system prompt
system_prompt = f"You are a helpful assistant. User query: {user_input}"

# clean — same input, routed through a structured message instead
messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": user_input},
]
$ secchecker vulnerable.py --type llm && secchecker safe.py --type llm
LLM - Prompt Injection via f-string (HIGH): 1 match(es)
  1. `system_prompt user_input`
[+] No findings detected.

Same input variable. Different sink. Different verdict — real output from bench/fixtures/ (see Benchmarks).

Architecture

Prompt / User / RAG / MCP
          |
        Agent
          |
      secchecker
          |
Memory / Tool / Shell / SQL / API

secchecker examines the transitions where untrusted context can influence actions — not a full dataflow analyzer, a static check on the specific lines where that transition happens unchecked.

Quickstart

pip install secchecker
secchecker . --type llm      # scan your project for AI-agent/LLM/MCP risks
cat secchecker_report.md

Requires Python 3.8+, no external dependencies.

What it checks

  • Action boundaries — LLM or tool output passed to eval, exec, shell, or SQL
  • Tool/MCP boundaries — MCP tool results injected into prompts unsanitized, untrusted tool descriptions loaded into prompts
  • Memory boundaries — user input written directly to agent memory
  • Prompt injection — jailbreak/role-override strings, delimiter injection, hardcoded overrides
  • Supporting checks — AI provider credentials, 56 hardcoded secret patterns, Docker/Kubernetes/Terraform misconfigurations, npm/pnpm/Yarn dependency risk

Full rule catalog: docs/RULES.md.

Why a generic scanner isn't enough

Generic SAST (Semgrep, CodeQL):  known-bad code patterns, any language
Secret scanners (Gitleaks):       credential-shaped strings in text
IaC scanners (Checkov):           misconfigured infrastructure resources

secchecker:  where does untrusted AI-application context
             (prompt / RAG / MCP result / model output) reach an action?

secchecker is not trying to replace any of those. It focuses on the boundary that's specific to AI applications — prompts, tool outputs, memory, RAG context, and model responses becoming actions — and bundles secrets/IaC/dependency checks alongside so one pass covers the AI-specific surface, the source code, and the deployment configs around it.

The rule

Every check is one named pattern with a severity and a compliance tag — the same shape whether it's a secret, an LLM-boundary check, or an IaC misconfiguration:

"LLM - Eval of LLM Output": (
    r'(?i)(eval|exec|subprocess\.run|os\.system)\s*\(\s*(llm_?response|completion|response\.text|output\.content)'
)
severity: CRITICAL
owasp:    A03:2021 (Injection)
owasp-llm: LLM05:2025 (Improper Output Handling)
cwe:      CWE-94

Rules are plain regex (compiled once at import) plus an AST walker for Python-specific checks (hardcoded assignments, eval/exec calls, single-hop taint tracking, poisoned tool docstrings). A shared severity map and OWASP/CWE lookup feed every output format. Rule-authoring guide: docs/RULES.md; design: docs/ARCHITECTURE.md.

One scanner, four categories, one interface

secrets      56 credential/connection-string patterns
llm          27 prompt injection / RAG leakage / MCP poisoning / agentic patterns
devsecops    25 Docker / Kubernetes / Terraform / CI misconfigurations
dependency   npm/pnpm/Yarn: obfuscation, install hooks, lockfile drift

All four share one function shape (scan_file(path) -> {rule_name: [matches]}) and feed the same five reporters — secchecker . --type all runs every category in one pass; --type llm runs only the AI-boundary checks.

Output formats

json · md · xml · sarif · html. SARIF carries OWASP Top 10 / OWASP LLM Top 10 tags and CWE IDs on every rule, validated against the official SARIF 2.1.0 JSON Schema (tests/test_sarif_schema.py) — ready for the GitHub Security tab:

secchecker . --type all --format sarif --output secchecker.sarif

Full flags and .secchecker.yml config: docs/CONFIGURATION.md.

CI and pre-commit

- uses: vishnu-77/secchecker@v0.5.0
  with:
    type: all
    format: sarif

SARIF results upload to the GitHub Security tab automatically. Pre-commit hooks and full Action inputs: docs/CI.md.

Benchmarks

Reproducible, offline, no LLM judge — python bench/run.py:

Corpus Result What it measures
Regression (23 vulnerable / 23 safe pairs) 1.00 precision / 1.00 recall Does this release still catch every case it was built to catch?
Adversarial (14 paraphrased/reshaped variants) 3/14 caught (21%) Does it generalize past the exact phrasing it was built to catch?
benign_realistic (4 plausible-FP shapes) 3/4 still flagged Known static-analysis limitation, not a bug

The 1.00/1.00 regression number is not an accuracy claim — full methodology and what would make it one: bench/methodology.md / docs/EVALUATION.md. Scan-throughput benchmark: python bench/perf.py.

Security-sensitive behaviour covered by tests

213 tests, pytest. Not exhaustive — these are the correctness-relevant ones:

✓ eval/exec/subprocess sink detection (raw and decoded/obfuscated input)
✓ single-hop taint tracking (os.environ -> eval)
✓ poisoned MCP tool docstrings/descriptions detected, mapped to LLM01:2025
✓ every shipped pattern (secrets/LLM/devsecops/dependency) has a severity
  and an OWASP/CWE mapping — enforced as a test, not a doc claim
✓ Luhn-validated credit cards, structurally-validated JWTs (placeholder/
  malformed values rejected as false positives)
✓ SARIF output validated against the real SARIF 2.1.0 JSON Schema
✓ lockfile integrity drift detected against git HEAD
✓ known false-positive patterns (placeholder secrets, example.com, localhost)
  correctly not reported

Security model / what secchecker is not

secchecker is not:

  • a dataflow-complete analyzer — it's static regex/AST, single-file, single-hop; expect both false positives and false negatives
  • a replacement for Semgrep, CodeQL, Gitleaks, or Checkov
  • a runtime monitor, WAF, or LLM red-teaming tool
  • a guarantee that a flagged pattern is actually exploited, or that a clean scan means the code is safe
  • an OWASP certification or compliance claim — the tags are guidance

secchecker detects patterns associated with unsafe context-to-action flows in source, before deployment. Runtime-only risks (delegated authority escalation, multi-hop consequence chains, mid-session privilege changes) need runtime governance, not a static scanner — see THREAT_MODEL.md for the full boundary.

Limitations

  • AST-based checks (hardcoded secrets in assignments, eval/exec calls, taint tracking, poisoned tool docstrings/descriptions) run on Python source only.
  • Taint tracking is single-file and single-hop; it does not follow values across module or function boundaries (planned: v0.7.0).
  • Entropy detection is heuristic and opt-in (.secchecker.yml).
  • Dependency scanning is static and offline: no tarball-integrity check against node_modules/ contents, no CVE matching, hook detection only works on already-installed packages.
  • Not a substitute for secret rotation, code review, or a full security audit.

Repository guide

Contributing

git clone https://github.com/vishnu-77/secchecker.git
cd secchecker
pip install -e ".[dev]"
pytest tests/ -v

See CONTRIBUTING.md and the rule-authoring guide in docs/RULES.md.

Responsible use

Intended for auditing repositories you own or have explicit written permission to test. Not a substitute for a full penetration test or security audit.

License

MIT — see LICENSE.

Metadata

Release files for secchecker 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for secchecker 0.5.0
File Size Uploaded
secchecker-0.5.0.tar.gz 68.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for secchecker 0.5.0
File Interpreter ABI Platform
secchecker-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 126.3 kB

Release files / secchecker-0.5.0.tar.gz

Download URL secchecker-0.5.0.tar.gz
Size 68.4 kB
Tags Source
SHA-256 checksum
How to use checksums
7a46d61aeaca13159a36b95b16a46accb7590da5fb18191bfc40ef117ea48d07
BLAKE2b-256 checksum
How to use checksums
fe9f9897fe877278509bfb3a577a458dd93bfcfa5778dce8d9f2ce6f207ac937
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.

Transparency log

Release files / secchecker-0.5.0-py3-none-any.whl

Download URL secchecker-0.5.0-py3-none-any.whl
Size 57.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4153a1865ee34ec01bfcf9871810c42f2d2d73544dbacec0c093afccafc8e71c
BLAKE2b-256 checksum
How to use checksums
70cdb35f7d81f2db8d6cacf99356ae4d1038a02d0d5088f6e395e3eeafbaf605
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.1

2 release files

This release

0.5.0 This release

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page