Agent skill

Symfony Security Review

by symfony in symfony/symfony

Review a change (a PR, the current branch diff, or a set of files) or audit a component or the whole tree for missing or incorrect security hardening.

MITAuto-check passedSecurity

Install Symfony Security Review

skills CLI
$ npx skills add symfony/symfony --skill symfony-security-review -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install symfony/symfony symfony-security-review --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/symfony/symfony.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/symfony-security-review .claude/skills/symfony-security-review && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
symfony-security-review
GitHub stars
31k
Token cost
~2.9k tokens
SKILL.md length
1,535 words
Files
2
Skills in repo
9
Repo updated
First seen
Licence
MIT

At a glance

Review a change (a PR, the current branch diff, or a set of files) or audit a component or the whole tree for missing or incorrect security hardening.

  • Works in 6 steps: Pick mode and resolve the scope → First-principles boundary pass… → Map to families (known-class checklist) → …
  • The user says security review
  • SKILL.md covers Scope and non-goals, Progress checklist, Confirmation rule and Parallelism (large audits only), plus 9 more sections
  • Calls git, gh and php

What it does

Symfony Security Review is an agent skill from symfony/symfony. Review a change (a PR, the current branch diff, or a set of files) or audit a component or the whole tree for missing or incorrect security hardening. Reasons about trust boundaries from first principles, then checks the code against Symfony's hardening-invariant families and runs the .github/sa-tools gates. Use when the user says "security review", "security audit", "check hardening", "review this PR/branch for security", "audit <component for <vuln class", "is any hardening missing", or names a vulnerability…

Its SKILL.md is about 2.9k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `hardening-families.md`).

It sits in Security, covering Security review. It works with Symfony, GitHub and PHP. The repository describes itself as: The Symfony PHP framework. The licence is MIT.

When your agent uses it

  • The user says security review
  • Check hardening
  • Review this PR/branch for security
  • Audit <component for <vuln class

Example prompts

  • “security review”
  • “security audit”
  • “check hardening”
  • “/symfony-security-review”

Workflow steps

6 steps, taken from the step headings in SKILL.md.

  1. Pick mode and resolve the scope
  2. First-principles boundary pass (open-world)
  3. Map to families (known-class checklist)
  4. Run the automated gates
  5. Manual per-family review
  6. Report findings

What it can do on your machine

Read from SKILL.md and the folder at commit af79aa7. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • git
    • gh
    • php

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use git and gh, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Symfony Security Review loads about 2.9k tokens when it runs. Until then it costs about 140 tokens; SKILL.md has 1,535 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~140
When it runs · the whole SKILL.md, loaded when a task matches
~2.9k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from symfony/symfony at commit af79aa7, republished under its MIT licence (© symfony). 1,535 words, ~2,932 tokens.

Download SKILL.mdSave it as .claude/skills/symfony-security-review/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
symfony-security-review
description
Review a change (a PR, the current branch diff, or a set of files) or audit a component or the whole tree for missing or incorrect security hardening. Reasons about trust boundaries from first principles, then checks the code against Symfony's hardening-invariant families and runs the .github/sa-tools gates. Use when the user says "security review", "security audit", "check hardening", "review this PR/branch for security", "audit <component> for <vuln class>", "is any hardening missing", or names a vulnerability class to hunt for.

Symfony Security Review

Finds hardening that is missing or wrong, grounded in code. It runs in two modes:

  • Review a change (default): a PR, the current branch vs its base, or named files.
  • Audit a target: a component path or the whole src/ tree, for one or all families.

Both modes run two passes: first reason about the change's trust boundaries from first principles (to catch novel issues), then check it against the hardening-invariant families catalogued in hardening-families.md. The catalogue is a checklist of known classes, not the search space.

Scope and non-goals

  • This skill spots missing hardening. It does not triage an incoming report end to end, assign a CVE, or merge a fix. Those are separate workflows.
  • Every finding must point at a real sink (a concrete file and line). No speculative findings. A family with no sink in scope is not in scope; but a sink that matches no family is still in scope (that is what Step 1 is for).
  • Respect the decision boundaries in the catalog: several plausible-looking shapes were ruled "not a security issue". Do not raise those.

Progress checklist

  • Step 0: Pick mode and resolve the scope
  • Step 1: First-principles boundary pass (open-world)
  • Step 2: Map to families (known-class checklist)
  • Step 3: Run the automated gates
  • Step 4: Manual per-family review
  • Step 5: Report findings

Confirmation rule

Whenever this skill says "Wait for confirmation", treat anything other than an explicit affirmative as no: stop and ask the user how they want to proceed.

Parallelism (large audits only)

