vinceamstoutz/symfony-security-auditor
A Symfony security auditor that scans your app's security configuration and flags misconfigurations, weak settings, and risky access rules. Get actionable reports to harden firewalls, authentication, and authorization before deployment.
audit:run --fail-on-incomplete plus exit code 3, a fail-on-incomplete input and a complete output on the GitHub Action turn the auditor from an advisory report into a pipeline gate. This is the decision point for "do we block merges on this?" — and the answer is now "yes, with an explicit triage path for incomplete runs" rather than "no, because results are partial and we can't tell."mcp:serve in the standalone binary (parity with bundle mode) means the auditor can be exposed over the Model Context Protocol to coding agents and IDE assistants. That reframes the tool from "a CLI we run nightly" to "a capability our agents can call," which is a different roadmap line item and a different competitive set.init now handles provider selection, base URLs, endpoints, keyless Bedrock (SigV4), and bridge installation; auth:set / auth:status / auth:remove manage a stored credential with masked previews and fingerprints. This is a "reduce time-to-first-audit" investment — the decision it informs is whether we can ship this to every engineer without a platform-team ticket.billed_models, with by_model retaining the configured model), which fixes the silent over/under-billing that occurs with routers, failover platforms and aliased model ids. That makes per-team cost attribution and budget forecasting defensible — a prerequisite for charging audits back to teams or for approving spend.provider: <platform>.<instance> instance selection, plus Fireworks, Together, Venice, Eden AI, TypeSafe and Higgsfield support (symfony/ai 0.14), and Azure/Bedrock routes. The decision this de-risks: we can commit to this tool without committing to one model vendor, and we can fail over or re-price without a re-integration.%env(file:VAR)% for Docker/Kubernetes secrets, systemd LoadCredential= and 0600 files; --no-api-key for Bedrock, Ollama and others. This is the checkbox that lets the tool run in locked-down environments where shell-exported keys are prohibited..symfony-security-auditor.yaml can no longer set cache, privacy, audit.custom_skills, scan.secret_scrubbing or scan.custom_risk_patterns, cannot loosen audit.budget, cannot use %env()%, %name% or %%, and cannot be a symlink. That converts project config from an unreviewable attack surface (a PR could silently disable secret scrubbing) into something a security team can approve once. Directly supports "can we accept config from the repo we're auditing?"::… and ##[ in runner output closes a workflow-command injection path — relevant if we run audits on untrusted forks or third-party PRs.access_control rules the production app never loads are flagged LACKS_ACCESS_CHECK again, with the attacker prompt labeling YAML coverage as unverified. This is the kind of precision change that determines whether engineers trust findings or start ignoring them.SECRETKEY=, APIKEY=, PGPASSWORD=) and PASS/PW suffixes while excluding MONKEY, MAX_PW_LENGTH, BYPASS_CACHE — fewer leaked secrets in prompts and reports, fewer false redactions that corrupt report readability.Adopt when most of the following hold:
access_control, and config layering rather than a language-agnostic scanner. For Laravel-first estates, treat this as adjacent: the YAML/access_control semantics and the bundle-mode assumptions are Symfony-shaped, so validate coverage on Laravel routing and middleware before standardizing.github format plus a complete output you can branch on.mcp:serve for coding assistants, or bin/console mcp:serve in bundle mode — rather than a human-read report only.credentials.json, owner-only, %env(file:)% for orchestrator secrets). The security posture is only as good as the file permissions and secret plumbing you provide.%env()%, %name%, per-project cache/privacy/scrubbing toggles, or model options inline. Plan the move to user config before upgrading.Look elsewhere when:
3). That is honest, but it is not a substitute for a deterministically reproducible SAST/SCA tool in a regulated audit trail.init, auth:*, doctor, bridges and instance syntax are a real operational surface; someone must own upgrades, key rotation and provider drift.Audit incomplete runs — --fail-on-incomplete will either block you constantly or get disabled, and a disabled gate is worse than no gate.For executives (one paragraph). This release moves our AI-assisted security audit from an experimental script to something we can put in the release path: it can now fail a build when analysis is incomplete, it exposes itself to coding agents via MCP, engineers can self-configure a provider in minutes instead of filing a ticket, and it bills against the model that actually answered — so cost per team is measurable. The security-relevant change is that a repository can no longer silently weaken its own audit settings, which is what makes it safe to run on code we don't fully control. Net: lower onboarding cost, defensible spend, and a gate we can actually turn on. The caveat we should state up front is that results are AI-generated and not a compliance-grade substitute for deterministic scanning.
For engineering leadership. The adoption story is reduced friction: init resolves provider, model, endpoint, base URL and key variable, installs the required bridge, refuses ambiguous instance names with a clear exit 2, and stops writing paste-ready export lines into shell history. auth:set/auth:status/auth:remove give a stored credential with masked previews and a fingerprint, with exported env vars still taking precedence, and %env(file:VAR)% supports Docker/K8s secrets and systemd credentials. The main upgrade work is configuration: project .symfony-security-auditor.yaml can no longer set cache, privacy, audit.custom_skills, scan.secret_scrubbing, scan.custom_risk_patterns, loosen audit.budget, or use %env()/%name%/%%; model keys there must be plain ids. Those settings move to user config, which retains them. Budget one migration ticket per repo that uses project config, and one for anyone relying on per-project scrubbing overrides.
For security and compliance. Three arguments land. First, a repository can no longer disable secret scrubbing, swap the privacy profile, loosen the budget, or read the environment through its own config — and symlinked project configs are refused before being read. That is a reviewable trust boundary. Second, CI output is hardened against workflow-command injection (::, ##[ defused on Actions runners), which matters for fork PRs; github format and --output files are unchanged. Third, the tool is more honest about its limits: uncovered-by-production-config routes are LACKS_ACCESS_CHECK again, attacker prompts label YAML coverage as unverified rather than confirmed, and incomplete analyses are surfaced via exit 3 / a complete output instead of being silently averaged into a clean report. Position it as a high-recall reviewer that complements, not replaces, deterministic SAST and dependency scanning.
For finance / platform owners. Billing now follows the responding model, not the configured one, so auto-routing gateways, failover platforms and date-pinned aliases are no longer reconciled at the wrong rate; billed_models gives per-model attribution while by_model stays stable for existing dashboards. Practically: you can budget audits per team and per repo without a monthly reconciliation exercise, and you can move traffic to a cheaper model or gateway without renegotiating the cost model.
How can I help you explore Laravel packages today?