Agent skill

Security Triage

by symfony in 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).

MITAuto-check passedSecurity

Install Security Triage

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

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

GitHub CLI
$ gh skill install symfony/symfony security-triage --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/security-triage .claude/skills/security-triage && 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
security-triage
GitHub stars
31k
Token cost
~2.6k tokens
SKILL.md length
1,344 words
Files
1
Skills in repo
9
Repo updated
First seen
Licence
MIT

At a glance

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).

  • Works in 4 steps: Establish the facts → Disposition decision tree → Severity and affected branches → …
  • The user says does this need a CVE
  • SKILL.md covers Progress checklist, Confirmation rule, Step 0 — Establish the facts and Step 1 — Disposition decision…, plus 5 more sections
  • Reaches symfony.com

What it does

Security Triage is an agent skill from 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). Assigns severity and affected maintained branches, and routes to the next step. Use when the user says "does this need a CVE", "CVE or hardening", "triage this report", "is this a security issue", "classify this finding", or "how should we disclose this".

Its SKILL.md is about 2.6k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

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

When your agent uses it

  • The user says does this need a CVE
  • Triage this report
  • Is this a security issue
  • Classify this finding

Example prompts

  • “does this need a CVE”
  • “CVE or hardening”
  • “triage this report”
  • “/security-triage”

Workflow steps

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

  1. Establish the facts
  2. Disposition decision tree
  3. Severity and affected branches
  4. Route

What it can do on your machine

Read from SKILL.md and the folder at commit 31ed3bf. 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

    No scripts in the folder and no shell commands in SKILL.md.

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

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • symfony.com

    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

Security Triage loads about 2.6k tokens when it runs. Until then it costs about 118 tokens; SKILL.md has 1,344 words of instructions outside code blocks.

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

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 31ed3bf, republished under its MIT licence (© symfony). 1,344 words, ~2,646 tokens.

Download SKILL.mdSave it as .claude/skills/security-triage/SKILL.md (or your agent's skills folder).
name
security-triage
description
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). Assigns severity and affected maintained branches, and routes to the next step. Use when the user says "does this need a CVE", "CVE or hardening", "triage this report", "is this a security issue", "classify this finding", or "how should we disclose this".

Symfony Security Triage

Decides how a finding is handled, not whether the code is wrong. It complements symfony-security-review (which finds missing hardening) by making the disclosure call on a report.

The three dispositions and the conventions that record them:

DispositionLabelBranch prefixProcess
CVEHas CVE + severitycve-*Private fix, GHSA/CVE, credit, blog post, coordinated release
Public hardeningnone / Not a security issueharden-*, hardening-*, pin-*, fix-*Normal open PR, changelog, no embargo
Not a security issueNot a security issue / Won't fixn/a or fix-*Reply to reporter; optionally a doc/robustness PR

This skill produces a recommendation. The final call belongs to the Symfony security team; treat its output as a structured argument, and defer to symfony.com/security for the authoritative "what is not a vulnerability" list.

Progress checklist

  • Step 0: Establish the facts (reproduce, scope, trust model)
  • Step 1: Apply the disposition decision tree
  • Step 2: Assign severity and affected maintained branches
  • Step 3: Route (branch prefix, labels, next workflow, reporter reply)

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.


Step 0 — Establish the facts

Before classifying, pin down four things. Guessing any of them produces a wrong call.

  1. Reachability: is the vulnerable code on a path reachable from untrusted input in a default configuration, or does it need opt-in/insecure config?
  2. Actor and precondition: what must the attacker already have? Unauthenticated and remote is the worst case; "already controls the serialized bytes" or "already has the app secret" usually means the precondition is itself game-over.
  3. Impact: RCE, auth/authz bypass, SSRF to internal, signature/secret bypass that accepts forged input, XSS on a default-rendered surface, secret disclosure, open redirect, session fixation, or "only" DoS / info of low value.
  4. Contract: is the component meant to defend this boundary (router, HttpFoundation/HttpClient, Security, webhook verification, HtmlSanitizer, Mime parsing), or is the unsafe behaviour documented as the caller's responsibility (deserializing untrusted bytes, a trusted-channel feature such as ESI, template_from_string)?

Reproduce if at all possible; an unreproducible report is not yet triable.

Step 1 — Disposition decision tree

Apply in order. The first matching bucket wins.

It is not a security issue if any of these hold
  • Pure DoS / resource exhaustion. Generally excluded from the CVE pipeline. Fix as hardening with a limit if cheap, but no CVE.
  • Requires misuse contrary to documentation, with no default-config attack. The component is not contracted to defend this (e.g. deserializing untrusted bytes through an API documented as trusted-only; using a trusted-channel feature to reach internal hosts).
  • Dev-only tooling (profiler, debug, web-profiler) manifesting only in a dev environment.
  • Precondition is already game-over (attacker already holds the app secret, controls the deserialized input contract, or has local/physical access).
  • Not reproducible, or rooted in a third-party dependency outside Symfony's control.
  • Not a realistic bypass (a comparison nuance with no working exploit, etc.).