When auditing the whole src/ tree or a large multi-file component, fan Step 1 and Step 4 out to subagents: one per family, or one per file-batch, each returning findings that point at a concrete file and line (no speculative findings leaking in through parallelism). Keep the rest in the main loop: aggregation, de-duplication, the completeness check, and the report are synthesis and must see every finding at once. For a single PR or a small diff, run every step inline; subagents are pure overhead there.


Step 0 — Pick mode and resolve the scope

Review a change. Resolve the diff and the changed non-test files:

bash
# A public PR
gh pr diff <n> --repo symfony/symfony
# The current branch against its base (e.g. 6.4)
git diff <base>...HEAD --stat

Audit a target. Take a component path (e.g. src/Symfony/Component/Mailer) or the whole src/ tree. There is no diff; the "changed files" are the target files.

In both modes, build the file list and drop tests (*/Tests/*). Hardening lives in the implementation; tests are checked separately in Step 3.

State the resolved mode and scope back to the user in one line before continuing.

Step 1 — First-principles boundary pass (open-world)

This pass finds what the catalogue does not list. Do it before mapping to families, and do not let the anchors narrow it. For each file in scope, reason as an attacker, independent of any known family:

  1. Inputs: what untrusted data can reach this code? Request (query/body/headers/cookies), uploaded files, environment, a broker/message payload, a stored blob later deserialized, a webhook, a third-party API response, a database value that was originally user-set.
  2. Flow: follow each input to where it is used. Does it reach a sink (filesystem, process, SQL, deserialization, object construction, HTML output, a redirect, an XML/URL parser, a comparison of a secret)?
  3. Boundary: which trust boundary does it cross, and who is the expected actor (unauthenticated, lower-privileged, a malicious broker)?
  4. Worst case: if the attacker fully controls the input, what is the maximum impact? State it concretely (RCE, auth bypass, SSRF, file read/write, XSS, info leak).

Record every input-to-sink path with a non-trivial worst case as a candidate finding, whether or not it matches a catalogued family. An unguarded path from untrusted input to a dangerous sink is a finding even if no anchor names it. This step uses no greps by design; it is meant to see sinks the dictionary misses.

Step 2 — Map to families (known-class checklist)

Now apply the catalogue as a checklist, to confirm no known class slipped past Step 1. Treat each anchor's listed APIs as seed examples of an abstract role (an inbound authenticator, a secret comparison, a deserialization entry, an XML/URL sink, a file or process sink); extend to anything in scope that plays that role, including classes the grep does not name.

For each file in scope, decide which families it touches using the grep anchors in hardening-families.md. Run the anchors against the scope, not the whole tree, when reviewing a change:

bash
# Example: which families does this branch touch?
git diff <base>...HEAD --name-only | grep -v /Tests/ > /tmp/scope.txt
grep -lf <(printf 'extends AbstractRequestParser\nfunction __unserialize\nhash_hmac(\nvalidateOnParse\nloadXML(\nescapeshellarg(\npreg_match') $(cat /tmp/scope.txt) 2>/dev/null

Carry forward both Step 1's boundary findings and the families with a sink in scope; they proceed to Step 4. List them.

Step 3 — Run the automated gates

These encode the already-shipped invariants. Run them first; anything they catch needs no manual argument.

Hardening-test convention (tokenizer only, always runs locally):

bash
php .github/sa-tools/check-hardening-tests.php

Fails if a concrete AbstractRequestParser lacks a RejectWebhookException test, or a class with __unserialize() and a string property lacks a __toString gadget test. Accepted gaps live in its ALLOWLIST const.

Custom PHPStan rules (HardenedComparisonRule, UnserializeToStringTrampolineRule, UnserializeMissingAllowedClassesRule). In CI these run base-vs-PR through phpstan-diff.php, which only fails on errors new to the PR. To reproduce locally you need PHPStan installed (it is not in composer.json; CI installs it ad hoc). The source of truth for a rule's logic is a RuleTestCase, not an ad-hoc phpstan analyse run:

bash
# Only meaningful if phpstan is installed in the project
./vendor/bin/phpstan analyse --error-format=json --no-progress \
  --autoload-file=.github/sa-tools/rules/bootstrap.php

Do not trust raw phpstan analyse counts for these rules: the result cache plus parallel workers make them nondeterministic (a rule can report 0 then N for the same input). See the gotchas.

Show full SKILL.md (633 more words)Show less

Step 4 — Manual per-family review

For each in-scope family, apply its invariant from hardening-families.md. The catalog gives, per family: the grep anchor, the invariant, the automated coverage (if any), and the decision boundary.

Work the sinks, not the families in the abstract: for every sink site the anchor found, answer the family's check question. If the answer is "no guard / wrong guard", it is a candidate finding; confirm it is not excluded by the decision boundary before reporting.

Step 5 — Report findings

Output a table, highest severity first:

LocationFamilySeverityInvariant at riskSuggested hardeningHardening test
Component/.../Foo.php:NNwebhook-verifyHighsignature compared with !==hash_equals()extend parser reject test

Severity rubric (match the corpus, not CVSS theatre):

  • Critical: pre-auth RCE or full auth bypass (e.g. verify-after-deserialize, gadget chain).
  • High: conditional RCE, SSRF, signature/secret bypass, XXE with file read.
  • Medium: stored/reflected XSS, open redirect, sensitive info leak.
  • Low: DoS / resource exhaustion / defense-in-depth only.
  • Not a finding: excluded by a decision boundary (say which one).

When a finding moves on to security-triage, Critical and High both map to its high label; Medium and Low map to medium and low.

For each real finding, state whether a hardening regression test is required so check-hardening-tests.php (or a component test) keeps it from being dropped later.

Completeness check (before you finalise). State explicitly: is there an untrusted input, a sink, a deserialization, an authentication, or a trust boundary in scope that matched no anchor and was not already raised in Step 1? If so, reason about it from scratch before reporting. A clean family sweep is not a clean review.

The table holds findings from both passes: the Step 1 boundary pass (Family column = the vulnerability class, or novel) and the Step 4 family review.

Separate confirmed findings from needs-human-judgement ones. Do not inflate.


If a finding is real: fix handoff

This follows the house conventions:

  • TDD: write the failing hardening test first, then the fix.
  • Component-scoped tests only: ./phpunit src/Symfony/Component/<Name> (never the whole suite).
  • Add the regression test at the boundary so the convention gate covers it; for a durable implementation-shape check, see the hardening-rule skill.
  • No em-dashes, no Co-Authored-By, no Claude/Anthropic credit. Comments sparingly, and do not reference issue numbers in code or tests.

Gotchas

  • Decision boundaries are real. An empty $secret that disables webhook verification is documented behaviour, not a bug. A literal allowed_classes on a first-party cache file was ruled not-a-security-issue. Pure DoS / memory exhaustion is generally outside the CVE pipeline (treat as Low). The catalog lists these; respect them or you will cry wolf.
  • Only string-typed properties trampoline. In __unserialize(), int/float/bool coercion throws TypeError without calling __toString. Do not flag non-string slots.
  • PHPStan custom-rule counts are nondeterministic (result cache + parallel workers). Verify rule behaviour with RuleTestCase, and rely on the CI base-vs-PR diff (phpstan-diff.php), not local counts.
  • The diff-lint only flags what a PR adds. Standing violations on the tree are filtered out by design, so a clean local audit does not mean the tree is clean; it means the PR introduced nothing new.
  • Data families are answer-keys. SSRF subnet lists and the HtmlSanitizer URL attribute set drift with specs; a static check only confirms a human-curated set, it cannot find the next missing entry. Flag these for a completeness test, not a gate.
  • Anchors are seed examples, not the search space. Novel issues surface in the Step 1 first-principles pass, not the greps. A finding that matches no family is still a finding; do not let the dictionary bound the review.

Error handling

  • Never fabricate a sink. If the anchor finds nothing, say the family is out of scope.
  • Security reports are handled privately. Do not echo report contents into public artifacts.
  • When unsure whether something crosses a decision boundary, report it as needs-human-judgement with the boundary named, and wait for confirmation.

© symfony, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file in .agents/skills/symfony-security-review of symfony/symfony.

  • SKILL.md
  • hardening-families.md

Open the folder on GitHubat commit af79aa7

Compare with similar skills

Symfony Security Review next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Symfony Security Review compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Symfony Security Review this skillsymfony/symfony31k—~2.9kAutomated safety check: PassMIT
Code Audit3stoneBrother/code-audit8921 repos~2.7kAutomated safety check: PassNone
Kedro Security Reviewkedro-org/kedro11k—~3.3kAutomated safety check: PassCustom licence
Pyspector Security AuditParzivalHack/PySpector151—~3.5kAutomated safety check: NotesApache-2.0
Security Advisory Rewriterobot-platform/obot1.1k—~1.3kAutomated safety check: PassMIT
Slowmist Agent Securityslowmist/slowmist-agent-security508—~1.4kAutomated safety check: PassMIT

Similar skills

  • Code Audit

    3stoneBrother/code-audit

    Professional code security audit skill covering 55+ vulnerability types.

    892 GitHub starsUsed in 1 repo~2.7k tokens
    SecurityAuto-check passed
  • Kedro Security Review

    kedro-org/kedro

    Run a Kedro security scan on the full codebase or just a pull request.

    11k GitHub stars~3.3k tokensUpdated 2 days ago
    SecurityAuto-check passed
  • Pyspector Security Audit

    ParzivalHack/PySpector

    Run a full Python codebase security audit using PySpector (https://github.com/ParzivalHack/PySpector), a Rust-core SAST scanner.

    151 GitHub stars~3.5k tokensUpdated yesterday
    SecurityAuto-check: notes
  • Security Advisory Rewriter

    obot-platform/obot

    Turns a verbose, reporter-submitted obot security advisory into a short, deployer-facing writeup covering impact, affected versions and mitigation.

    1.1k GitHub stars~1.3k tokensUpdated today
    SecurityAuto-check passed
  • Slowmist Agent Security

    slowmist/slowmist-agent-security

    Comprehensive security review framework for AI agents. An agent skill from slowmist/slowmist-agent-security.

    508 GitHub stars~1.4k tokensUpdated 5 mo ago
    SecurityAuto-check passed
  • Skeptic

    RaoFoundation/subtensor

    Run the security-focused Skeptic persona on the local working tree's diff against a base branch.

    391 GitHub stars~660 tokensUpdated yesterday
    SecurityAuto-check passed

More from symfony/symfony

All 9 skills in this repo
  • Sync Translations

    symfony/symfony

    Synchronize translation catalogs across maintained Symfony branches: find messages that newer branches added to the English catalogs but that are still missing from the oldest maintained branch…

    31k GitHub stars~1.9k tokensUpdated today
    Auto-check passed
  • Bug Triage

    symfony/symfony

    Decide whether open Bug PRs target the correct branch. An agent skill from symfony/symfony.

    31k GitHub stars~1.9k tokensUpdated today
    Auto-check passed
  • Merge Up

    symfony/symfony

    Cascade-merge maintained Symfony branches from oldest to newest (e.g.

    31k GitHub stars~4k tokensUpdated today
    Auto-check passed
  • PR Merge

    symfony/symfony

    Merge a reviewed pull request the way the Symfony core team does: one --no-ff merge commit per PR, whose message archives the whole discussion, with the review gates checked first.

    31k GitHub stars~3.1k tokensUpdated today
    Auto-check passed
  • Security Triage

    symfony/symfony

    Triage a reported security finding into a disposition: a private CVE (coordinated disclosure + advisory), a public hardening PR (fix in the open, no CVE), or not-a-security-issue (reply to reporter).

    31k GitHub stars~2.6k tokensUpdated today
    Auto-check passed
  • Hardening Rule

    symfony/symfony

    Decide whether a recurring hardening invariant is worth a CI gate, and add it without hitting the traps.

    31k GitHub stars~1.2k tokensUpdated today
    Auto-check passed

Categories

Questions about Symfony Security Review

What does Symfony Security Review do?

Review a change (a PR, the current branch diff, or a set of files) or audit a component or the whole tree for missing or incorrect security hardening. Symfony Security Review is an agent skill from symfony/symfony. Review a change (a PR, the current branch diff, or a set of files) or audit a component or the whole tree for missing or incorrect security hardening.

When should I use Symfony Security Review?

Symfony Security Review fits situations like: the user says security review; check hardening; review this PR/branch for security; audit <component for <vuln class.

How do I install Symfony Security Review in Claude Code?

Run `npx skills add symfony/symfony --skill symfony-security-review -a claude-code`. Or copy the skill folder (.agents/skills/symfony-security-review in symfony/symfony) into .claude/skills/symfony-security-review in your project. Claude Code loads it when a task matches its description.

How do I install Symfony Security Review in Codex?

Run `npx skills add symfony/symfony --skill symfony-security-review -a codex`. Or copy the skill folder (.agents/skills/symfony-security-review in symfony/symfony) into .agents/skills/symfony-security-review in your project. Codex loads it when a task matches its description.

Can I use Symfony Security Review in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add symfony/symfony --skill symfony-security-review -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/symfony-security-review, .gemini/skills/symfony-security-review, .github/skills/symfony-security-review and .opencode/skills/symfony-security-review in your project.

What does Symfony Security Review need to run?

Going by SKILL.md and its folder, Symfony Security Review needs the command-line tools its instructions call (git, gh and php).

Does Symfony Security Review access the network?

SKILL.md contains no URLs. Its commands use git and gh, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Symfony Security Review safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Symfony Security Review use?

Symfony Security Review is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Symfony Security Review use?

About 2.9k tokens (SKILL.md is roughly 12k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Symfony Security Review?

Skills that share tags, products or a category with Symfony Security Review: Code Audit (3stoneBrother/code-audit, 892 stars), Kedro Security Review (kedro-org/kedro, 11k stars), Pyspector Security Audit (ParzivalHack/PySpector, 151 stars) and Security Advisory Rewriter (obot-platform/obot, 1.1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Symfony Security Review?

symfony (a GitHub organization) maintains it in symfony/symfony, which has 31,184 GitHub stars. The repository holds 9 skills in this directory. The repository was last updated on October 10, 2026.

Source: symfony/symfony on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.