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
- nikic/php-parser: ^5.3
- psr/clock: ^1.0
- psr/log: ^3.0
- symfony/ai-bundle: ^0.10
- symfony/config: ^7.4 || ^8.0
- symfony/console: ^7.4 || ^8.0
- symfony/dependency-injection: ^7.4 || ^8.0
- symfony/filesystem: ^7.4 || ^8.0
- symfony/finder: ^7.4 || ^8.0
- symfony/process: ^7.4 || ^8.0
- symfony/string: ^7.4 || ^8.0
- symfony/validator: ^7.4 || ^8.0
Requires (Dev)
- ergebnis/composer-normalize: ^2.52
- ergebnis/phpunit-agent-reporter: ^0.3
- ergebnis/phpunit-slow-test-detector: ^2.24
- friendsofphp/php-cs-fixer: ^3.95
- 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
- robiningelbrecht/phpunit-coverage-tools: ^1.10
- staabm/phpstan-todo-by: ^0.3
- symfony/clock: ^7.4 || ^8.0
- symfony/dotenv: ^7.4 || ^8.0
- symfony/error-handler: ^7.4 || ^8.0
- symfony/var-dumper: ^7.4 || ^8.0
Suggests
- symfony/ai-anthropic-platform: Anthropic (Claude) platform bridge — claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5-20251001
- symfony/ai-azure-platform: Azure OpenAI platform bridge — enterprise GPT-5.4, o4-mini
- symfony/ai-bedrock-platform: AWS Bedrock platform bridge — Claude, Nova, Llama on AWS
- symfony/ai-deep-seek-platform: DeepSeek platform bridge — deepseek-chat, deepseek-reasoner
- symfony/ai-gemini-platform: Google Gemini platform bridge — gemini-3.1-pro-preview, gemini-3.5-flash
- symfony/ai-meta-platform: Meta (Llama) platform bridge — Llama-4-Scout, Llama-3.3
- symfony/ai-mistral-platform: Mistral platform bridge — mistral-large, codestral
- 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.4, gpt-4.1, o4-mini
- symfony/ai-open-responses-platform: OpenAI Responses API platform bridge
- symfony/ai-vertex-ai-platform: Google Vertex AI platform bridge — Gemini + Claude on GCP
This package is auto-updated.
Last update: 2026-06-16 15:03:18 UTC
README
AI-powered multi-agent security auditor for Symfony applications. Catches business logic flaws, broken access control, missing Voters, mass assignment, and complex injection chains that traditional SAST tools miss. Provider-agnostic via
symfony/ai— works with Claude, GPT, Gemini, Mistral, Llama, DeepSeek, and Ollama.
What it does
Feeds your Symfony project through a three-stage AI pipeline that catches what SAST tools miss: broken access control, complex injection chains, business logic flaws, missing Voters, and mass assignment vulnerabilities. An adversarial Attacker agent hunts for issues; a skeptical Reviewer agent eliminates false positives over up to three iterations. Output is a validated vulnerability report in your console, as JSON, as SARIF for GitHub Code Scanning / GitLab Security Dashboard, as a self-contained HTML report, or as PR-friendly Markdown.
Project files
│
▼
1. Ingestion — scans .php / .twig / .yaml / .xml recursively
│
▼
2. Mapping — classifies Controllers, Entities, Voters, Forms, Routes
│
▼
3. Audit — Attacker ⚔ Reviewer multi-agent loop (up to 3 iterations)
│
▼
Validated vulnerability report: console, JSON, SARIF, HTML, or Markdown
Getting Started
1. Install — Symfony Flex wires everything
composer require --dev vinceamstoutz/symfony-security-auditor
The official
Flex recipe
(published in
symfony/recipes-contrib)
automatically:
- registers
SymfonySecurityAuditorBundleinconfig/bundles.phpfor thedevandtestenvironments; - creates a pre-configured
config/packages/symfony_security_auditor.yamlwith a default model and commented split-model and rate-limit examples ready to uncomment.
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 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-4-8'
Optionally pick a one-knob preset — fast, balanced (default), or thorough;
any explicitly configured key always wins:
# config/packages/symfony_security_auditor.yaml symfony_security_auditor: profile: 'fast'
5. Run
# audit the current directory 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.
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.
- 39 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. - Diff mode —
audit:run --since=mainaudits only changed files for fast pull-request CI. - 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). - Cost levers — split-model (powerful Attacker + cheap Reviewer, ~20× cheaper), Anthropic prompt caching on by default (~90% input-token discount), content-hash caching that skips identical chunks entirely, cheap→expensive escalation, code slicing, and concurrent reviewer calls.
- PoC synthesis — optionally attach a concrete, copy-pasteable reproduction (curl/console/payload) to every high-severity finding.
- Five output formats —
console,json,sarif(GitHub Code Scanning / GitLab Security Dashboard),html(self-contained, shareable), andmarkdown(PR-friendly). Baseline suppression:--generate-baselineaccepts known findings,--baselinedrops them from the report and exit code so only new findings fail CI. - CI-ready — a reusable
GitHub Action
(
uses: vinceamstoutz/symfony-security-auditor@1.12.0) plus GitLab CI templates, with SARIF upload to Code Scanning. See CI Integration. - DDD architecture — strict layering and a sole
LLMClientInterfaceseam let you plug in custom providers, agents, stages, advisory feeds, or report formats.
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.
| Concern | This auditor | PHPStan / Psalm | Psalm Security / Progpilot (SAST) | Dependabot / Snyk |
|---|---|---|---|---|
| Type bugs | ❌ | ✅ | partial | ❌ |
| Taint flow (SQLi, XSS) | ✅ | ❌ | ✅ | ❌ |
Missing #[IsGranted] / Voter |
✅ | ❌ | ❌ | ❌ |
| Business logic flaws | ✅ | ❌ | ❌ | ❌ |
| IDOR / mass assignment | ✅ | ❌ | partial | ❌ |
| Firewall misconfiguration | ✅ | ❌ | ❌ | ❌ |
| Cross-file attack chains | ✅ | ❌ | partial | ❌ |
| Dependency CVEs | ✅ (via lookup_advisory) |
❌ | ❌ | ✅ |
| OWASP Top 10 application-level coverage | ✅ | ❌ | partial | ❌ |
Use this alongside — not instead of — PHPStan/Psalm and Dependabot. It targets the application-level logic flaws those tools cannot see.
Example Output
Console mode (truncated)
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 --format=json/sarif to stdout and for
--dry-run.
🔍 Auditing 152 file(s) — 24 controller(s), 5 voter(s), 8 form(s)
⚔ 🔴 CRITICAL sql_injection — src/Controller/UserController.php:42
⚔ 🟠 HIGH broken_access_control — src/Controller/AdminController.php:88
✓ chunk 1/12 analyzed (47s)
✓ Reviewed: 2 validated, 1 rejected
2/3 [===============> ] 67% — audit · iteration 1/3 · ⏳ querying model
Full output after the pipeline completes:
══════════════════════════════════════════════════════════════════════
🔍 SYMFONY LLM AUDIT REPORT — AUDIT-a1b2c3d4
vinceamstoutz/symfony-security-auditor
══════════════════════════════════════════════════════════════════════
Project : /var/www/my-app
Started : 2026-05-22 09:14:02
Duration: 2m 31s
Files : 142 scanned
──────────────────────────────────────────────────────────────────────
RISK LEVEL: HIGH (Score: 34)
──────────────────────────────────────────────────────────────────────
[1] VULN-7f3a1b2c CRITICAL broken_access_control
src/Controller/AdminController.php:42-58
Title: Missing #[IsGranted] on admin DELETE endpoint
OWASP: A01:2021 — Broken Access Control
Confidence: 0.95 Reviewer: ✓ validated
[2] VULN-2e9d5c1a HIGH mass_assignment
src/Controller/UserController.php:71-89
Title: Form type binds isAdmin field from untrusted request
OWASP: A04:2021 — Insecure Design
Confidence: 0.88 Reviewer: ✓ validated
... (3 more findings)
--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
Symfony LLM Security Auditor
=============================
Project: /var/www/my-app
Pipeline: Ingestion → Mapping → Audit (Attacker ⚔ Reviewer)
Estimating audit cost (dry run)...
───────────────────────────────────
* Model : claude-opus-4-8
* Tokens: 52,400 in / 4,200 out (total: 56,600)
* Cost : $0.3670 (estimate)
! [NOTE] Dry run — no LLM calls were made. This is a cost estimate only.
[OK] Dry run complete.
No LLM calls are made; exit code is always 0.
The JSON, SARIF, HTML, and Markdown formats are documented in CLI Reference and Output Formats Reference.
Supported Platforms
| Platform | Bridge package | Key env var |
|---|---|---|
| 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 |
| Azure OpenAI | symfony/ai-azure-platform |
AZURE_OPENAI_API_KEY |
| 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 |
AWS credentials |
| DeepSeek | symfony/ai-deep-seek-platform |
DEEPSEEK_API_KEY |
| Mistral | symfony/ai-mistral-platform |
MISTRAL_API_KEY |
| Meta (Llama) | symfony/ai-meta-platform |
META_API_KEY |
| Ollama (local) | symfony/ai-ollama-platform |
(none) |
Swapping providers requires only a config/packages/ai.yaml change — no PHP
edits.
Documentation
- Configuration — every config key, all platforms, split-model, model options, CLI reference
- 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. 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