Stoa · agent risk scanner

Every agent inventoried. Every claim evidenced.

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.

  • Local-first
  • Zero telemetry
  • No accounts
  • Python 3.10+
  • MIT
Quick start
$ 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

What one scan gives you

Weighted detection

Agent candidates, not guesses

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.

Show your work

Line-level evidence

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.

Full reach map

Providers, capabilities, integrations

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.

Git attribution

Last touched by, not “owner”

Most recent non-bot author, last commit, and CODEOWNERS per candidate. No emails collected; credentials stripped from remote URLs.

Manager view

Highest-exposure first

The HTML report ranks candidates by high-impact capabilities × sensitive integrations × finding severity — the refund agent with payment access outranks the demo chatbot.

Two audiences

HTML + JSON reports

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.

Nine rules, honestly ranked

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.

RuleFindingSeverityGates CI?
SEC001Hardcoded API credential (OpenAI, Anthropic, GitHub, Slack, Stripe-live, AWS…) with entropy + placeholder checkscriticalHigh confidence only
SEC002Hardcoded password — literal assignments only, never env lookups or placeholdershighHigh confidence only
SEC003Interpolated SQL — f-strings, .format(), %, concatenation, template literalshighNo
REL001Swallowed exception — except: pass, empty catch {}mediumNo
NET001–002Insecure non-local HTTP · request timeout not observedmediumNo
CTRL001–003Auth / validation / rate-limit control not observed — one review prompt per candidate, maxinfoNever
0gate passed
1gate failed
2bad args / config
3scanner error

Guardrails you can trust

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.

Redaction · in source vs. in every artifact
api_key = "sk-proj-Zx9mKq3vNp7rTb2wYc5dHj8fLg4sVn6a"
api_key = "sk-pro…[REDACTED:a18c45f21a0e]"
Suppression · inline, file-wide, path, config
query = f"SELECT * FROM {t}"  # stoa: ignore[SEC003] enum
# stoa: ignore-file[CTRL001]  ·  .stoaignore  ·  stoa.toml
✓ EXIT 0 — unrelated PR over existing debt

With --base origin/main --fail-on-new critical, only findings on added lines gate. Old debt is reported, never blocking.

✕ EXIT 1 — PR adds a real-looking key

New high-confidence critical → build fails with a ::error annotation on the exact line. Unresolvable base? Stoa fails open with a warning, never silently.

Stoic about certainty

Stoa says

  • “Agent candidate” — with a confidence tier
  • “Last touched by” — commit history, plainly
  • “Call site” — what code shows
  • “Control not observed in this file”

Stoa never says

  • “Confirmed agent” — regex can’t confirm
  • “Owner” — attribution ≠ ownership
  • “API call count” — that’s runtime data
  • “Missing authentication”

Install it once, wire it into the pipeline

Five stops from a bare laptop to a repository where agents ship fast — and new critical risk doesn’t.

  1. Install30 seconds

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

  2. Take the first censusreport-only

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

  3. Teach it your repo

    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.

  4. Put it on guard dutyCI

    $ stoa init github

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

  5. Hand the registry to your coding agent

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