Skip to content

Check Catalog

aisecscan ships 31 checks across seven categories. Each check is identified by an AS-<CATEGORY>-NNN ID and declares a severity, a description, and a framework mapping (OWASP LLM Top 10, OWASP Top 10 for Agentic Applications (ASI01–ASI10), NIST AI RMF).

Most checks catch misconfiguration (over-broad permissions, missing pins, hardcoded secrets). A smaller set targets agentic attack patterns specifically — combinations of capabilities that enable goal hijacking, memory poisoning, or rogue-agent behavior even when each individual setting looks reasonable on its own: AS-AGENT-002 (ASI01 Agent Goal Hijack) and AS-HOOK-005 (ASI06 Memory & Context Poisoning). These don't require reading a skill's bundled script content — they're detectable from the same frontmatter/config aisecscan already parses, by looking at combinations of declared capabilities rather than any single one.

Severities: CRITICALHIGHMEDIUMLOW


Hooks (AS-HOOK-*)

Hooks are arbitrary shell commands that run at 30+ Claude Code lifecycle events. They are the highest-risk artifact in the config surface.

ID Severity What it catches
AS-HOOK-001 CRITICAL Hook fetches & executes remote code (curl\|sh, eval $(curl))
AS-HOOK-002 HIGH Hook runs a script from a relative / world-writable path
AS-HOOK-003 MEDIUM Context-injecting hook (SessionStart/UserPromptSubmit) makes network calls
AS-HOOK-004 LOW Hook has no timeout
AS-HOOK-005 HIGH Hook fetches external content and writes it into persistent memory/context (CLAUDE.md, MEMORY.md, .claude/memory/*)

Framework mapping: OWASP LLM05 (Improper Output Handling), Agentic Tool Misuse; AS-HOOK-005 maps to OWASP Agentic AI Top 10 ASI06 (Memory & Context Poisoning).

AS-HOOK-005 is distinct from AS-HOOK-003: AS-HOOK-003 flags a context-injecting hook making a network call, which only affects the current session's context. AS-HOOK-005 requires the command to also redirect (>>, >, tee) that fetched content into a persistent memory path — a narrower, higher-confidence pattern because the poisoned content survives and re-influences every future session, not just this one.


Permissions (AS-PERM-*)

Permission rules decide what Claude Code may do without asking the user. Over-broad or bypassed rules remove the human-in-the-loop.

ID Severity What it catches
AS-PERM-001 HIGH defaultMode: bypassPermissions / acceptEdits weakens prompts
AS-PERM-002 HIGH Overly broad Bash allow (Bash(*), Bash(:*))
AS-PERM-003 MEDIUM Dangerous command allowed unscoped (curl, sudo, rm, eval, …)

Framework mapping: OWASP LLM06 (Excessive Agency), NIST AI RMF GOVERN/MANAGE.


MCP Servers (AS-MCP-*)

MCP servers are arbitrary processes (stdio) or remote endpoints (HTTP/SSE) given privileged access to the agent's context. Supply-chain and transport risks are high.

ID Severity What it catches
AS-MCP-001 HIGH Plaintext secret in MCP server env
AS-MCP-002 HIGH Remote MCP server over cleartext http://
AS-MCP-003 HIGH enableAllProjectMcpServers: true (auto-trust all project MCP)
AS-MCP-004 MEDIUM stdio MCP pulls an unpinned remote package (npx -y pkg)
AS-MCP-005 HIGH* stdio MCP pins a package with a known vulnerability (live OSV.dev lookup)
AS-MCP-007 LOW** stdio MCP server has no explicit timeout

Framework mapping: OWASP LLM03 (Supply Chain), MCP security guidance; AS-MCP-007 maps to OWASP LLM10 (Unbounded Consumption).

* AS-MCP-005 severity is taken from the matched OSV advisory (CRITICAL/HIGH/MEDIUM/LOW), not fixed.

** AS-MCP-007 only applies to stdio (command-launched) servers — a remote (url-based) server already gets a sane ~60-second default per-request timer. A stdio server with no timeout falls back to MCP_TOOL_TIMEOUT, which defaults to roughly 28 hours — long enough that a hung process is, in practice, unbounded. AS-MCP-006 (MCP server not on an explicit allowlist) remains a separate, unimplemented roadmap item — not to be confused with this check.


Environment & Secrets (AS-ENV-*, AS-SECRET-*)

Endpoint redirect and hardcoded credentials are both exfiltration and MITM vectors.

ID Severity What it catches
AS-ENV-001 HIGH API endpoint/token redirected away from Anthropic (ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN)
AS-SECRET-001 HIGH Hardcoded secret/API key in a config file

Framework mapping: OWASP LLM02 (Sensitive Information Disclosure).


Dependencies (AS-DEP-*)

Skills can bundle a requirements.txt or package.json. A pinned dependency with a known CVE is a supply-chain risk independent of whether the pin itself is "good practice" (see AS-MCP-004, which flags the opposite problem — no pin at all).

ID Severity What it catches
AS-DEP-001 HIGH* Skill dependency pinned to a version with a known vulnerability (live OSV.dev lookup)

Framework mapping: OWASP LLM03 (Supply Chain).

* Severity is taken from the matched OSV advisory. Only pinned versions (pkg==1.2.3) are checked — OSV lookups need a concrete version to test against an affected range. Unpinned dependencies aren't silently treated as safe; they're simply out of scope for this check.

Network and offline behavior: this check calls OSV.dev (no API key required) and caches results to ~/.cache/aisecscan/osv_cache.json for 24h. Pass --offline to skip the lookup entirely — the check then finds nothing rather than reporting stale or fabricated results. Unlike scanners that ship a bundled "offline CVE list," aisecscan does not: a static list goes stale the day it's written and makes an offline scan look identical to a fully-informed one. --offline makes the tradeoff explicit instead of hiding it.


Agents & Subagents (AS-AGENT-*)

Agents inherit permissions and can spawn further agents. Over-privilege compounds across the call chain.

ID Severity What it catches
AS-AGENT-001 HIGH Over-privileged agent/skill (bypassPermissions, tools: *)
AS-AGENT-002 MEDIUM* Agent/skill combines an untrusted-input tool (WebFetch, WebSearch, mail/calendar/feed-like MCP tools) with a high-impact action tool (Bash, write/send/pay/deploy/delete-like tools)
AS-AGENT-005 LOW** Agent frontmatter has no effective maxTurns bound — missing entirely, or present but not a positive integer
AS-AGENT-006 CRITICAL Agent sets permissionMode: bypassPermissions/acceptEdits (no approval checkpoint) AND has no effective maxTurns — unattended and unbounded at the same time
AS-AGENT-007 HIGH Agent sets background: true (runs detached) AND has no effective maxTurns — unobserved and unbounded at the same time

Framework mapping: OWASP LLM06 (Excessive Agency); AS-AGENT-002 maps to OWASP Agentic AI Top 10 ASI01 (Agent Goal Hijack) and LLM01 (Prompt Injection); AS-AGENT-005/AS-AGENT-006/AS-AGENT-007 map to OWASP LLM10 (Unbounded Consumption).

* AS-AGENT-002 escalates to HIGH when permissionMode is bypassPermissions/acceptEdits (no approval checkpoint at all). This check flags a combination of capabilities, not a single bad setting — an agent with WebFetch + Bash is common and often legitimate; the finding is a prompt to add a human-approval or agent-separation checkpoint per OWASP ASI01 guidance, not necessarily a bug.

AS-AGENT-006 and AS-AGENT-007 are compound checks in the same spirit as AS-AGENT-002: AS-AGENT-001 already flags bypassPermissions alone, and AS-AGENT-005 already flags a missing maxTurns alone, but the combination is worse than either — an agent that can act without approval and never stops, or one that runs detached and never stops, with no per-agent or repo-wide safety net to fall back on (there is no settings.json-level default for either maxTurns or a spend cap — see below).

What this can't catch (checked, not just unimplemented): two related ideas were considered and ruled out as not statically checkable, rather than deferred to a roadmap —

  • A maxBudgetUsd-style spend cap in agent frontmatter. No such field exists on the .claude/agents/*.md / plugin agents/*.md surface. Budget capping (maxBudgetUsd / max_budget_usd) is an Agent SDK query()-time option only — a runtime call parameter, never persisted to a file — so there is nothing in any repo for a static scanner to read.
  • A repo-wide settings.json default for maxTurns or spend, so individual agents wouldn't be the only line of defense. settings.json's schema (project/user/managed) has no such key at any scope; per-agent maxTurns in each agent's own frontmatter is the only lever, with no floor/ceiling settable from one place. AS-AGENT-005/006/007 are therefore the full extent of what static analysis can offer here — there's no missing-global-setting to also flag.

** AS-AGENT-005 fires unconditionally (like AS-HOOK-004's missing-timeout check) — there is no platform default cap on agent turns, so a missing maxTurns genuinely means unbounded. It escalates from LOW to MEDIUM when the field is present but broken (non-integer, zero, negative, or a bool) — that's worse than missing, since the config looks safe but doesn't actually bound anything.


Prompts & Steering (AS-PROMPT-*)

CLAUDE.md, skills, and agents are untrusted text that steers the model. Malicious contributions can inject instructions or hide payloads.

ID Severity What it catches
AS-PROMPT-001 MEDIUM Prompt-injection / hidden-unicode indicators in steering files
AS-PROMPT-002 MEDIUM Instructions tell the agent to disregard turn limits, resist interruption, or run indefinitely

Framework mapping: OWASP LLM01 (Prompt Injection); AS-PROMPT-002 maps to OWASP LLM10 (Unbounded Consumption).

AS-PROMPT-002 is distinct from AS-PROMPT-001: that check targets untrusted content trying to redirect the agent; this one targets the agent's own authored instructions telling the model to disregard turn limits or resist interruption. maxTurns is a hard harness-level stop regardless of what the prompt says, so this can't actually defeat the cap — but it makes hitting that cap on every single invocation far more likely instead of the agent stopping when the task is genuinely done, and it reads as an attempt to override a safety backstop even where the backstop itself can't be overridden. Deliberately narrow phrasing (specific co-occurring words, not generic "keep iterating until done" language, which is common and benign) to keep false positives low.


Skills (AS-SKILL-*)

Skills extend Claude Code's capabilities. Malicious or misconfigured skills can grant shell access, bypass sandboxing, or hide obfuscated payloads.

ID Severity What it catches
AS-SKILL-001 CRITICAL Skill requests write access to agent identity files
AS-SKILL-002 HIGH Skill has a social-engineering Prerequisites section with pipe-to-shell
AS-SKILL-003 HIGH Universal-Format skill missing a cryptographic signature
AS-SKILL-004 HIGH Skill sets permissions.network: true (binary boolean, not a domain allowlist)
AS-SKILL-005 HIGH Skill declares explicit shell access
AS-SKILL-006 HIGH Skill risk_tier contradicts declared permissions (risk-tier spoofing)
AS-SKILL-007 CRITICAL Skill file contains YAML unsafe-execution tags
AS-SKILL-008 HIGH Skill explicitly disables sandboxed execution
AS-SKILL-009 MEDIUM Universal-Format skill missing version field (update-drift risk)
AS-SKILL-010 MEDIUM Skill body contains a standalone base64-encoded block (obfuscated payload)
AS-SKILL-011 MEDIUM Universal-Format skill missing publisher field (governance gap)
AS-SKILL-012 MEDIUM Multi-platform skill missing a signature (security metadata lost in translation)

Framework mapping: OWASP LLM03 (Supply Chain), LLM06 (Excessive Agency), LLM01 (Prompt Injection).


Model sensitivity

Some checks flag content whose real-world exploitability depends on which model executes it — prompt injection, social-engineering framing, obfuscated payloads, and injected hook context are all things a frontier model is more likely to resist than a smaller/less-aligned one. These checks are marked model_sensitive: AS-PROMPT-001, AS-PROMPT-002, AS-HOOK-003, AS-SKILL-002, AS-SKILL-010.

Static (default, deterministic, offline):

aisecscan scan . --model-tier low

Bumps model_sensitive findings one severity level (capped at CRITICAL), reflecting that the content is riskier if it ends up running on a smaller model. --model-tier high (the default) leaves severities unchanged. This is a static adjustment based on general model-capability reasoning — it does not test any specific model.

Dynamic (optional, live, costs tokens — aisecscan probe):

export ANTHROPIC_API_KEY=sk-ant-...
aisecscan probe . --model claude-haiku-4-5 --model claude-sonnet-5

Actually sends each model_sensitive finding's content to the named model(s), using your own API key, and has a judge model assess whether the target complied with an embedded instruction rather than just describing it. Reports VULNERABLE / RESISTANT / INCONCLUSIVE per model per finding.

This is a fundamentally different kind of check from everything else in aisecscan: it is non-deterministic (the same content can probe differently across runs), spends tokens, and is never invoked by scan. Treat a probe result as a signal to investigate, not a definitive verdict — a single judge call can be wrong. It exists because a static scanner cannot answer "does this specific model actually fall for this," only "does this content look like something that would try."


AIVSS scoring

Every check also carries an OWASP AIVSS-Agentic score, surfaced with aisecscan scan --aivss. This layers agent-specific risk amplification (autonomy, tool use, memory, multi-agent interaction, etc.) on top of Severity — see AIVSS Scoring for the formula, what's official-spec vs. our own mapping, and how to reproduce a number by hand.


Suppressing findings

Add an inline directive on the offending line to suppress a specific check:

"defaultMode": "acceptEdits"  // aisecscan:ignore AS-PERM-001

Or pass --skip-check AS-PERM-001 on the CLI to skip globally for a run.


Roadmap

Checks planned for v1.x / v2:

ID Description
AS-ENV-002 Code-exec helpers (apiKeyHelper, statusLine, awsCredentialExport) pointing to external scripts
AS-HOOK-006 Unsafe tool_input interpolation in hook commands (shell injection via agent output)
AS-MCP-006 MCP server not on an explicit allowlist
AS-XFILE-001 Project scope re-allows a managed/user-scope deny (cross-file pass)
AS-XFILE-002 Committed permissive settings.local.json not gitignored
AS-AGENT-003 Skill declares both permissions.network: true and write access to a memory-persisted path (ASI06, skill-level companion to AS-HOOK-005)
AS-AGENT-004 Multi-agent config with no message-integrity/authentication between agents (ASI07 Insecure Inter-Agent Communication)