It is a CVE only if all of these hold
  1. Default-reachable: exploitable against a default or documented-safe config.
  2. Expected actor: the attacker is at or below the trust level the boundary is meant to enforce (typically unauthenticated/remote, or a lower-privileged user escalating), with no game-over precondition.
  3. Contracted boundary: the component is meant to defend this (see Step 0.4).
  4. Real impact: RCE, auth/authz bypass, SSRF to internal, sanitizer/signature bypass accepting forged input on a sensitive sink, stored/reflected XSS on a default surface, secret disclosure, or open redirect with meaningful reach.
  5. Maintained: the vulnerable code ships in a maintained version.
Otherwise it is public hardening

A genuine improvement where a CVE condition fails. Typical shapes:

  • Defense-in-depth on top of an existing control, or that only matters once another bug already holds (an __unserialize __toString trampoline guard needs a pre-existing untrusted unserialize() entry to matter).
  • Safer-default change where the old default was not a vulnerability under the threat model (adding a webhook IP allowlist, pinning the HMAC algorithm).
  • Limited impact or exposure even though a boundary is technically crossed (a forged webhook against an opt-in endpoint with a user-configured secret injects only a delivery-status event).
  • Robustness improvements (input-length caps, broader sanitizer coverage).

Step 2 — Severity and affected branches

Severity (match the low/medium/high labels; CVSS is a sanity check, not the goal):

  • high: unauthenticated RCE, auth bypass, full sanitizer bypass enabling stored XSS, SSRF reaching internal services.
  • medium: reflected XSS, open redirect, signature bypass with bounded impact, info disclosure of non-trivial data.
  • low: defense-in-depth, narrow-config or low-impact issues, most hardening.

Affected branches: find the oldest version where the vulnerable code exists, intersect with maintained_versions from https://symfony.com/releases.json. Fix on the lowest maintained affected branch, then merge up (see the merge-up skill). Record the oldest exposure even if it predates maintained versions.

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

Step 3 — Route

State the recommendation as: disposition + severity + affected maintained branches + the one-line rationale (which decision-tree conditions decided it), then route:

  • CVE: name the branch cve-<slug>-<branch>; apply Has CVE + severity; the fix is prepared privately and goes through the coordinated-disclosure process (request a GHSA/CVE, credit the reporter, prepare the security release and blog post). Do not open a public PR or push to a public remote before release. Wait for confirmation before any outward step.
  • Public hardening: name the branch harden-/hardening-/pin-/fix-<slug>; open a normal PR with a CHANGELOG entry; use symfony-security-review to confirm the fix and hardening-rule to add a durable gate where the class recurs.
  • Not a security issue: draft a short, factual reply to the reporter explaining why (cite the contract/threat-model reason), and optionally a doc clarification or low-priority robustness PR. Apply Not a security issue / Won't fix.

In every case, the fix follows TDD, component-scoped tests, no em-dashes, no Claude/Anthropic credit, comments sparingly, no issue references in code.


Worked examples (abstracted patterns)

Finding shapeDispositionDeciding factor
SSRF filter (private-network client) bypassed in a default configurationCVEdefault control bypassed, unauthenticated reach
HTML sanitizer lets a javascript: URL through on a default profileCVEsanitizer's core contract bypassed, stored XSS
URL generator emits a path that crosses a routing boundary by defaultCVEboundary crossed in default use
A signed transport decodes the payload before verifying its MACCVE candidate, highpre-auth RCE if signing is meant to defend a malicious broker; confirm the trust model
Webhook signature compared with !==, or the secret is ignoredHardeningopt-in endpoint, user-configured secret, bounded impact
__unserialize assigns a string property without a \Stringable guardHardeningneeds a pre-existing untrusted unserialize() entry (game-over precondition)
Input-length cap / broader sanitizer coverage addedHardeningrobustness, not a default-exploitable bypass
Unbounded recursion / regex backtracking / cache growth on inputHardening, lowpure DoS, excluded from the CVE pipeline
Deserializing bytes through an API documented as trusted-onlyNot a security issuedocumented contract, caller's responsibility
A trusted-channel feature (e.g. ESI/SSI) used to reach internal hostsNot a security issuetrusted by design
Case-insensitive host allowlist with no working bypassNot a security issuenot a realistic bypass

