| Version | Supported |
|---|---|
| 0.6.x-beta | Yes |
| < 0.6 | No; upgrade required |
During the beta, flags, intermediate-file schemas, and YAML output formats may change in minor-version bumps (0.6 → 0.7). Check the release notes before upgrading.
Do not report security vulnerabilities through public GitHub issues.
Open a GitHub Security Advisory in this repository instead. You will receive a response within 5 business days. If the issue is confirmed, a patch will be released as soon as possible.
Please include:
- a description of the vulnerability and its impact;
- steps to reproduce, if applicable;
- any mitigations you have identified.
AppSec reviewers should read this section before approving a run on a sensitive repository.
Each step of the assessment sends one bounded request to the Anthropic API. The assessment models have no file, shell, or network tools; the controller decides what each request contains:
- Step instructions from
agents/*.md. No repository content. - Source excerpts: line ranges of repository files that the step needs, served by the controller from the selected revision. A model may ask for further excerpts within a fixed per-step limit. This is how source code reaches the API: source code and configuration of the analyzed components are sent. Secrets matched by the plugin's secret patterns are masked in every excerpt.
- Earlier step results the task builds on, such as the component list or the findings to merge. Component analyses run in separate requests and do not see each other's findings.
- Business context you supply interactively, with
--context, or indocs/security/business-context.md.
The plugin does not upload the repository as a whole. The optional repository exploration of /appsec-advisor:analyze-threats is the only analysis that gives a model file tools; they are read-only and confined to a copy with secrets masked.
The Claude Code session that runs the plugin also sends its own conversation to the API, as any Claude Code session does: your messages, the plugin's progress output, and whatever else you ask it to read in that session.
Results and intermediate files are written to the assessment directory. By default it lies outside the repository, under your user data directory; see where results are stored.
| File | Content | Sensitivity |
|---|---|---|
security-assessment.md / .yaml / .sarif.json |
The report | Describes vulnerabilities in your code; treat as sensitive |
.assessment-work/ and .assessment-state.json |
Accepted step results (components, data flows, findings per component) and run state | Same as the report |
.threats-merged.json |
Merged finding list | Same as the report |
.agent-run.log |
Event log (agent, phase, and file-write events) | File paths, tool-call counts, durations |
.hook-events.log |
Token and cost accounting per tool call | Token counts and estimated cost; no repository content |
The two log files contain no source code or prompts, but they do contain file paths (for example FILE_WRITE /path/to/secrets.ts). Treat them like the reports. Logs rotate at 5 MB (logging.max_log_bytes in config.json).
A finding about a hardcoded secret names its file and line. Masking only covers secrets that match the plugin's patterns, so a secret in an unusual format can still appear in an excerpt sent to the API or in a quoted line of a finding. Treat the report and its step results as secret-handling scope.
Anthropic logs prompts and responses according to its privacy policy. API-key and Claude Pro, Team, or Enterprise subscriptions have different retention terms; check your contract.
The plugin uses prompt caching (see pricing.cache_* in config.json). Cached segments stay on Anthropic's infrastructure for the cache lifetime.
Claude Code needs a connection to api.anthropic.com. The assessment has no offline mode and cannot run where this connection is blocked.
The plugin runs locally, installed from the marketplace or from a checkout with --plugin-dir. If GitHub access is restricted, install it from an internal mirror. It fetches code only when you ask for it, for example with a Git URL as --repo or with install-baseline. It never downloads model weights.
Before you assess a codebase with production secrets, personal data, or regulated data:
- Confirm that your Anthropic contract covers the data classification of the source files that will be read.
- Decide who may read the assessment directory. It is private to your user by default; sharing a result takes an explicit export.
- If the Security Coach is enabled, review
hooks/steering_keywords.json. It adds guidance to matching prompts throughout the session, also outside plugin runs. - Rotate any hardcoded secret in the repository before the run, and assume that one the masking patterns miss can reach the API and the results.
Scanned repositories are untrusted by default. Headless runs apply the untrusted preflight before Claude starts; --trust-mode trusted is an explicit opt-in for repositories whose committed agent configuration has been reviewed. This reduces the known exposure but is not a complete sandbox against actively malicious content.
| # | Issue | Details |
|---|---|---|
| 1 | Prompt injection via repository content | Source excerpts enter the model context, and instructions planted there can steer an analysis step, for example to hide or invent a finding. The assessment models have no tools, and the controller validates every result and excerpt request, so such an injection does not directly execute commands. The hosting Claude Code session is different: the recommended permission rule is Bash(*), so repository content you ask that session to read can lead to command execution on the reviewer's machine. |
| 2 | SSRF via docs/related-repos.yaml |
(Hardened 2026-05.) scripts/contexts/load_related_repos.py checks target URLs with scripts/shared/_url_guard.py. It rejects private, loopback, link-local (including 169.254.169.254), multicast, and reserved addresses, and strips Authorization and Cookie headers on cross-host redirects. For stricter control, set APPSEC_URL_ALLOWLIST=host1,host2 and pass --strict-urls (on by default in untrusted mode). |
| 3 | File reads through symlinks | (Hardened 2026-05.) The recon walker (scripts/analyzers/recon_patterns.py) does not follow symlinks, and scripts/shared/_path_guard.py drops symlinks that point outside the repository. Reads through Claude Code's Read tool are not sandboxed. scripts/validators/preflight_untrusted.py lists escaping symlinks before the run and refuses to continue in untrusted mode. |
| 4 | Repository-owned Claude Code hooks | An interactive Claude Code session may load .claude/settings.json, .claude/hooks/, or .vscode/tasks.json from its working directory before the plugin runs. Run scripts/validators/preflight_untrusted.py --strict --strict-urls before starting an interactive session in a third-party repository, or use the headless runner, which runs this check first. The recon scanner also reports these files (Cat 28). |
| 5 | Argument injection in subprocess calls | File names and refs from the repository are passed to git (and, if the GitHub CLI is available, to an optional gh pr list) without consistent -- separators or strict validation. (Reduced 2026-05: package-manager and CVE-database tools are no longer run.) |
| 6 | Resolved 2026-05. The plugin no longer runs external audit tools such as npm audit, pip-audit, or govulncheck on repository manifests. Supply-chain checks (scripts/model/emit_sca_practice.py, emit_known_bad_libs.py, emit_dep_update_activity.py) only read files and git log. |
- Run the assessment in a disposable container or VM, not on your main workstation.
- During the scan, block outbound traffic except to
api.anthropic.comand any hosts inAPPSEC_URL_ALLOWLIST. - Before starting an interactive Claude session in the target repository, run
python3 scripts/validators/preflight_untrusted.py --repo-root <path> --strict --strict-urls. It fails on repository-owned Claude or IDE hooks, symlinks pointing outside the repository, and unchecked URLs indocs/related-repos.yaml. The headless runner does this automatically. - If the repository is not fully trusted, remove
docs/related-repos.yaml, or setAPPSEC_URL_ALLOWLISTand use--strict-urls. There is no flag that disables related repositories. - Assume the reviewer's environment may be compromised after the scan: no plain-text credentials in environment variables, no SSH agent forwarding, no cached cloud CLI tokens.
scripts/run-headless.sh uses --trust-mode untrusted by default. This mode:
- runs
scripts/validators/preflight_untrusted.py --strict --strict-urlsfirst and stops before any model call if it finds anything; - sets
APPSEC_RELATED_REPOS_STRICT_URLS=1, so related repositories requireAPPSEC_URL_ALLOWLIST; - sets
APPSEC_LOG_REDACT_PATHS=1, so.agent-run.logrecords<redacted:<basename>:<sha8>>instead of absolute paths; - refuses to run when it finds an escaping symlink, a repository-owned
.claude/file, or an unchecked related-repository URL.
Not yet covered (open a GitHub issue if you need one of these):
- mandatory isolation in a container (the script relies on the caller for isolation);
- a narrower shell permission than
Bash(*)for prompt-free interactive runs; - size or extension limits on individual manifests beyond
scripts/analyzers/scan_excludes.py.
The plugin produces security assessments by reading local repository source code. It sends source code to no external service other than the Anthropic API.
The mock server (scripts/mock-server.py) ships with illustrative data. Do not store real credentials, findings, or sensitive architecture data in it.