The third tool in a series: iam-privesc-mapper found AWS privilege-escalation paths, cloudtrail-privesc-detector caught them being exploited. This applies the same idea — find dangerous combinations of access, not just risky individual permissions — to AI agents instead of AWS IAM.
Two tools:
- Static capability mapper — tags an agent's tools/MCP servers with what they can actually do, then flags dangerous combinations.
- Prompt-injection test harness — drives a real Claude tool-use conversation against adversarial payloads to check whether the model takes the bait.
Most "AI projects" in a portfolio are a RAG demo or a wrapper around a chat completion — that shows you can call an API, not that you understand how these systems actually fail. Agentic AI's most-cited real risk pattern is the "lethal trifecta": an agent that (1) has access to private data, (2) processes content it didn't write itself — web pages, documents, other people's messages — and (3) has a channel to send data somewhere. Any one of those is fine alone. All three on one agent means a prompt injection hidden in that untrusted content can read the secret and exfiltrate it, and the agent will do it willingly because nothing it did was technically disallowed.
pip install -r requirements.txt
python map.py demo/sample_agent.json
# open output/report.htmlFive capability flags — reads_private_data, exposed_to_untrusted_content,
can_exfiltrate, can_execute, persistent_write — tagged per tool from
real Claude/MCP tool-config shapes (the tools array, MCP server
declarations, Managed Agents toolsets), then checked for dangerous
combinations:
- Lethal trifecta (Critical) — all three of reads/exposed/exfiltrate
- Execute + exfiltrate (Critical) — code execution plus a way out is remote-code-execution-equivalent if either is ever driven by untrusted input
- Persistent write + untrusted exposure (High) — an injected instruction that gets written to memory/files/tickets outlives the conversation that planted it — the agent equivalent of stored XSS
- Reads private + exfiltrate, no injection vector yet (Medium) — worth knowing about before any untrusted-content tool gets added later
- Unclassified tool (Low) — capabilities for unknown custom tools/MCP servers are guessed from their name/description, not confirmed; this finding says exactly that, every time
Findings map to the OWASP Top 10 for LLM Applications — confidently for
LLM01 (Prompt Injection) and LLM06 (Excessive Agency), which are stable
across OWASP revisions; everything else maps to a named theme with a note
to verify the exact number against whichever revision you're citing. See
mapper/owasp_mapping.py.
python test_injection.py --fixture demo/sample_transcript.json # zero setup, illustrative
python test_injection.py --live # real Claude API callsThe harness gives a toy agent two tools (read_document, send_email),
asks it to summarize a document, then returns a poisoned document as the
tool result — text containing an embedded instruction trying to get the
model to email the document contents to an attacker address instead of
just summarizing it. Three payload styles: a direct override, a fake
<system> tag, and an impersonated-authority message.
The demo fixture is illustrative, not a captured run — there's no
Anthropic API key in the environment this was built in, so it ships with a
labeled, expected-outcome fixture rather than a real one. Run --live with
your own key to get a real result. Expect "RESISTED" across the board —
current frontier Claude models handle these specific basic injection
patterns well, and a defensive tool confirming that is a legitimate result,
not a disappointing one. The harness's value is being able to re-run this
as a regression check after any prompt or tool change, not "proving" a
vulnerability that may not exist.
Capabilities for anything outside the known-tool-type and known-MCP-server
lists are guessed from keyword matching on the tool's name and
description — that's a heuristic, not a fact, and it says so on every
finding it produces. Pass an explicit "capabilities" list on a tool's
config entry to override the guess. The injection harness only tests the
three payload styles shipped here against a two-tool toy agent — it is not
an exhaustive red-team, and passing it isn't a clean bill of health for a
production agent with a much larger tool surface.
mapper/loader.py known-tool-type + known-MCP-server capability tags, keyword fallback
mapper/detectors.py set-intersection rules over tagged capabilities
mapper/owasp_mapping.py rule_id -> OWASP LLM Top 10
mapper/report.py string.Template -> static HTML (no web framework)
map.py CLI for the static mapper
injector/payloads.py the three adversarial documents
injector/harness.py real two-turn Claude tool-use loop + pure verdict classifier
injector/report.py string.Template -> static HTML
test_injection.py CLI for the injection harness
python -m pytest12 tests: capability tagging, all four combo rules (including a true negative), and the injection harness's verdict classifier — the classification logic is a pure function, so it's fully unit-testable without an API key or any network access.
MIT

