Skip to main content

LLMSafe

CI Code scanning PyPI License: MIT Python 3.9+

LLMSafe is an open-source static security scanner for AI-powered and agentic Python applications. It traces user input and model-controlled data into dangerous capabilities such as code execution, shells, SQL, outbound requests, and dynamic tool dispatch.

It runs locally. Source code is not uploaded to a model or external analysis service.

Status: v0.2.1 is an early release. LLMSafe provides reviewable security signals, not a guarantee that an AI system is secure.

Why another security scanner?

Traditional Python scanners are good at finding dangerous APIs. Agentic applications add a different question: can untrusted user or model output reach that capability?

flowchart LR
    A["User input"] --> C["Assignments and transforms"]
    B["Model output"] --> C
    C --> D["Shell / eval / SQL / HTTP / tool dispatch"]
    D --> E["Finding with source-to-sink evidence"]

LLMSafe combines focused API checks with AST-based dataflow and agent-framework rules:

def run_agent(client, user_input):
    response = client.responses.create(input=user_input)
    generated_code = response.output_text
    return eval(generated_code)

The scanner reports both the dangerous eval() and the path from the model response to that sink:

agent.py:4:12: CRITICAL FLOW001 Untrusted data reaches code execution
  Untrusted or model-controlled data flows into eval(). Source: model, user.
  Trace 2:16: model source: client.responses.create
  Trace 1:23: user source: user_input
  Trace 4:12: reaches eval
  Fix: Replace dynamic execution with a typed parser and an allow-listed operation.

Detection coverage

Family Rule IDs Examples
Dataflow FLOW001FLOW005 Model/user data reaching code, shell, SQL, URL, or tool dispatch
Agent tools AGENT001AGENT003 Python/shell tools, dangerous capability flags, disabled approval
Secrets SECRET001SECRET005 Provider keys, tokens, private keys, hard-coded credentials
Python PY001PY004 eval, exec, unsafe pickle and YAML deserialization
Shell SHELL001SHELL002 os.system and subprocess(..., shell=True)
Prompt trust LLM001 Dynamic data interpolated into system/developer instructions
MCP MCP001MCP003 Shell launch, remote HTTP, wildcard tool permissions

See the complete rule catalog and threat model.

Integrations can query the same catalog without parsing documentation:

llmsafe --list-rules
llmsafe --list-rules --format json

The versioned JSON output includes every stable ID, severity, family, description, and remediation.

Install

LLMSafe supports Python 3.9 and newer.

python3 -m venv .venv
source .venv/bin/activate
python -m pip install llmsafe

For development:

git clone https://github.com/rezerpaul-crypto/llmsafe.git
cd llmsafe
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"

Use the CLI

Scan the current repository:

llmsafe .

Scan selected paths and fail on medium-or-higher findings:

llmsafe src agent.py --fail-on medium --exclude "generated/**"

Generate machine-readable reports:

llmsafe . --format json --output reports/llmsafe.json
llmsafe . --format sarif --output reports/llmsafe.sarif

Exit codes are stable for automation:

Code Meaning
0 No finding at or above the selected threshold
1 At least one finding reached the selected threshold
2 Invalid configuration, missing target, or scan error

Repository policy

Commit a .llmsafe.toml file:

[llmsafe]
exclude = ["generated/**", "vendor/**"]
fail_on = "high"
max_file_size = 1000000
disabled_rules = ["PY004"]

CLI options override or extend repository policy. Policy can also live under [tool.llmsafe] in pyproject.toml. See configuration.

Adopt LLMSafe without ignoring new risk

Existing repositories can review and commit a baseline of current findings:

llmsafe . --write-baseline .llmsafe-baseline.json
llmsafe . --baseline .llmsafe-baseline.json

The second command reports and fails only on findings not represented in the baseline. Matching is line-independent, duplicate-aware, and deterministic so ordinary code movement does not create noise while an additional dangerous operation is still reported. Baselines are review artifacts, not permanent suppressions; see incremental adoption.

