vinceamstoutz / symfony-security-auditor
AI-powered multi-agent security auditor for Symfony applications — provider-agnostic via symfony/ai
Package info
github.com/vinceAmstoutz/symfony-security-auditor
Type:symfony-bundle
pkg:composer/vinceamstoutz/symfony-security-auditor
Requires
- php: >=8.3
- composer-runtime-api: ^2.0
- league/uri-polyfill: ^7.8
- mcp/sdk: ^0.9.0
- nikic/php-parser: ^5.3
- psr/clock: ^1.0
- psr/log: ^3.0
- symfony/ai-bundle: ^0.15
- symfony/clock: ^7.4 || ^8.0
- symfony/config: ^7.4 || ^8.0
- symfony/console: ^7.4 || ^8.0
- symfony/dependency-injection: ^7.4 || ^8.0
- symfony/deprecation-contracts: ^2.5 || ^3
- symfony/filesystem: ^7.4 || ^8.0
- symfony/finder: ^7.4 || ^8.0
- symfony/http-client: ^7.4 || ^8.0
- symfony/models-dev: >=130.0
- symfony/process: ^7.4 || ^8.0
- symfony/string: ^7.4 || ^8.0
- symfony/validator: ^7.4 || ^8.0
- symfony/yaml: ^7.4 || ^8.0
Requires (Dev)
- deptrac/deptrac: ^4.6
- ergebnis/composer-normalize: ^2.52
- ergebnis/phpunit-agent-reporter: ^1.0
- ergebnis/phpunit-slow-test-detector: ^2.24
- friendsofphp/php-cs-fixer: ^3.95
- phpstan/extension-installer: ^1.4
- phpstan/phpdoc-parser: ~2.3.0
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpstan/phpstan-symfony: ^2.0
- phpunit/phpunit: ^12.5
- rector/rector: ^2.4
- rector/swiss-knife: ^2.4
- spaze/phpstan-disallowed-calls: ^4.12
- staabm/phpstan-todo-by: ^0.3
- symfony/ai-anthropic-platform: ^0.15
- symfony/dotenv: ^7.4 || ^8.0
- symfony/error-handler: ^7.4 || ^8.0
- symfony/var-dumper: ^7.4 || ^8.0
- symplify/phpstan-rules: ^14.10
- tomasvotruba/cognitive-complexity: ^1.0
Suggests
- symfony/ai-albert-platform: To run the audit against the Albert platform (needs a base_url)
- symfony/ai-amazee-ai-platform: To run the audit against amazee.ai (needs a base_url)
- symfony/ai-anthropic-platform: Anthropic (Claude) platform bridge — claude-opus-5-5, claude-sonnet-5-5, claude-haiku-5-5
- symfony/ai-azure-platform: Azure OpenAI platform bridge — enterprise GPT-5.6, o4-mini
- symfony/ai-bedrock-platform: AWS Bedrock platform bridge — Claude, Nova, Llama on AWS
- symfony/ai-deep-seek-platform: DeepSeek platform bridge — deepseek-flash, deepseek-v4-pro
- symfony/ai-eden-ai-platform: Eden AI platform bridge — OpenAI-compatible gateway over many providers
- symfony/ai-fireworks-platform: Fireworks AI platform bridge — hosted open-weight models
- symfony/ai-gemini-platform: Google Gemini platform bridge — gemini-3.1-pro-preview, gemini-3.6-flash
- symfony/ai-generic-platform: Generic OpenAI-compatible platform bridge for any AI gateway or self-hosted endpoint exposing a custom base_url plus token (LiteLLM, vLLM, LocalAI, …)
- symfony/ai-mini-max-platform: MiniMax platform bridge — MiniMax-M3, MiniMax-M2.7
- symfony/ai-mistral-platform: Mistral platform bridge — mistral-large-latest, codestral-latest
- symfony/ai-ollama-platform: Ollama local inference bridge — llama3.3, deepseek-r1, qwen3, phi4 (no API key)
- symfony/ai-open-ai-platform: OpenAI platform bridge — gpt-5.6, gpt-4.1, o4-mini
- symfony/ai-open-responses-platform: OpenAI Responses API platform bridge
- symfony/ai-together-platform: Together AI platform bridge — hosted open-weight models
- symfony/ai-venice-platform: Venice AI platform bridge — private inference
- symfony/ai-vertex-ai-platform: Google Vertex AI platform bridge — Gemini + Claude on GCP
Provides
None
Conflicts
None
Replaces
None
- 2.x-dev
- 1.x-dev
- 1.22.1
- 1.22.0
- 1.21.0
- 1.20.1
- 1.20.0
- 1.19.1
- 1.19.0
- 1.18.0
- 1.17.0
- 1.16.0
- 1.15.0
- 1.14.0
- 1.13.0
- 1.12.0
- 1.11.0
- 1.10.1
- 1.10.0
- 1.9.0
- 1.8.0
- 1.7.2
- 1.7.1
- 1.7.0
- 1.6.4
- 1.6.3
- 1.6.2
- 1.6.1
- 1.6.0
- 1.5.0
- 1.4.0
- 1.3.3
- 1.3.2
- 1.3.1
- 1.3.0
- 1.2.1
- 1.2.0
- 1.1.1
- 1.1.0
- dev-main / 1.0.x-dev
- 1.0.0
- dev-feat/eager-ritchie-4ni3v6
- dev-ccr-a70e2699-nsqbrx
- dev-claude/implementation-379-streaming
- dev-feat/zealous-mayer-0mnz6p
- dev-claude/bot-impersonation-issues-t96em2
- dev-claude/classification-seam-248
This package is auto-updated.
Last update: 2026-11-06 16:24:35 UTC
README
AI-powered, multi-agent security auditor for Symfony applications. An adversarial Attacker ⚔ Reviewer loop catches the application-level flaws SAST tools miss. Provider-agnostic via symfony/ai.
Note
main holds exactly the latest release, so everything documented here is in the version you install. Development happens on version branches.
What's new in 1.22
- Claude Opus 5.5 by default —
initlists the providers and the newest models the pricing catalog prices, to pick by number, and suggestsclaude-opus-5-5. - Gates in YAML, config per project —
audit.min_score,audit.fail_on_incomplete,audit.formatandaudit.outputlive in the configuration, and the standalone binary layers the audited project's own.symfony-security-auditor.yamlover your user config. A flag always wins. - Sharper pull-request audits —
audit.tools_scope: scannedlets a--sinceor--pathrun follow a changed controller into unchanged files, andaudit.report_path_prefixputs SARIF and GitHub annotations on the right file in a monorepo. - Honest reports —
xssis a finding type of its own, files the scan left out are listed, and a run that found no file readsUNKNOWNinstead of a clean grade. - Standalone binary, all the commands —
audit:diff,audit:trendandaudit:baselinerun with no configuration;self-updateshows its download progress, andself-update --snapshotinstalls the build of every push to1.xto try a fix before it ships. - More secrets scrubbed — Symfony secrets-vault keys,
Authorizationheaders, and the credentials passed to PDO, LDAP, Redis, HttpClient and many more are redacted before any code leaves your machine.
Everything else is in the changelog.
Why this auditor?
Traditional PHP static analysis tools (PHPStan, Psalm) catch type errors. Static SAST tools (Psalm Security, Progpilot) follow taint flows but cannot reason about business logic, missing authorization, or multi-file attack chains. Dependency scanners (Dependabot, Renovate, Snyk) only flag known CVEs in third-party packages. This auditor runs alongside them, targeting the application-level logic flaws they cannot see.
Side-by-side comparison with PHPStan, Psalm, Progpilot, Dependabot, and Snyk: FAQ.
What it does
An adversarial Attacker agent hunts for vulnerabilities; a skeptical Reviewer agent culls false positives over up to three iterations — then emits a validated report in console, JSON, SARIF, HTML, or Markdown.
🔀 Pipeline: Ingestion → Mapping → Audit (Attacker ⚔ Reviewer) → Report.
See it in action
doctor — preflight check
The standalone binary checks that it is ready to audit before you spend a token: configuration and API key, provider bridge, Composer, and pricing catalog. It exits 1 when a check fails, so it drops into a CI preflight step — see doctor.
symfony-security-auditor doctor
--dry-run mode
Scans files and estimates token usage and cost without calling the LLM. Use this to gauge cost before committing to a full audit.
bin/console audit:run --dry-run
No LLM calls are made; the exit code is 0 unless the command is refused before the estimate — an invalid option or project path, or a --path outside the project — which exits 1.
Console mode
While the pipeline runs, the audit narrates itself live — an attack-surface overview, each finding streamed (color-coded by severity in a terminal) the moment the Attacker flags it, per-chunk timing, and a reviewer tally. In CI or any non-TTY output it degrades to clean, append-only lines (no bar, no ANSI codes). Progress is suppressed for any non-console --format to stdout and for --dry-run.
The full report renders the same way in console, JSON, SARIF, HTML, and Markdown — see CLI reference and output formats.
Getting Started
The auditor ships two maintained ways to run it — pick the one that fits:
- Standalone CLI (recommended) — one download, configured once, audits any project with zero footprint in it. Best for most users, and for auditing a project you don't want to add a dependency to.
- Symfony bundle — wired into a Symfony app via Flex. Pick this to extend the auditor (custom services, decorated ports) or to pin it in the app's
devdependencies.
Tip
Both expose the same audit command, options, and output formats — see the CLI reference — and both can serve the auditor to your AI assistant over MCP (experimental).
Standalone tool (binary)
One install, many projects, zero footprint in the audited app. Each release ships a self-contained native binary with its own PHP runtime for Linux, macOS, and Windows.
Requirements
Running audits needs nothing but the binary and an API key for your provider (not even that for a local model such as Ollama).
The one-time init also needs composer and PHP on your machine, to download the package that talks to your AI provider. It checks for both before asking anything and says which one is missing.
| System | Install PHP and Composer |
|---|---|
| Debian, Ubuntu, WSL | sudo apt update && sudo apt install -y php-cli php-curl php-mbstring php-xml unzip composer |
| macOS | brew install composer (installs PHP with it) |
| Windows | PHP from https://windows.php.net/download/, then the Composer installer from https://getcomposer.org/download/ |
| Other Linux | the php-cli, composer and unzip packages of your package manager |
On WSL, install them inside WSL: a Windows Composer reached through /mnt/c/… cannot find a PHP there. --since needs git, and live CVE lookups use composer audit when composer is present.
1. Install
# Linux, macOS, Windows under WSL curl -fsSL https://raw.githubusercontent.com/vinceAmstoutz/symfony-security-auditor/main/install.sh | sh
# Native Windows (PowerShell, Git Bash, MSYS, Cygwin) irm https://raw.githubusercontent.com/vinceAmstoutz/symfony-security-auditor/main/install.ps1 | iex
Both detect your OS and CPU, download the matching binary and abort rather than install one whose SHA-256 checksum they cannot verify. You can also download an asset from the latest release and check it with its .sha256 file.
Tip
Set SSA_INIT=1 on either command and the installer runs the guided init right after downloading ($env:SSA_INIT = '1' in PowerShell). With a terminal it prompts for your provider and API key; in a pipe or CI it takes the Anthropic defaults and stores no key.
2. Configure — the guided init
symfony-security-auditor init
init walks you through three things:
- The config file:
~/.config/symfony-security-auditor/config.yamlon Linux/macOS,%APPDATA%\symfony-security-auditor\config.yamlon Windows. - The provider bridge: the package that talks to your AI provider, downloaded with
composer. - Your API key: pasted invisibly, never echoed, never in your shell history. Press Enter to skip it and run
auth:setlater, or keep using an environment variable.
The config takes the bundle's keys without the symfony_security_auditor: wrapper, plus a platform: block handed to symfony/ai — see configuration.
3. Run
symfony-security-auditor audit /path/to/your/symfony/project
audit is an alias for audit:run; every option of the CLI reference (--format, --output, --dry-run, --since, --fail-on, …) works identically. Every run names the key it is about to spend, masked (API key: sk-ant…qF4A).
Managing the stored key
| Command | What it does |
|---|---|
auth:set |
Store or replace the key — prompts invisibly, writes an owner-only file |
auth:status |
Show which key an audit would use, where it came from, and its SHA-256 fingerprint — never the key |
auth:remove |
Forget the stored key on this machine |
The key lives in an owner-only credentials.json next to your config, which an audit refuses to read if other users can. An exported variable always wins, so Docker, Kubernetes and CI are unchanged: ANTHROPIC_API_KEY=$(pass show anthropic/api-key) symfony-security-auditor audit .. Storing nothing is fine too — Providing the API key covers environment variables, mounted secret files, password managers and CI secrets.
4. Keep it up to date
symfony-security-auditor self-update # download + verify + replace, if newer symfony-security-auditor self-update --check # only report whether a newer version exists
self-update verifies the checksum before replacing the binary — see the CLI reference. self-update --snapshot (or SSA_VERSION=snapshot with the installers) installs the pre-release built from every push to the development branch; a plain self-update returns to the latest release.
Use it as a Symfony bundle
1. Install — Symfony Flex wires everything
Installing the bundle requires PHP 8.3+ and Symfony 7.4+ in the host application (see composer.json) — the standalone binary needs no PHP to audit, since it bundles its own runtime (only its one-time init needs PHP and Composer, see its requirements).
composer require --dev vinceamstoutz/symfony-security-auditor
The official Flex recipe registers the bundle (dev/test) and drops a pre-configured config/packages/symfony_security_auditor.yaml.
Not using Flex? See Manual setup.
2. Install a platform bridge
# Anthropic shown
composer require symfony/ai-anthropic-platform
Full list of supported providers: Configuration → Supported platforms.
3. Configure the platform
# config/packages/ai.yaml (or e.g. config/packages/ai_anthropic_platform.yaml) ai: platform: anthropic: api_key: '%env(ANTHROPIC_API_KEY)%'
4. Adjust the auditor config
The Flex recipe already created this file — pick your model:
# config/packages/symfony_security_auditor.yaml symfony_security_auditor: model: 'claude-opus-5-5'
Optionally pick a one-knob preset — fast, balanced (default), or thorough:
# config/packages/symfony_security_auditor.yaml symfony_security_auditor: profile: 'fast'
A profile only fills the keys you leave unset — any explicitly configured key always wins. See Cost & Performance for exactly what each profile sets.
5. Run
# audit the current directory (`bin/console audit` is an equivalent alias) bin/console audit:run # or point at another project bin/console audit:run /path/to/your/symfony/project
Want JSON, SARIF, HTML, or Markdown instead? Add --format json --output report.json, --format sarif --output report.sarif, --format html --output report.html, or --format markdown --output report.md. See CLI reference.
Estimate cost before running:
bin/console audit:run --dry-run
Warning
Audit reports list your application's vulnerabilities. On a public repository, CI artifacts are publicly downloadable — storing the report exposes your attack surface. Prefer GitHub Code Scanning (SARIF, restricted to collaborators), private storage (S3/GCS with IAM), or notification-only. See Report Visibility on Public Repositories.
Tip
Schedule the audit as a nightly CI job — the multi-agent LLM loop can take minutes, so blocking PRs on it hurts productivity. CI Integration has ready-to-copy GitHub Actions and GitLab CI schedules and a split-model config to control API costs. For dependency CVEs, pair it with Dependabot or Renovate — this auditor targets the application-level logic flaws those scanners cannot see.
Use it from your AI assistant (MCP)
Warning
mcp:serve is experimental. The command, the audit tool and its input schema may change in any release, including a MINOR or PATCH one, and are not covered by the backward compatibility promise.
mcp:serve starts a Model Context Protocol server, so any MCP client — Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, Gemini CLI, Codex CLI, … — can audit a project on request and read back the JSON report. It works from the standalone binary and from the bundle alike:
# Claude Code, with the standalone binary
claude mcp add --transport stdio symfony-security-auditor -- symfony-security-auditor mcp:serve
{
"mcpServers": {
"symfony-security-auditor": {
"command": "symfony-security-auditor",
"args": ["mcp:serve"]
}
}
}
The second snippet is the shape Claude Desktop, Cursor, Windsurf and Gemini CLI read; with the bundle, use "command": "php" and "args": ["/absolute/path/to/bin/console", "mcp:serve"].
With the binary, the server reads its configuration once, when it starts — your user config and the .symfony-security-auditor.yaml of the folder it starts in — and applies it to every project it audits, never the audited project's own file: start it from the project it will audit (see Per-project overrides).
Note
The audit still runs on your configured provider and model, not on the assistant's, so it needs the same API key as a CLI run — with the binary, store it once with auth:set so a desktop client finds it. Point the auditor at a local Ollama and it needs no key at all. Setup for every client, including VS Code and Codex CLI: mcp:serve.
Features
- Multi-agent loop — adversarial Attacker + skeptical Reviewer cut false positives across up to 3 iterations, with confirmed findings fed back so later iterations generalize patterns instead of re-finding the same bugs, and the Reviewer remembering its own rejections across runs.
- 50 vulnerability types covering OWASP-aligned categories: Injection, Broken Access Control, Logic Flaws, Symfony-specific, Data Exposure, Cryptographic — including the modern Symfony 7.x/8.x surface (Authenticators, Messenger handlers, Webhooks, Serializer denormalizers, Schedules, RateLimiter, Mailer, cache poisoning).
- Symfony-aware — understands Controllers, Voters, Forms, Firewalls, Routes,
#[IsGranted],denyAccessUnlessGranted,#[MapRequestPayload], Twig/Live Components, and surfaces controllers without proper access checks. - Feature-based chunking — groups a controller with its entity, repository, form, voter, and templates so the Attacker can follow data flow across files.
- Deterministic pre-scan — a zero-token risk-marker pass flags concrete locations (unserialize,
|raw, hardcoded secrets, unsafe Doctrine, …) to focus the LLM; optional lean mode drops marker-free files to cut tokens. Results from other SAST tools can be imported as markers via SARIF. - Diff mode —
audit:run --since=mainaudits only changed files for fast pull-request CI; withaudit.tools_scope: scannedthe Attacker can still follow a changed controller into the unchanged files it calls. - Cross-file investigation tools — Attacker (and optionally Reviewer) can
read_file,grep,list_files, andlookup_advisory(zero-config live CVE lookups viacomposer audit, backed by Packagist + GitHub Security Advisories). - One-knob profiles —
fast,balanced, andthoroughpreset the cost/speed/depth levers in a single line; any explicit key still wins. - Tunable for speed & cost — split-model (powerful Attacker + cheap Reviewer, ~20× cheaper), concurrent Attacker and Reviewer calls (
attacker_max_concurrent/reviewer_max_concurrent), Anthropic prompt caching on by default (~90% input-token discount), content-hash caching that skips identical chunks, cheap→expensive escalation, and code slicing. - Secret-safe by default — credential-shaped strings are scrubbed from file content before it reaches the LLM, and
privacy.offline_onlyrefuses every network call the auditor owns (see Security by design). - Rate-limit aware — reactive retry with
Retry-After-aware exponential backoff plus an optional proactive token-bucket limiter keep you inside provider quotas (see Cost & Performance). - Actionable findings — optionally attach a copy-pasteable reproduction (curl/console/payload) and a suggested patch to every high-severity finding; each one also carries a heuristic CVSS v4.0 estimate.
- Nine output formats —
console,executive(stakeholder summary: risk level, business impact, severity/type/hotspot distributions, no per-finding detail),json,sarif(GitHub Code Scanning / GitLab Security Dashboard),html(self-contained, shareable),markdown(PR-friendly),junit(CI test-report panels),github(inline PR annotations, no SARIF upload step), andgithub-comment(PR comment headlined by the grade and score, self-updating on rerun). Baseline suppression:--generate-baselineaccepts known findings,--baselinedrops them from the report and exit code so only new findings fail CI;--min-scoregates on the normalized score independently of--fail-on. - Callable from your AI assistant (experimental) —
mcp:serveexposes the audit as an MCP tool to Claude Code, Claude Desktop, Cursor, VS Code and any other MCP client, from the binary or the bundle (see Use it from your AI assistant). - Findings over time —
audit:diffcompares two JSON reports by finding fingerprint,audit:trendtracks counts across a series of them, andaudit:baselinemerges, prunes and annotates a baseline — in the bundle and the standalone binary alike. - CI-ready — a reusable GitHub Action (
uses: vinceamstoutz/symfony-security-auditor@1.22.1) plus GitLab CI templates, with SARIF upload to Code Scanning and an optional shields.io badge tracking the report's letter grade. See CI Integration. - Extensible — strict DDD layering and a sole
LLMClientInterfaceseam let you plug in custom providers, agents, stages, advisory feeds, or report formats; project-specific attacker skills need only configuration, no PHP. - Bundle or standalone — install as a Symfony bundle, or run it from a single self-contained binary configured once at the user level to audit any project with zero footprint, kept current with
self-updateand preflighted withdoctor(see Standalone tool).
Security by design
The auditor is conservative about what leaves your machine:
- Secrets are scrubbed before they leave your machine. With
scan.secret_scrubbing.enabled: true(the default), credential-shaped strings are redacted from file content before it reaches the LLM: AWS / GitHub / Stripe / Slack / Google API keys, JWTs, PEM private keys, Symfony secrets-vault decryption keys, env-style credential assignments,Authorizationheaders, the credentials passed in code to PDO, LDAP, Redis or HttpClient, and connection-string URIs with embedded credentials (postgres://user:pass@host). Add project-specific shapes withscan.secret_scrubbing.additional_patterns. - The cache never stores your files. The filesystem cache keys LLM responses by content hash. An entry holds the findings the model reported, with the short source excerpts it quoted, and the reviewer's reasoning — never a project file — so treat
cache.dirlike a report: keep it out of shared CI caches and public artifacts. - You choose where the code goes. Source is sent only to the provider you wire in
ai.yaml. For zero third-party exposure, run fully offline with Ollama — nothing leaves your network. Setprivacy.offline_only: trueto have that enforced rather than assumed: the advisory feed is dropped (nocomposer audit) and the standalone CLI refuses to boot against a platform endpoint that is not loopback or private-range.docs/faq.mdcarries atcpdumprecipe for verifying it yourself. - Reports are sensitive — they list your weak spots. On public repos, prefer SARIF → GitHub Code Scanning (collaborator-only) over downloadable CI artifacts. See Report Visibility.
Tuning & cost
Profiles (fast / balanced / thorough), split-model, concurrency, caching, budget caps, and 429 rate-limit handling are covered in Cost & Performance — start with a profile, then override individual keys as needed.
Supported Platforms
| Platform | Bridge package | Key env var(s) |
|---|---|---|
| Anthropic (Claude) | symfony/ai-anthropic-platform |
ANTHROPIC_API_KEY |
| OpenAI | symfony/ai-open-ai-platform |
OPENAI_API_KEY |
| OpenAI Responses API | symfony/ai-open-responses-platform |
OPENAI_API_KEY plus a base_url |
| Azure OpenAI | symfony/ai-azure-platform |
AZURE_OPENAI_API_KEY, AZURE_OPENAI_BASEURL |
| Google Gemini | symfony/ai-gemini-platform |
GEMINI_API_KEY |
| Google Vertex AI | symfony/ai-vertex-ai-platform |
GCP credentials |
| AWS Bedrock | symfony/ai-bedrock-platform |
BEDROCK_API_KEY, or AWS credentials |
| DeepSeek | symfony/ai-deep-seek-platform |
DEEPSEEK_API_KEY |
| Mistral | symfony/ai-mistral-platform |
MISTRAL_API_KEY |
| MiniMax | symfony/ai-mini-max-platform |
MINIMAX_API_KEY |
| Ollama (local) | symfony/ai-ollama-platform |
(none) |
| Albert (French gov) | symfony/ai-albert-platform |
ALBERT_API_KEY plus a base_url |
| amazee.ai | symfony/ai-amazee-ai-platform |
AMAZEEAI_API_KEY plus a base_url |
| Fireworks AI | symfony/ai-fireworks-platform |
FIREWORKS_API_KEY |
| Together AI | symfony/ai-together-platform |
TOGETHER_API_KEY |
| Venice AI | symfony/ai-venice-platform |
VENICE_API_KEY |
| Eden AI | symfony/ai-eden-ai-platform |
EDENAI_API_KEY |
| Generic (AI gateway) | symfony/ai-generic-platform |
depends on the gateway |
Swapping providers requires only a config/packages/ai.yaml change — no PHP edits.
Any OpenAI-compatible endpoint behind a custom URL and token (an in-house AI gateway, LiteLLM, vLLM, LocalAI) goes through the generic platform. It is configured per instance, so the instance name is part of the platform block and, in standalone mode, part of provider: as well:
# config/packages/ai.yaml ai: platform: generic: my_gateway: base_url: '%env(GATEWAY_URL)%' api_key: '%env(GATEWAY_TOKEN)%'
See Configuration → Instance-keyed platforms.
Documentation
- Configuration — every config key, all platforms, split-model, model options, CLI reference
- Cost & Performance — profiles, split-model, concurrency, caching, budgets, and rate-limit handling
- Architecture — DDD layers, pipeline, agent loop, domain model, design decisions
- CI Integration — scheduled GitHub Actions & GitLab CI, SARIF upload, cost management
- Extending — custom LLM clients, agents, pipeline stages, report formats
- FAQ — accuracy, cost, privacy, model picks, comparisons
- Troubleshooting — empty reports, LLM errors, composer audit failures, cache issues
- Contributing — dev setup, Docker workflow, QA, PR checklist
FAQ
How much does an audit cost? Depends on project size and model. A medium Symfony app (~150 files) on Claude Opus + Haiku split-model with prompt caching enabled costs roughly $0.50 per nightly run. See CI → Managing LLM Costs.
Does it send my code to the cloud? Only to the LLM provider you configure, and credential-shaped strings are scrubbed first (see Security by design). For zero-cloud operation, use the Ollama local platform.
Full FAQ — privacy, false positives, model picks, comparisons: docs/faq.md.
Contributing
Contributions welcome, please refer to CONTRIBUTING.md.
Security
Found a vulnerability in the auditor itself? Do not open a public issue. Report privately via GitHub Security Advisories.
See SECURITY.md.
License
MIT — Copyright © Vincent Amstoutz



