Observed since 20 Oct, 21:58 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
CVE-style advisory database and static scanner for AI agent security risks
Static security scanner for AI agent codebases. Analyzes repositories and MCP config files against a CVE-style advisory database — no live agent interaction required.
eval(), exec(), shell=True, hardcoded API keysclaude_desktop_config.json, .mcp.json) for shell execution tools, overly broad filesystem access, and unverified npx/uvx packages# From repo root (inside a virtualenv)
pip install agentfort
# Or dev install from repo root
pip install -e .
# Scan a repo
agentfort scan --repo /path/to/your/agent-project
# Scan just an MCP config file
agentfort scan --mcp-config ~/.config/claude/claude_desktop_config.json
# JSON output (clean stdout, progress on stderr)
agentfort scan --repo . --format json
# Markdown report to file
agentfort scan --repo . --format md --output report.md
# Only show high and above
agentfort scan --repo . --min-severity high
# Disable CI exit code
agentfort scan --repo . --no-fail-on-critical
# Skip OSV live lookup (air-gapped / CI without outbound)
agentfort scan --repo . --offline
# Browse advisories
agentfort advisories list
agentfort advisories list --severity critical
agentfort advisories show AGSA-001
Post findings to Slack or email when a scan completes:
# Slack alert on critical findings
agentfort scan --repo . --notify-slack https://hooks.slack.com/services/...
# Email alert (requires SMTP env vars)
export AGENTFORT_SMTP_HOST=smtp.example.com
export AGENTFORT_SMTP_USER=alerts@example.com
export AGENTFORT_SMTP_PASS=secret
export AGENTFORT_SMTP_FROM=alerts@example.com
agentfort scan --repo . --notify-email team@example.com
# Env var shorthand (useful in CI secrets)
export AGENTFORT_SLACK_WEBHOOK=https://hooks.slack.com/services/...
agentfort scan --repo .
Send a digest of new advisories on a schedule:
# Show all advisories
agentfort digest
# Show only advisories added in the last 7 days
agentfort digest --since 7
# Post to Slack
agentfort digest --since 7 --slack $SLACK_WEBHOOK
# Email the digest
agentfort digest --since 7 --email team@example.com
Run the digest weekly via GitHub Actions scheduled workflow:
on:
schedule:
- cron: '0 9 * * 1' # every Monday at 9am UTC
jobs:
digest:
runs-on: ubuntu-latest
steps:
- run: pip install agentfort
- run: agentfort digest --since 7 --slack ${{ secrets.SLACK_WEBHOOK }}
- name: AgentFort Security Scan
uses: ./.github/actions/agentfort
with:
repo-path: '.'
fail-on-critical: 'true'
offline: 'true'
slack-webhook: ${{ secrets.SLACK_WEBHOOK }} # optional
notify-email: 'team@example.com' # optional
Add AgentFort to any CI pipeline with one step. The action installs agentfort from PyPI and runs a full scan — failing the build on critical findings by default.
- name: AgentFort Security Scan
uses: NeuronKnight/agentfort-action@v1
with:
repo-path: '.' # directory to scan (default: .)
min-severity: 'low' # critical | high | medium | low (default: low)
fail-on-critical: 'true' # fail build on critical findings (default: true)
offline: 'false' # skip OSV.dev live CVE lookup (default: false)
Full workflow example:
name: Security Scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: NeuronKnight/agentfort-action@v1
with:
min-severity: high
fail-on-critical: 'true'
Note:
NeuronKnight/agentfort-actionis the planned standalone Action repo. Until it's published, use the local action from this repo:uses: ./.github/actions/agentfort.
Every scan queries OSV.dev in parallel for known CVEs against every package detected in the repo. No database to update — findings reflect OSV's current state on each run.
database_specific.severity) for accurate critical/high/medium/low mapping--offline to skip the lookup entirely# Scan with live CVEs (default)
agentfort scan --repo .
# Air-gapped / no outbound network
agentfort scan --repo . --offline
Create .agentfortignore in your repo root to exclude directories or files from scanning. Uses gitignore-style glob patterns:
# .agentfortignore
# Ignore generated code
generated/
# Ignore vendor directory
vendor/
# Ignore specific file pattern
*.pb.py
The scanner skips any file whose path matches a pattern. Useful for:
14 static advisories covering structural/behavioral risks from the OWASP Agentic Top 10. Package CVEs are handled live by OSV.dev (see above).
| ID | Severity | Risk |
|---|---|---|
| AGSA-001 | Critical | LangChain ShellTool unrestricted shell execution |
| AGSA-002 | Critical | MCP server exposes shell execution tool |
| AGSA-003 | Critical | eval()/exec() in agent tool handler |
| AGSA-005 | Critical | AutoGen/CrewAI code execution without confirmation |
| AGSA-004 | High | Hardcoded API key or secret in MCP config |
| AGSA-006 | High | MCP filesystem server with overly broad path (/, ~) |
| AGSA-007 | High | subprocess with shell=True or os.system() |
| AGSA-008 | High | Agent tool writes to arbitrary file paths |
| AGSA-010 | High | Prompt injection via unvalidated tool output |
| AGSA-013 | High | OpenAI Assistants file_search/code_interpreter without scope restriction |
| AGSA-009 | Medium | MCP server loaded via unverified npx/uvx package |
| AGSA-012 | Medium | Secrets exposed via os.environ in tool scope |
| AGSA-014 | Medium | Non-PyPI/non-npm dependency as framework component |
| AGSA-015 | Medium | System prompt in user-accessible config location |
0–100. Each finding adds: critical=40, high=15, medium=5, low=1. Capped at 100.
Terminal (default) — Rich panels with color-coded severity table and detail panels for critical/high findings.
JSON — Machine-readable. Progress messages go to stderr so stdout is clean for piping:
agentfort scan --repo . --format json 2>/dev/null | jq '.findings[] | select(.severity=="critical")'
Markdown — Full report with summary table and per-finding sections, suitable for GitHub issues or PR comments.
agentfort/ # project root
├── agentfort/ # Python package
│ ├── cli.py # Click CLI entry point
│ ├── models.py # Finding, ScanResult dataclasses
│ ├── db/
│ │ ├── advisory.py # Advisory loader and index
│ │ └── data/ # AGSA-001.yaml … AGSA-015.yaml
│ ├── scanner/
│ │ ├── frameworks.py # requirements.txt / pyproject.toml / package.json
│ │ ├── mcp.py # MCP config file scanner
│ │ ├── osv.py # Live CVE lookup via OSV.dev API
│ │ ├── patterns.py # Python source pattern scanner
│ │ └── secrets.py # Hardcoded credential scanner
│ └── report/
│ └── formatter.py # Terminal, Markdown, JSON renderers
└── pyproject.toml
pypistats · 47 observations shown. Missing days are unknown. Source category: overall: without mirrors.
| Date / source period | Value | Observed at |
|---|---|---|
| 2026-10-19 – 2026-10-19 | 2 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-18 – 2026-10-18 | 4 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-17 – 2026-10-17 | 11 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-16 – 2026-10-16 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-15 – 2026-10-15 | 7 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-14 – 2026-10-14 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-13 – 2026-10-13 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-12 – 2026-10-12 | 3 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-11 – 2026-10-11 | 12 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-10 – 2026-10-10 | 8 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-09 – 2026-10-09 | 2 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-08 – 2026-10-08 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-06 – 2026-10-06 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-05 – 2026-10-05 | 4 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-04 – 2026-10-04 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-02 – 2026-10-02 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-10-01 – 2026-10-01 | 2 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-30 – 2026-09-30 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-28 – 2026-09-28 | 3 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-27 – 2026-09-27 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-26 – 2026-09-26 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-23 – 2026-09-23 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-22 – 2026-09-22 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-20 – 2026-09-20 | 18 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-16 – 2026-09-16 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-14 – 2026-09-14 | 2 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-13 – 2026-09-13 | 10 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-12 – 2026-09-12 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-10 – 2026-09-10 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-08 – 2026-09-08 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-07 – 2026-09-07 | 4 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-05 – 2026-09-05 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-03 – 2026-09-03 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-09-01 – 2026-09-01 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-08-31 – 2026-08-31 | 2 | 2026-10-20T22:50:19.2913964Z |
| 2026-08-28 – 2026-08-28 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-08-24 – 2026-08-24 | 16 | 2026-10-20T22:50:19.2913964Z |
| 2026-08-23 – 2026-08-23 | 3 | 2026-10-20T22:50:19.2913964Z |
| 2026-08-17 – 2026-08-17 | 2 | 2026-10-20T22:50:19.2913964Z |
| 2026-08-14 – 2026-08-14 | 4 | 2026-10-20T22:50:19.2913964Z |
| 2026-08-09 – 2026-08-09 | 5 | 2026-10-20T22:50:19.2913964Z |
| 2026-08-04 – 2026-08-04 | 3 | 2026-10-20T22:50:19.2913964Z |
| 2026-08-02 – 2026-08-02 | 1 | 2026-10-20T22:50:19.2913964Z |
| 2026-07-27 – 2026-07-27 | 3 | 2026-10-20T22:50:19.2913964Z |
| 2026-07-24 – 2026-07-24 | 2 | 2026-10-20T22:50:19.2913964Z |
| 2026-07-23 – 2026-07-23 | 2 | 2026-10-20T22:50:19.2913964Z |
| 2026-07-22 – 2026-07-22 | 3 | 2026-10-20T22:50:19.2913964Z |
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.5 | 13 Jun 2026 | 4 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 21:58 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:262368359bf3c46c06b727eb0bf2335e74379a13f41e8c7d5a39af4dcb6a1b84