Suppress one reviewed finding

Place a narrow suppression on the finding line or immediately above it:

# llmsafe: ignore[PY001] -- expression is generated from a fixed internal grammar
result = eval(TRUSTED_EXPRESSION)

Prefer a rule-specific suppression over a bare llmsafe: ignore.

GitHub Code Scanning

The repository includes a reusable composite action. A consumer workflow can scan, upload SARIF, then enforce the configured threshold:

permissions:
  contents: read
  security-events: write

steps:
  - uses: actions/checkout@v7
  - uses: actions/setup-python@v7
    with:
      python-version: "3.12"
  - id: llmsafe
    continue-on-error: true
    uses: rezerpaul-crypto/llmsafe@v0.2.1
    with:
      path: .
      fail-on: high
  - if: always()
    uses: github/codeql-action/upload-sarif@v4
    with:
      sarif_file: ${{ steps.llmsafe.outputs.sarif-file }}
  - if: steps.llmsafe.outcome == 'failure'
    run: exit 1

The workflow uses only contents: read and security-events: write.

Pre-commit

repos:
  - repo: https://github.com/rezerpaul-crypto/llmsafe
    rev: v0.2.1
    hooks:
      - id: llmsafe

Benchmark

The checked-in benchmark exercises vulnerable and safe agent boundaries:

python -m benchmarks.run

Current expectations cover 18 rule-level signals across direct and local-helper code execution, shell execution, SQL, SSRF, tool dispatch, prompt boundaries, high-impact tools, approval bypasses, and MCP. This is a regression corpus—not an industry benchmark or a claim of real-world detection rate. See the benchmark methodology.

How LLMSafe fits

Tool category Primary strength LLMSafe relationship
General Python SAST Broad language and API security checks Complementary; LLMSafe focuses on AI/agent trust boundaries
Pattern-rule engines Highly customizable organizational rules LLMSafe supplies opinionated agent rules without rule authoring
Dependency scanners Known vulnerable packages and supply chain Out of scope; run alongside LLMSafe
Runtime guardrails Enforce live policy and monitor model/tool calls Out of scope; LLMSafe reviews source and configuration before runtime

Read the architecture for implementation boundaries and tradeoffs.

Contributing and security

Contributions are welcome. Start with CONTRIBUTING.md and the public roadmap. Report vulnerabilities privately according to SECURITY.md.

LLMSafe is released under the MIT License.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

llmsafe-0.2.1.tar.gz (39.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

llmsafe-0.2.1-py3-none-any.whl (38.1 kB view details)

Uploaded Python 3

File details

Details for the file llmsafe-0.2.1.tar.gz.

File metadata

  • Download URL: llmsafe-0.2.1.tar.gz
  • Upload date:
  • Size: 39.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for llmsafe-0.2.1.tar.gz
Algorithm Hash digest
SHA256 60d616242cedb4af3c78f3067a33a06a72041d0c8bfe38c0cbe7dc27f21f66e2
MD5 bd876317d096b651774fccdb41bac090
BLAKE2b-256 c0422a2815369ecd57ce393a3e69761df6bd6eb41556ac75a48ea1859aece476

See more details on using hashes here.

Provenance

The following attestation bundles were made for llmsafe-0.2.1.tar.gz:

Publisher: release.yml on rezerpaul-crypto/llmsafe

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file llmsafe-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: llmsafe-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 38.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for llmsafe-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 62909c7d8babc7eaa0c247f705f8bcf03d069d66acce9a023e1fc328a32878f6
MD5 a8eb8bc5921e497c9f617c129210e320
BLAKE2b-256 ae0676f83954fdc74fb0ce335e483ae8633d3b18a723015bb97df73fbd179d25

See more details on using hashes here.

Provenance

The following attestation bundles were made for llmsafe-0.2.1-py3-none-any.whl:

Publisher: release.yml on rezerpaul-crypto/llmsafe

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page