Skip to content

docs: add creating-security-bulletins skill, bulletin template, and triage control-case rule - #1820

Open
lukaszlenart wants to merge 2 commits into
mainfrom
docs/security-bulletin-skill
Open

docs: add creating-security-bulletins skill, bulletin template, and triage control-case rule#1820
lukaszlenart wants to merge 2 commits into
mainfrom
docs/security-bulletin-skill

Conversation

@lukaszlenart

@lukaszlenart lukaszlenart commented Jul 29, 2026

Copy link
Copy Markdown
Member

Documents the editorial process for S2-XXX security bulletins as a companion to the existing triaging-security-reports skill, and closes two gaps in that skill found by running it against a live report.

Triage establishes what is true; the new skill covers what the published page is allowed to say. This is as much a policy proposal as a tooling change, and the disclosure budget is the part worth PMC review.

Why

Earlier bulletins explained causes and mitigations in enough detail to build working exploits. The project moved away from that, but the rule was never written down — it lived in the heads of whoever happened to be drafting. This records it, and extends it past Problem to Backward compatibility and Workaround, which is where a carefully guarded advisory tends to leak: describing what changed about the fixed behaviour describes the defect.

What else it records

Conventions that were previously tacit, each derived from how recent bulletins are actually written:

  • Affected Software lists voted releases only — never a build that failed its test period, and never a range inferred from git tags, since tags exist for builds that were never voted through
  • Ratings match a definition on the Security Bulletins page, which is the only authority: the four-level naming postdates many older advisories, so they cannot be used to calibrate
  • Workarounds are verified in source or not published — including the claim that none exists, which is an assertion about absence and the easiest thing to get wrong
  • Behavioural claims come from the fix diff rather than its commit message, and the fix is confirmed merged before publication rather than at drafting time
  • Who is not affected is stated explicitly, because scoping shrinks the population that has to act and costs an attacker nothing they could not read off a dependency list

Changes to triaging-security-reports

The second commit adds two rules, both found by putting the existing skill against a real inbound report rather than by reasoning about it:

  • Run a supplied PoC when it is runnable. The claim table said to trace a PoC through the code but never to execute one, even where the reporter shipped a test and the command to run it. Reading and inferring is weaker evidence than executing.
  • Find the control case. A single odd behaviour is nearly always arguable as intended — a type that opts into dynamic binding can be read as the developer asking for it. What settles the question is the sibling that behaves correctly under the same input: where one dispatch path rejects an unannotated member and its neighbour does not, the control is incomplete rather than by design, and that divergence is the finding.

The second rule is the load-bearing one. Two independent triages of the same report both leaned on that argument to rule out "by design", and neither the skill nor THREAT_MODEL.md prompted for it — it was reached twice by instinct, which is precisely what a written process should make routine.

Files

  • creating-security-bulletins/SKILL.md — the method
  • creating-security-bulletins/bulletin-template.md — field reference, per-section guidance, pre-publication checklist, and a storage-format skeleton ready to POST to the Confluence API
  • triaging-security-reports/SKILL.md — the two rules above

bulletin-template.md is the source of truth for page structure. The restricted wiki template becomes a rendered copy of it, so the process is reviewable here rather than only being visible to struts-committers.

Notes for review

  • No Jira ticket — process documentation, consistent with how SECURITY.md, AGENTS.md and THREAT_MODEL.md landed
  • Draft while the wording gets a second read; the disclosure-budget section in particular is the one to argue with
  • Contains no detail about any unpublished advisory: every worked example is drawn from already-published bulletins, and the triage rules are stated without reference to the report that prompted them

🤖 Generated with Claude Code

Captures the editorial process for S2-XXX security bulletins, which has
been implicit until now, as a companion to the existing
triaging-security-reports skill. Triage establishes what is true; this
covers what the published page is allowed to say.

The load-bearing part is the disclosure budget. Earlier bulletins
explained causes and mitigations in enough detail to build working
exploits, and the project moved away from that; this writes the rule
down and extends it past Problem to Backward compatibility and
Workaround, which is where a carefully guarded advisory tends to leak.

Also records conventions that were previously tacit:

- Affected Software lists voted releases only, never a build that failed
  its test period, and never a range inferred from git tags
- ratings match a definition on the Security Bulletins page, which is the
  only authority since the four-level naming postdates older advisories
- workarounds are verified in source or not published, including the
  claim that none exists
- behavioural claims are derived from the fix diff rather than its commit
  message, and the fix is confirmed merged before publication
- who is *not* affected is stated explicitly, since scoping shrinks the
  population that has to act

bulletin-template.md is the source of truth for page structure and
carries the storage-format skeleton; the restricted wiki template becomes
a rendered copy of it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lukaszlenart
lukaszlenart marked this pull request as ready for review July 29, 2026 12:35
Two gaps surfaced by triaging a real report against the skill.

The claim table told the triager to trace a PoC through the code but
never to run it, even when the reporter supplied a runnable one. Reading
and inferring is weaker evidence than executing, and the report that
exposed this shipped a JUnit test and the exact command to run it.

More importantly, the skill never said to look for the control case. A
single odd behaviour is nearly always arguable as intended -- a type that
opts into dynamic binding can be read as the developer asking for it. What
settles the question is the sibling that behaves correctly under the same
input: when one dispatch path rejects an unannotated member and its
neighbour does not, the control is incomplete rather than by design, and
that divergence is the finding. Two independent triages of the same report
both relied on this argument, and neither the skill nor THREAT_MODEL.md
prompted for it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lukaszlenart
lukaszlenart marked this pull request as draft July 29, 2026 16:06
@lukaszlenart lukaszlenart changed the title docs: add creating-security-bulletins skill and bulletin template docs: add creating-security-bulletins skill, bulletin template, and triage control-case rule Jul 29, 2026
@sonarqubecloud

Copy link
Copy Markdown

@lukaszlenart
lukaszlenart marked this pull request as ready for review July 29, 2026 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant