agentsec · Tools · resultguard

Offline · stdlib-only · MIT

resultguard: detect indirect prompt injection in tool results in AI agents


Offline scanner for indirect prompt injection in AI agent tool results.

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

RuleSeverityWhat it flags
TR01highAI-directed override / jailbreak phrasing (ignore previous instructions, you are now in DAN mode, …)
TR02highFake role delimiters / system tokens (`<\
TR03criticalHidden Unicode smuggling (zero-width, bidi, Unicode TAG block)
TR04highTool-chaining / action bait (call the send_email tool, run bash, exfiltrate, …)
TR05highExfil / callback URL bait (webhook.site, requestbin, interact.sh, evil-callback.*, “send secrets to https://…”)
TR06mediumBase64/hex blob that decodes to instruction-like text
TR07highCredential harvest (paste your API key, cat ~/.ssh/…, dump .env)
TR08mediumConceal-from-user phrasing (do not tell the user, silently perform)
TR09mediumMarkdown/HTML auto-loading image or resource URL in a result
TR10highStructural 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-rules

After 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.

Known limits

can match (especially TR09). Use --disable / --tools / --fail-on.

ignored by design.

binary blobs are skipped.

domains need TR05's phrasing arm or a custom allow/deny later.

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.