Static analyzer for prompt injection and confused-deputy risks in LLM agent code.
Project description
agentic-guard
Static analyzer for prompt-injection and confused-deputy risks in LLM agent code. The missing
bandit/semgrepfor AI agents.
agentic-guard reads your agent code (LangGraph, OpenAI Agents SDK, plus Jupyter notebooks)
and flags dangerous architectural patterns before you ship — without running the
agent, without sending data anywhere, without LLM calls.
pip install agentic-guard
agentic-guard scan ./my-agent-project
Why this exists
The most common real-world AI security failure is the confused deputy: an agent has a tool that reads untrusted text (an email, a web page, a PDF, a ticket) AND a tool that takes a privileged action (sending email, transferring money, executing shell commands), with the LLM acting as the unwitting middleman that follows attacker instructions embedded in the untrusted text.
This pattern has shipped, in production, at major companies — Bing Chat, Slack AI, Microsoft 365 Copilot, ChatGPT plugins have all had variants disclosed publicly. Existing AI-security tools work at runtime — they inspect prompts as they happen and try to block injection attempts. They can't tell you whether your agent's architecture is unsafe.
agentic-guard catches the architectural mistakes at build time, when they're cheap
to fix.
What it catches
| ID | Name | OWASP LLM Top 10 |
|---|---|---|
IG001 |
Confused-deputy: untrusted source flows to a privileged sink without a human-approval gate | LLM01 + LLM06 |
IG002 |
System prompt built from runtime input (f-string / .format() / concat) |
LLM01 |
Severity is scored on the sink's privilege × reversibility × source trust. The
classification of which tools are sources vs sinks lives in
src/agentic-guard/taxonomy.yaml and is community-extensible.
Quick start
pip install agentic-guard
# Scan a directory or a single file
agentic-guard scan ./my-agent-project
# Different output formats
agentic-guard scan ./agent --format pretty # default — human-readable terminal output
agentic-guard scan ./agent --format sarif # GitHub code scanning / IDE integration
agentic-guard scan ./agent --format json # machine-readable
# Useful flags
agentic-guard scan ./agent --fail-on high # exit non-zero on HIGH+ findings (CI gate)
agentic-guard scan ./agent --include-tests # also scan test files (skipped by default)
agentic-guard scan ./agent --output report.sarif
GitHub Action
Add to .github/workflows/ci.yml:
- uses: sanjaybk7/agentic-guard@v0.1.0
with:
path: .
fail-on: high
Findings appear in your repo's Security → Code scanning tab via SARIF upload.
VS Code extension
Inline diagnostics on save (red squigglies in the editor, hover tooltips with rule ID + OWASP mapping + fix hint). See vscode-extension/README.md for build/install instructions.
Supported frameworks
| Framework | Status | Recognized patterns |
|---|---|---|
| LangGraph | ✅ supported | @tool decorators, create_react_agent(...) and similar factories, interrupt_before=[...] gates |
| OpenAI Agents SDK | ✅ supported | @function_tool decorators, Agent(...) constructor, tool_use_behavior="stop_on_first_tool" and StopAtTools(...) gates |
| Jupyter notebooks (.ipynb) | ✅ supported | Code cells extracted and parsed; magics/shell escapes sanitized; findings report cell[N] line M |
| Microsoft Agent Framework | ⏳ planned | — |
| MCP servers | ⏳ planned | — |
| AutoGen, CrewAI, Swarm | ⏳ unsupported | Open an issue if you'd use this |
How it works
- Discovery. Walks your project, picks up
.pyand.ipynbfiles. Skipstests/,venv/,__pycache__/, etc. by default. - Parse. For each file, builds a Python AST. For notebooks, extracts code cells into virtual source first.
- Per-framework recognition. A parser fires only when the file imports its
framework (so a generic
class Agent:won't false-positive). Each parser produces a framework-agnostic intermediate representation:ToolandAgentobjects with classifications, privilege levels, and gating info. - Taint-aware rule evaluation. Detection rules operate on the IR, not on framework-specific syntax. Adding a new framework means writing a new parser only — the rules stay the same.
- Output. Pretty terminal panels, SARIF v2.1.0 (with
security-severityfor GitHub Security tab badges), or JSON.
No code is executed. No data leaves your machine. No LLM calls.
A longer technical writeup, including the taint-analysis adaptation and
honest limitations, is in docs/HOW_IT_WORKS.md.
What InjectGuard is not
Being honest about scope matters more than overselling. This tool:
- Is not a runtime defense. It doesn't intercept prompts in production. Use Lakera, Prompt Armor, or NeMo Guardrails for that.
- Is not a deep code analyzer. It analyzes tool names and agent architecture,
not what's inside tool function bodies. A function named
process()whose body callssmtplib.send()is currently invisible to the tool — names matter, just as they do forbandit, ESLint, and Semgrep. (See roadmap for IG003.) - Is not a cross-module analyzer. It resolves intra-module string constants
(so
instructions=PROMPTwherePROMPT = "..."lives in the same file is treated as static), but doesn't follow imports across files. Constants imported from other modules will currently flag IG002 as a likely false positive. - Does not support TypeScript-based agent frameworks at v0. Python-only.
- Does not execute, evaluate, or send your code anywhere. All analysis is local and deterministic.
Real-world validation
Scanned 9 popular open-source agent codebases (LangChain, LangGraph, OpenAI Agents
SDK, OpenAI Cookbook, GenAI_Agents, etc.) covering ~3,000 Python files and notebook
cells. Surfaced 22 prompt-injection patterns, all in examples/ and tutorial/
code that developers actively copy from. Findings were not publicly disclosed against
specific repos; this is intended to be reported responsibly to maintainers as we
go.
Roadmap
Driven by community feedback after v0 launch.
- IG003 — library-call rule. Walk inside tool function bodies for known-dangerous
calls (
smtplib.send_message,subprocess.run,requests.post,boto3.client('ses'), etc.) so tools with neutral names but dangerous bodies get caught. - Cross-module import resolution for constants used as prompts.
- Microsoft Agent Framework parser (Python).
- MCP server parser.
agentic-guard init— interactive command to add project-local taxonomy entries for unfamiliar tool names.
Contributing
Contributions very welcome — especially:
- New taxonomy entries. Edit
src/agentic-guard/taxonomy.yamlto add tool-name patterns we don't recognize yet. - New rules. Subclass
Ruleinsrc/agentic-guard/rules/. - New parsers. Add a
FrameworkParserfor a framework we don't support.
See CONTRIBUTING.md.
Security disclosure
If you find a vulnerability in agentic-guard itself (rather than using
agentic-guard to find vulnerabilities), please email the maintainer rather than
opening a public issue.
If you find a vulnerability in a third-party project using agentic-guard, please
disclose it responsibly to that project's maintainers — give them at least 30
days to fix before public discussion.
License
Apache-2.0. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agentic_guard-0.1.0.tar.gz.
File metadata
- Download URL: agentic_guard-0.1.0.tar.gz
- Upload date:
- Size: 47.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
73848765418d23f3b3ad302c0f9e0d369fc8c0724679c8d99b3851b7c00e3045
|
|
| MD5 |
a12991def747ffc859b905ea1f1b97d6
|
|
| BLAKE2b-256 |
0b648d5ea6fb7fbf5c72bffe92bcba4ce24d45dd67ab8cd38fcdc49d26e81acc
|
File details
Details for the file agentic_guard-0.1.0-py3-none-any.whl.
File metadata
- Download URL: agentic_guard-0.1.0-py3-none-any.whl
- Upload date:
- Size: 35.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a82e925265095bd1ba4b9c5cb4582a148055f583153275ada124bde9719ee8c4
|
|
| MD5 |
25cd3d0aee9caa53d805cb806071e930
|
|
| BLAKE2b-256 |
a614d38a2b4e4f55e2dc55aff714d348362263bafbf1704cc584f3d1bc03ecc2
|