Gotchas

  • "Boundary crossed" does not imply CVE. Impact and exposure decide it. A forged webhook against an opt-in, user-secret endpoint is hardening; an SSRF filter bypass in default use is a CVE.
  • DoS is the most common miscategorisation. Resource exhaustion is hardening/low, not a CVE, even when trivially triggerable.
  • Defense-in-depth tells. If exploiting the finding requires another, already-present vulnerability or a leaked secret, it is hardening.
  • Trust-model questions are for the maintainer. A signed-transport verify-order case turns on whether the broker is trusted; surface the question, do not assume.
  • Embargo discipline. Never name a CVE-bound finding, push a cve-* branch, or open a public PR for a CVE-class finding before the coordinated release. Wait for confirmation.
  • Defer to authority. symfony.com/security is the source of truth for what is not a vulnerability; this skill encodes observed practice, not policy.

Error handling

  • If reachability or trust model is unknown, say so and triage as needs-human-judgement; do not force a disposition.
  • Security reports are handled privately. Do not echo report contents into public artifacts, commit messages, or branch names that leak the vulnerability before release.
  • Never push to a public remote during CVE triage. Stop and hand back to the user.

© 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

Just SKILL.md in .agents/skills/security-triage of symfony/symfony.

Open the folder on GitHubat commit 31ed3bf

Compare with similar skills

Security Triage 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.

Security Triage compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Security Triage this skillsymfony/symfony31k—~2.6kAutomated safety check: PassMIT
Code Audit3stoneBrother/code-audit8921 repos~2.7kAutomated safety check: PassNone
Security Reviewgithub/awesome-copilot40k1 repos~2.3kAutomated safety check: NotesMIT
Php Symfony Audit0xShe/PHP-Code-Audit-Skill4021 repos~599Automated safety check: PassNone
Phy Regex AuditLeoYeAI/openclaw-master-skills2.2k—~5.1kAutomated safety check: PassApache-2.0
Security Triagesymfony/ux1.1k—~3.2kAutomated 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
  • Security Review

    github/awesome-copilot

    Official

    AI-powered codebase security scanner that reasons about code like a security researcher — tracing data flows, understanding component interactions, and catching vulnerabilities that pattern-matching…

    40k GitHub starsUsed in 1 repo~2.3k tokens
    SecurityAuto-check: notes
  • Php Symfony Audit

    0xShe/PHP-Code-Audit-Skill

    Symfony 框架特效安全审计工具。针对 Symfony 常见 security.yaml、CSRF、Twig/Twig raw、表达式与访问控制等框架机制做白盒静态审计,并将风险映射到通用漏洞类型体系(AUTH/CSRF/CFG/XSS/TPL/LOGIC 等)。

    402 GitHub starsUsed in 1 repo~599 tokens
    SecurityAuto-check passed
  • Phy Regex Audit

    LeoYeAI/openclaw-master-skills

    Static ReDoS (Regular Expression Denial of Service) vulnerability scanner and regex quality auditor for codebases.

    2.2k GitHub stars~5.1k tokensUpdated 2 mo ago
    SecurityAuto-check passed
  • Security Triage

    symfony/ux

    Triage a security finding in a Symfony UX package into a disposition: a private CVE (coordinated disclosure through the Symfony security process), a public hardening PR (fix in the open, no CVE), or…

    1.1k GitHub stars~3.2k tokensUpdated today
    SecurityAuto-check passed
  • Php Framework Audit

    wgpsec/AboutSecurity

    PHP 框架特定安全审计。当在 PHP 白盒审计中已识别目标使用特定框架、 需要检查框架特有安全机制和常见配置缺陷时触发。

    1.8k GitHub stars~767 tokensUpdated today
    Backend & APIsAuto-check: notes

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
  • 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.

    31k GitHub stars~2.9k 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

Works with

Categories

Questions about Security Triage

What does Security Triage do?

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). Security Triage is an agent skill from 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).

When should I use Security Triage?

Security Triage fits situations like: the user says does this need a CVE; triage this report; is this a security issue; classify this finding.

How do I install Security Triage in Claude Code?

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

How do I install Security Triage in Codex?

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

Can I use Security Triage 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 security-triage -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/security-triage, .gemini/skills/security-triage, .github/skills/security-triage and .opencode/skills/security-triage in your project.

What does Security Triage need to run?

SKILL.md names no scripts, command-line tools or credentials: Security Triage is instructions for the agent only.

Does Security Triage access the network?

SKILL.md names 1 domain. In commands or code: symfony.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.

Is Security Triage 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 Security Triage use?

Security Triage 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 Security Triage use?

About 2.6k tokens (SKILL.md is roughly 11k 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 Security Triage?

Skills that share tags, products or a category with Security Triage: Code Audit (3stoneBrother/code-audit, 892 stars), Security Review (github/awesome-copilot, 40k stars), Php Symfony Audit (0xShe/PHP-Code-Audit-Skill, 402 stars) and Phy Regex Audit (LeoYeAI/openclaw-master-skills, 2.2k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Security Triage?

symfony (a GitHub organization) maintains it in symfony/symfony, which has 31,182 GitHub stars. The repository holds 9 skills in this directory. The repository was last updated on October 9, 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.