What it detects
Offline data-flow secret-propagation detector for AI agent transcripts.
tracesweep asks whether a secret *appeared* in a run. secretflow asks the next question: once a secret showed up in a tool result (or earlier message), was that *same value* later passed into another tool's arguments — especially an outbound HTTP/webhook/email tool or a shell? That reuse pattern is the classic agent exfiltration hop (read .env → http_post webhook).
Standard library only. It never connects to a network.
Rules
| Rule | Severity | What it flags |
|---|---|---|
| FL01 | critical | Secret from a tool result propagated into an outbound/exfil tool's arguments |
| FL02 | critical | Secret from a tool result propagated into a shell/command tool's arguments |
| FL03 | high | Secret from a tool result reused in a later tool call's arguments |
| FL04 | critical | Auth/session token (Bearer, JWT, Cookie, Authorization) reused in later tool args |
| FL05 | high | Secret echoed by the assistant, then passed into a subsequent tool call |
| FL06 | high | Multi-hop: same secret value appears in arguments of two or more distinct tools |
| FL07 | high | Labeled secret value (api_key= / password= / token= / env *_KEY=) reused later |
| FL08 | medium | User-supplied secret forwarded into an outbound/exfil tool |
| FL09 | medium | Secret from a tool result written to a file/log/memory sink tool |
| FL10 | info | Inventory of tainted secret sources and observed sinks |
Usage
python3 secretflow.py transcript.json [more.jsonl dir/ -]
--disable RULE ... skip rule ids (e.g. FL10)
--json machine-readable output
--min-severity S hide findings below S (default info)
--fail-on S exit 1 if any finding >= S (default high; any, none)
--list-rulesAfter pip install of the kit, the same options work as agentsec secretflow …. Every tool also accepts --help and almost every tool accepts --json.
Example output
Flags the staging API_KEY flowing into http_post (FL01), the session token into bash (FL02/FL04), assistant echo then tool use (FL05), labeled env reuse (FL07), stripe key into write_file (FL09), and multi-tool hops (FL06). Exit 1.
examples/clean_openai.json is clean under --fail-on high (exit 0).
python3 secretflow.py examples/risky_openai.json --disable FL10
SARIF and CI
agentsec secretflow path/to/input --sarif > secretflow.sarif
# GitHub Actions (composite action ships with the repo)
- uses: dunkleschitz/agentsec@v0
with:
tools: secretflow
paths: path/to/input
fail-on: high
SARIF 2.1.0 can be uploaded to GitHub code scanning. The composite action writes per-tool reports under agentsec-sarif/ by default.
OWASP mapping
Heuristic mapping of what this tool helps a reviewer look for. Not an official OWASP endorsement, and not complete coverage of any item. Sources: OWASP Top 10 for LLM Applications 2025 and OWASP Top 10 for Agentic Applications 2026.
- LLM02 Sensitive Information Disclosure — OWASP LLM Top 10 (2025)
- ASI02 Tool Misuse and Exploitation — OWASP Agentic Top 10 (2026)
Known limits
- Value-equality taint only (exact substring). Transformed secrets (base64 of a
key, truncated, hashed, or concatenated differently) are invisible.
- Secret shapes are heuristic (FAKE-EXAMPLE-*, labeled assignments, JWT, Bearer,
common provider prefixes, *_KEY= env lines). Novel formats are missed; long benign tokens can false-positive — review masked snippets.
- Only sees what was logged. A clean secretflow result does not mean no secrets
were present — run tracesweep for presence, and treat this as a propagation / exfil-hop review aid, not a security boundary.
- Outbound / shell / write-sink classification is by tool-name tokens; renamed
wrappers may be under-counted (they still hit FL03 on any later reuse).
Full source, tests, and fixtures: tools/secretflow/ in the repository. Install the kit with pip install git+https://github.com/dunkleschitz/agentsec.git.