What it detects
Offline scanner for indirect prompt injection in AI agent tool results.
When an agent reads a page, file, ticket or API response, that content is fed back to the model as a tool result. Attackers plant instructions there ("ignore prior rules", "call send_email", "quietly hit this webhook"). resultguard extracts those results from saved transcripts and flags hijack / exfil bait patterns with tool and turn attribution.
Standard library only. It never runs an agent or contacts a model.
Rules
| Rule | Severity | What it flags |
|---|---|---|
| TR01 | high | AI-directed override / jailbreak phrasing (ignore previous instructions, you are now in DAN mode, …) |
| TR02 | high | Fake role delimiters / system tokens (`<\ |
| TR03 | critical | Hidden Unicode smuggling (zero-width, bidi, Unicode TAG block) |
| TR04 | high | Tool-chaining / action bait (call the send_email tool, run bash, exfiltrate, …) |
| TR05 | high | Exfil / callback URL bait (webhook.site, requestbin, interact.sh, evil-callback.*, “send secrets to https://…”) |
| TR06 | medium | Base64/hex blob that decodes to instruction-like text |
| TR07 | high | Credential harvest (paste your API key, cat ~/.ssh/…, dump .env) |
| TR08 | medium | Conceal-from-user phrasing (do not tell the user, silently perform) |
| TR09 | medium | Markdown/HTML auto-loading image or resource URL in a result |
| TR10 | high | Structural injection: instruction-to-agent cues combined with authority/override framing, a sensitive object, and an exfil sink (URL, email, tool call, markdown image). Decodes Unicode, HTML, URL, base64, and similar layers first. |
Usage
python3 resultguard.py transcript.json [more.jsonl dir/ -]
--as-result treat each file body as one tool result (skip transcript parse)
--tool-name NAME name used with --as-result / plain files (default: file)
--tools NAME ... only scan results from these tools
--disable RULE ... skip rule ids (e.g. TR09)
--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 resultguard …. Every tool also accepts --help and almost every tool accepts --json.
Example output
Flags TR01/TR04/TR05/TR07/TR08/TR09 on fetch_ticket and TR01/TR02/TR06/TR09 on browse_page (exit 1). examples/clean_openai.json is clean (exit 0). examples/poisoned_anthropic.json shows hidden Unicode (TR03). examples/generic_results.jsonl and examples/standalone_result.txt cover generic and --as-result paths. All secrets and callback IDs in examples are FAKE-EXAMPLE-*.
python3 resultguard.py examples/poisoned_openai.json
SARIF and CI
agentsec resultguard path/to/input --json > resultguard.json
# resultguard does not yet emit SARIF; use --json and keep --fail-on for CI.
# GitHub Actions (composite action ships with the repo)
- uses: dunkleschitz/agentsec@v0
with:
tools: resultguard
paths: path/to/input
fail-on: high
--sarif is not available on this tool yet (resultguard and toolpoison are reserved as good first issues). Use --json and a --fail-on exit gate instead.
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.
- LLM01 Prompt Injection — OWASP LLM Top 10 (2025)
- ASI01 Agent Goal Hijack — OWASP Agentic Top 10 (2026)
- ASI06 Memory and Context Poisoning — OWASP Agentic Top 10 (2026)
Known limits
- Heuristic. Benign docs that discuss jailbreaks, or HTML with ordinary
<img src=https://…>,
can match (especially TR09). Use --disable / --tools / --fail-on.
- Only *tool results* are scanned. User messages, assistant prose and tool *arguments* are
ignored by design.
- Encoded-blob detection (TR06) only flags UTF-8 payloads that look instruction-like; short or
binary blobs are skipped.
- Callback-host matching is a fixed list plus a few
evil-*/exfil*patterns — novel
domains need TR05's phrasing arm or a custom allow/deny later.
- It analyzes what was saved. It cannot block a live tool result; pair it with a runtime
filter in front of the model context.
Full source, tests, and fixtures: tools/resultguard/ in the repository. Install the kit with pip install git+https://github.com/dunkleschitz/agentsec.git.