A local-first static scanner that finds likely AI agents in Python, JavaScript, and TypeScript, maps what they can reach, and blocks newly introduced high-confidence critical risks — without uploading a line of code.
$ pipx install stoa-agent-risk $ stoa scan . stoa 0.1.0 — scanned 347 files Agent candidates: 4 (3 high confidence) Findings: 1 critical, 2 high, 5 medium (2 suppressed) $ open stoa-report.html
Evidence-scored across 10 frameworks (LangChain, LangGraph, CrewAI, AutoGen, LlamaIndex, OpenAI Agents SDK, PydanticAI, Bedrock, Semantic Kernel, LiteLLM). One regex never qualifies a file; test paths are downweighted; a UserAgentParser never counts.
Every candidate lists exactly why it was flagged — “LangChain agent construct · line 24” — in collapsible sections, plus a confidence tier (high / medium / low) from its score.
14 LLM providers, 21 capabilities (payment access, DB writes, shell exec…), and 28 integrations from Stripe to Snowflake — reported as call sites, never as runtime call counts.
Most recent non-bot author, last commit, and CODEOWNERS per candidate. No emails collected; credentials stripped from remote URLs.
The HTML report ranks candidates by high-impact capabilities × sensitive integrations × finding severity — the refund agent with payment access outranks the demo chatbot.
A self-contained, CSP-locked, no-JavaScript HTML report for humans; a deterministic, schema-versioned JSON registry for machines — byte-identical across runs, reserved fields for future versions.
Stable IDs, redacted snippets, remediations, move-proof fingerprints. Only high-confidence credential findings can fail a build — regex never gates what it can’t prove.
| Rule | Finding | Severity | Gates CI? |
|---|---|---|---|
| SEC001 | Hardcoded API credential (OpenAI, Anthropic, GitHub, Slack, Stripe-live, AWS…) with entropy + placeholder checks | critical | High confidence only |
| SEC002 | Hardcoded password — literal assignments only, never env lookups or placeholders | high | High confidence only |
| SEC003 | Interpolated SQL — f-strings, .format(), %, concatenation, template literals | high | No |
| REL001 | Swallowed exception — except: pass, empty catch {} | medium | No |
| NET001–002 | Insecure non-local HTTP · request timeout not observed | medium | No |
| CTRL001–003 | Auth / validation / rate-limit control not observed — one review prompt per candidate, max | info | Never |
Secrets are redacted the moment they’re matched — tests prove the raw value is absent from terminal, JSON, HTML, annotations, summaries, and logs. Suppressions are rule-scoped and always counted.
api_key = "sk-proj-Zx9mKq3vNp7rTb2wYc5dHj8fLg4sVn6a" api_key = "sk-pro…[REDACTED:a18c45f21a0e]"
query = f"SELECT * FROM {t}" # stoa: ignore[SEC003] enum # stoa: ignore-file[CTRL001] · .stoaignore · stoa.toml
With --base origin/main --fail-on-new critical, only findings on added lines gate. Old debt is reported, never blocking.
New high-confidence critical → build fails with a ::error annotation on the exact line. Unresolvable base? Stoa fails open with a warning, never silently.
Five stops from a bare laptop to a repository where agents ship fast — and new critical risk doesn’t.
$ pipx install stoa-agent-risk && stoa --version
Python 3.10+. No accounts, no API keys, no config to start — and nothing you scan ever leaves your machine.
$ stoa scan . && open stoa-report.html
Always exits 0 until you ask for gates, so explore freely. You get the HTML report for humans and stoa-registry.json for machines. A ~2,000-file monorepo scans in under a second.
query = f"SELECT * FROM {t}" # stoa: ignore[SEC003] internal enum
Silence false positives with rule-scoped inline ignores (reasons encouraged), .stoaignore paths, or per-rule settings in stoa.toml. Every suppression stays counted in the report — nothing disappears silently.
$ stoa init githubScaffolds the workflow, stoa.toml, and .stoaignore (never overwrites without --force). Commit them and every PR is diffed against its base — only new high-confidence criticals fail the build, with line annotations, a job summary, and report artifacts. Protect those three files with CODEOWNERS.
$ stoa scan . --json stoa-registry.json > "Read stoa-registry.json and fix the new critical findings"
Claude Code, Cursor, or Copilot can read the deterministic, already-redacted JSON to summarize your agent inventory and remediate findings — without ever seeing a raw credential. The loop closes: agents write the code, Stoa audits it, agents fix what it finds.