security-triage
Skill1.1k starsChanged 8 days agoMITView on GitHub
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 not-a-security-issue (reply to the reporter). Assigns severity and the affected maintained branches, and routes to the next step. Use when deciding whether a report or a discovered weakness needs a CVE, how it should be disclosed, or whether it is a security issue at all.
- Commits and pushes
We split this skill into the rules it gives an agent
4 rules. 0 are common, 3 are distinctive, and 1 is very specific to this project.
0
Common
Most of the 22 edited versions we read keep these.
3
Distinctive
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 40
Before classifying, pin down four things.
- Very specific: line 122
Embargo discipline: Never name a CVE-bound finding, push a cve-* branch, or open a public issue or PR for a CVE-class finding before the …
- Distinctive: line 127
If reachability or the trust model is unknown, say so and triage as needs-human-judgement.
- Distinctive: line 129
Never push to a public remote during CVE triage.
“Common” is measured: kept by at least 6 in 10 of the 22 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Symfony UX 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.
Symfony UX follows the Symfony security process (https://symfony.com/security): reports go privately to security@symfony.com, the security team works on the fix in a private Git repository, and the release publishes a GitHub Security Advisory (GHSA) with a CVE and a severity. The fix lands as a merge titled security #cve-<year>-<number> [<Package>] <title>, for example security #cve-2026-55878 [Toolkit] Harden recipe installer against path traversal. A security fix is always published as one, never disguised as a refactor or a routine bug fix: users decide whether to upgrade from that signal.
The three dispositions:
| Disposition | Branch | Process |
| CVE | cve-<year>-<number> | Private fix, GHSA + CVE with severity, reporter credit, coordinated release, merge titled security #cve-... |
| Public hardening | normal topic branch | Normal open PR, merged as bug #<number>, no embargo |
| Not a security issue | none, or a normal topic branch | Reply to the reporter; optionally a doc or robustness PR |
The symfony/ux repository has no security or severity labels: the severity lives in the GHSA.
This skill produces a recommendation. The final call belongs to the Symfony security team; treat its output as a structured argument, and defer to https://symfony.com/security for the authoritative list of what is not a vulnerability.
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, 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.
- Reachability: is the vulnerable code on a path reachable from untrusted input in a default configuration, or does it need opt-in or insecure config?
- Actor and precondition: what must the attacker already have? Unauthenticated and remote is the worst case; "already has the app secret" or "already controls the templates" usually means the precondition is itself game-over.
- Impact: RCE, arbitrary file read/write, auth/authz bypass, XSS on a default-rendered surface, CSRF on a state-changing endpoint, signature bypass that accepts forged input, secret or data disclosure, or "only" DoS / info of low value.
- Contract: is the package meant to defend this boundary, or is the unsafe behaviour documented as the app's responsibility? Boundaries ux defends: the LiveComponent props checksum and its request gate on live endpoints, TwigComponent attribute escaping, the Icons SVG sanitizer (for Iconify responses and local files alike), Autocomplete result escaping and search-query handling, the Toolkit installer's path confinement for third-party kits. Documented app responsibilities: a
writable: trueLiveProp accepts values from the client by design,options_as_html: truerenders Autocomplete results as raw HTML on purpose, and an autocompleter left with the defaultsecurity: falseis public (seesrc/Autocomplete/doc/index.rst).
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
- Requires misuse contrary to documentation, with no default-config attack (one of the documented app responsibilities from Step 0.4).
- Dev-only tooling (debug commands, profiler data) manifesting only in a dev environment.
- Precondition is already game-over (attacker already holds the app secret, writes the templates, or has local access).
- Not reproducible, or rooted in a third-party dependency outside ux's control. Content ux fetches and renders is not in that category: ux sanitizes Iconify SVG responses because it outputs them (CVE-2026-55877).
- Not a realistic bypass (a comparison nuance with no working exploit, etc.).
Pure DoS / resource exhaustion is listed by the Symfony policy among the issues not considered security issues. ux has nevertheless published CVE-2026-49209 (low) for the unbounded _batch action fan-out in LiveComponent. For a DoS on a ux endpoint, recommend hardening, cite that precedent, and leave the call to the security team.
It is a CVE only if all of these hold
- Default-reachable: exploitable against a default or documented-safe config.
- Expected actor: the attacker is at or below the trust level the boundary is meant to enforce (typically unauthenticated/remote, a lower-privileged user escalating, or the author of a third-party Toolkit kit), with no game-over precondition.
- Contracted boundary: the package is meant to defend this (see Step 0.4).
- Real impact: RCE, arbitrary file read/write, auth/authz bypass, stored/reflected XSS on a default surface, CSRF on live endpoints, signature bypass accepting forged input, or data disclosure.
- Maintained: the vulnerable code ships on
2.xor3.x.
Otherwise it is public hardening
A genuine improvement where a CVE condition fails. Shapes from ux history:
- Safer default where the unsafe one never reached production:
LiveComponentSubscriber's test mode defaulted totruein the constructor, but the bundle's compiler pass already overrode it for non-test kernels; flipping the default was abugPR (#3566). - Timing-safe comparison without a working exploit: the Autocomplete
extra_optionschecksum moved from!==tohash_equals()as abugPR (#3565). - Robustness improvements (input caps, broader sanitizer coverage).
ux has also published CVEs for fixes that close a boundary a default install already guards: CVE-2026-49210 (child component tag, rejected even though the request is gated by the live endpoint checks) and CVE-2026-49212 (checksum bound to component name and slot). When a finding has that defense-in-depth shape, present both kinds of precedent instead of deciding.
Step 2 — Severity and affected branches
Severity (the GHSA severity; CVSS is a sanity check, not the goal). ux precedent:
- high: arbitrary file write/read (CVE-2026-55878, Toolkit path traversal through a crafted kit manifest). Also unauthenticated RCE or auth bypass.
- medium: XSS on a default-rendered surface (CVE-2025-47946 TwigComponent attributes, CVE-2026-49210 LiveComponent child tag, CVE-2026-49216 Autocomplete AJAX results, CVE-2026-55877 Icons SVG).
- low: bounded impact or defense-in-depth (CVE-2026-49208 lenient date LiveProp parsing, CVE-2026-49209
_batchDoS, CVE-2026-49211 LIKE wildcards in Autocomplete, CVE-2026-49212 checksum binding, CVE-2026-49215 CSRF through the CORS-safelistedAcceptheader).
Affected branches: find the oldest version where the vulnerable code exists and intersect with the maintained branches, 2.x and 3.x (ux publishes no releases.json). Fix on the lowest maintained affected branch, then merge up with the merge-up skill: every 2026 CVE fix landed on 2.x and reached 3.x that way. Code that exists only on 3.x is fixed on 3.x. Record the oldest exposure even if it predates maintained versions; it becomes the GHSA affected range.
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-<year>-<number>. The fix is prepared privately and goes through the coordinated-disclosure process (GHSA + CVE, reporter credit, security release). Do not open a public PR or push to a public remote before the release;originis a public fork, so it counts. The fix carries asrc/<Package>/CHANGELOG.mdentry ending with(security fix), plus a BC note when the fix changes behaviour users can see (see the LiveComponent2.36entries). Wait for confirmation before any outward step, and print anygit pushcommand for the user instead of running it. - Public hardening: open a normal PR against the lowest affected branch; use
symfony-security-reviewto confirm the fix. Hardening PRs such as #3565 and #3566 carried no CHANGELOG entry; add one only when users see a behaviour change. - Not a security issue: draft a short, factual reply to the reporter explaining why (cite the contract or threat-model reason), and optionally a doc clarification or low-priority robustness PR.
In every case, the fix follows TDD and runs only the affected package's tests: cd src/<Package> && composer update && php vendor/bin/phpunit, plus pnpm run test:unit and pnpm run build in src/<Package>/assets for a JS change, since dist/ is committed. No Claude/Anthropic credit, comments sparingly, no issue references in code.
Worked examples
From ux's published advisories and merged fixes:
| Finding shape | Disposition | Deciding factor |
A third-party kit's copy-files entry with .. makes the installer write outside the project (CVE-2026-55878) | CVE, high | the author of a remote kit is untrusted; arbitrary file write |
{{ attributes }} renders attribute values unescaped (CVE-2025-47946) | CVE, medium | default rendering path, XSS |
| Iconify API or local SVG rendered without sanitization (CVE-2026-55877) | CVE, medium | ux outputs the markup, so it owns sanitizing it |
Autocomplete Stimulus controller renders AJAX text unescaped (CVE-2026-49216) | CVE, medium | stored XSS through a default option |
| Client-sent child component tag interpolated into HTML (CVE-2026-49210) | CVE, medium | XSS, published even though the live endpoint checks gate it by default |
Accept header used as the only CSRF gate on live endpoints (CVE-2026-49215) | CVE, low | Accept is CORS-safelisted, so cross-origin fetch() sets it without a preflight |
Unbounded _batch actions, one sub-request each (CVE-2026-49209) | CVE, low | DoS; ux precedent differs from the Symfony policy default |
LiveComponentSubscriber test mode defaulting to on outside the compiler pass (#3566) | Hardening | the unsafe default never reached production through the bundle's DI |
extra_options checksum compared with !== (#3565) | Hardening | timing nuance, no working exploit |
Not-a-security-issue shapes follow from the documented contracts in Step 0.4 (a writable LiveProp set by the client, options_as_html: true, an autocompleter left public). They come from the documentation, not from a ruling on record, so say so in the reply.
Gotchas
- "Boundary crossed" does not imply CVE. Impact and exposure decide it; present the ux precedents on both sides when the finding is defense-in-depth.
- DoS is where ux practice and the written policy diverge. Cite CVE-2026-49209 and let the security team decide.
- Rendered third-party content is ux's boundary. Whatever ux outputs (Iconify SVG, AJAX results rendered by a Stimulus controller) has to be made safe by ux, even though another system produced it.
- Trust-model questions are for the maintainer. Surface them (is a remote kit trusted? is a given prop meant to be client-writable?) instead of assuming the answer.
- Embargo discipline. Never name a CVE-bound finding, push a
cve-*branch, or open a public issue or PR for a CVE-class finding before the coordinated release. Wait for confirmation. - Defer to authority. https://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 the 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.
Trending
Quiet since September.about the whole repository
Who's talking about symfony/ux
- symfony/symfony“[Form] Add `MultiStepType`”GitHub · Jan 18, 2025 · 40 reactions
- twigphp/Twig“Add an `html_attr` function to make outputting HTML attributes easier”GitHub · Dec 6, 2023 · 12 reactions
- twigphp/Twig“Introduce CVA to html-extra”GitHub · Mar 9, 2024 · 6 reactions
- chartjs/Chart.js“Rollup build failing since Chart.js 3.9”GitHub · Aug 15, 2022 · 6 reactions
- contao/contao“Refactored backend controllers and backend module fragments”GitHub · Feb 14, 2021 · 6 reactions
The biggest 5 of 44 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 44
Talked about on GitHub and Stack Overflow (44 times).
On GitHub · 41
- Jan 18, 2025[Form] Add `MultiStepType` — symfony/symfony40 reactions · 24 comments
- Dec 6, 2023Add an `html_attr` function to make outputting HTML attributes easier — twigphp/Twig12 reactions · 35 comments
- Mar 9, 2024Introduce CVA to html-extra — twigphp/Twig6 reactions · 6 comments
- Aug 15, 2022Rollup build failing since Chart.js 3.9 — chartjs/Chart.js6 reactions · 2 comments
- Feb 14, 2021Refactored backend controllers and backend module fragments — contao/contao6 reactions · 2 comments
36 more on GitHub
- Jul 14, 2022Don't update package.json or controllers.json if vendor not updated — symfony/flex5 reactions · 6 comments
- Jun 4, 2025Improve `Config::getMergedConfig()` perf by ~15% — gehrisandro/tailwind-merge-phpsays it tested it3 reactions · 3 comments
- Nov 25, 2021Add `make:twig-component` maker — symfony/maker-bundle3 reactions · 6 comments
- Aug 8, 2026Switching away from `scrivo/highlight.php` in the code element — contao/contao2 reactions · 6 comments
- Jan 9, 2026[UX-Icon] Add ability to lock icon — Sylius/Sylius2 reactions · 3 comments
- Aug 18, 2024[RFC] Add PreLexerInterface — twigphp/Twig2 reactions · 3 comments
- Apr 18, 2024Twig functions becoming internal — twigphp/Twig2 reactions · 26 comments
- Sep 27, 2026Complete Twig function hash keys and values from the PHP parameter array shape — Haehnchen/idea-php-symfony2-plugin1 reaction
- Sep 17, 2026Fresh install using docker is failing with errors unable to access the database file. — SolidInvoice/SolidInvoice1 reaction
- Apr 10, 2026Update Symfony UX packages to 3.x — symfony/ux.symfony.com1 reaction
- Jan 20, 2026Add `html_attr_relaxed` escaping strategy — twigphp/Twig1 reaction · 3 comments
- Jan 16, 2026Import and migrate Toolkit recipes here — symfony/ux.symfony.com1 reaction
- Jan 12, 2026Support for ComponentName/index.html.twig anonymous templates — Haehnchen/idea-php-symfony2-plugin1 reaction · 1 comment
- Nov 22, 2025Fix declaration of twig extension as runtime — symfony/mercure-bundle1 reaction · 1 comment
- Nov 21, 2025feat: allow PHPUnit 9 — spatie/phpunit-snapshot-assertions1 reaction · 1 comment
- Oct 8, 2025[UX][Bug] Avoid considering "false" as a truthy value for "synchronize_package_json" — symfony/flex1 reaction · 6 comments
- Jul 16, 2025[Panther] Configure env `PANTHER_DEVTOOLS=0` — symfony/recipes1 reaction · 2 comments
- Jul 13, 2025[PropertyInfo] `PhpStanExtractor::getDocBlock` fallback to `getX()` PHPDoc even if property `X` exists (but has no PHPDoc) — symfony/symfony1 reaction · 2 comments
- May 7, 2025[FrameworkBundle] Ensure `Email` class exists before using it — symfony/symfony1 reaction · 2 comments
- Sep 19, 2024Auto-Set Locale from HTML-lang-attribute when used with international routing — FriendsOfSymfony/FOSJsRoutingBundle1 reaction · 1 comment
- Sep 18, 2024vite_entry_link_tags nonce attribute — lhapaipai/symfony-vite-dev1 reaction · 8 comments
- Jan 17, 2024[DomCrawler] Allow to add choices to single select — symfony/symfony1 reaction · 3 comments
- Dec 28, 2023🚧 New autocomplete — Sylius/Sylius1 reaction · 1 comment
- Nov 28, 2023Removing yarn — symfony/symfony-docs1 reaction · 3 comments
- Nov 9, 2023[AssetMapper] Only download a CSS file if it is explicitly advertised — symfony/symfony1 reaction · 2 comments
- Jan 17, 2022[WIP] Integrating UX docs more closely into Symfony docs — symfony/symfony-docs1 reaction · 6 comments
- Jan 11, 2022[HttpFoundation] : add support for text/vnd.turbo-stream.html — symfony/symfony1 reaction · 4 comments
- Feb 27, 2025How can we update the `TurboStreamListenerRenderer` configuration? — symfony/mercure-bundle0 reactions · 4 comments
- Jan 25, 2025Add contributing steps — symfony/stimulus-bridge0 reactions
- Jan 5, 2025Universal Module Definition (UMD) vs ES Modules (ESM) — Leaflet/Leaflet.Editable0 reactions · 2 comments
- Oct 11, 2024[AssetMapper] Document how to install in China (JsDelivr is not accessible reliably) — symfony/symfony0 reactions · 6 comments
- Apr 21, 2024Feature request: stimulus-helper package, a package for rendering stimulus attributes easily — ajaishankar/stimulus-reactive0 reactions · 3 comments
- May 4, 2023Upgrade Symfony UX — Demokratis-ch/demokratis-ch0 reactions
- Dec 10, 2021Symfony UX — Coderockr/backstage0 reactions
- Sep 29, 2021Handle state refresh without poll — sandoche/Symfony-ux-live-component-todo-list0 reactions
- Jun 17, 2021Use typing effect for pages' titles — Elao/elao_0 reactions
On Stack Overflow · 3
- Jul 21, 2023How to add DateTime adapter to symfony/ux-chartjs?2 votes
- Feb 22, 2023Symfony 5 - Override Form Type Options1 vote
- Jul 27, 2026Symfony UX Live Components: File Validation Only Triggers After Other Fields Pass Validation0 votes
Other versions22 projects use a version of this.
Word for word · 0
None found.
Edited · 1
- symfony/symfony★ 31k38% same
Wrote their own version · 21
- steipete/warelay★ 394ksame name
- moltbot/clawdbot★ 394ksame name
- moltbot/moltbot★ 394ksame name
- clawdbot/clawdbot★ 394ksame name
- steipete/clawdis★ 394ksame name
- openclaw/openclaw★ 394ksame name
- molt-bot/clawdbot★ 391ksame name
- rack/rack★ 5.1ksame name
- OpenBMB/EdgeClaw★ 1.2ksame name
- apache/streampipes★ 756same name
11 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
Used alongsideProjects with it also use openclaw-qa-testing and openclaw-secret-scanning-maintainer.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
AtomicBot-aiSkillopenclaw-qa-testing
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
Also in 4 projects that use this
QVerisAISkillopenclaw-secret-scanning-maintainer
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
Also in 3 projects that use this
In this repository7 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- merge-upSkill
- pr-authoringSkill
- pr-review-merge-prepSkill
- symfony-security-reviewSkill
- symfony-ux-toolkit-kitSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

