This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow-steward.git
The following commit(s) were added to refs/heads/main by this push:
new 080212a refactor(security-triage): rename NOT-CVE-WORTHY disposition
to INVALID (#165)
080212a is described below
commit 080212a6f11232121ab1b4d62e3e4fd5b2053db7
Author: Jarek Potiuk <[email protected]>
AuthorDate: Fri May 15 14:19:05 2026 +0200
refactor(security-triage): rename NOT-CVE-WORTHY disposition to INVALID
(#165)
Aligns the triage-class name with its sibling skill name
(`/security-issue-invalidate`) and the applied tracker label
(`invalid`), and pairs cleanly with VALID. Bulk-rename across the
two skills + AGENTS.md + docs/security/. No semantic change —
canned-response precedents, retriage criteria, decision tables,
jq filters in invalidate's bulk-mode selector all get the new
name with identical meaning.
Triggered by raboof's question on Slack — current name doesn't
distinguish well from DEFENSE-IN-DEPTH / INFO-ONLY (which also
don't get a CVE); INVALID captures the specific shape (report is
misframed / circular / by-design / out-of-scope).
Generated-by: Claude Code (Claude Opus 4.7)
---
.claude/skills/security-issue-invalidate/SKILL.md | 10 ++---
.claude/skills/security-issue-triage/SKILL.md | 50 +++++++++++------------
AGENTS.md | 2 +-
docs/security/README.md | 2 +-
docs/security/process.md | 2 +-
5 files changed, 33 insertions(+), 33 deletions(-)
diff --git a/.claude/skills/security-issue-invalidate/SKILL.md
b/.claude/skills/security-issue-invalidate/SKILL.md
index 28ff45b..d9dcdc5 100644
--- a/.claude/skills/security-issue-invalidate/SKILL.md
+++ b/.claude/skills/security-issue-invalidate/SKILL.md
@@ -212,7 +212,7 @@ privacy-llm pre-flight failure is also a hard stop.
|---|---|
| `invalidate <N>` / `invalidate #N` | single tracker; the existing
single-issue flow |
| `invalidate #N1, #N2, …` / `invalidate #N1-#N5` | explicit list; bulk-mode
flow |
-| `invalidate proposed` | every open tracker that satisfies **both**: (a) has
a triage proposal posted by
[`security-issue-triage`](../security-issue-triage/SKILL.md) carrying
**Proposed disposition: NOT-CVE-WORTHY**, and (b) has a team-consensus marker —
a thumbs-up reaction on the triage proposal from a roster member who is **not**
the proposal author, OR a follow-up comment from a roster member containing a
positive-acknowledgement keyword (`agree`, `concur`, `+1`, `confirmed`, `LGTM`)
|
+| `invalidate proposed` | every open tracker that satisfies **both**: (a) has
a triage proposal posted by
[`security-issue-triage`](../security-issue-triage/SKILL.md) carrying
**Proposed disposition: INVALID**, and (b) has a team-consensus marker — a
thumbs-up reaction on the triage proposal from a roster member who is **not**
the proposal author, OR a follow-up comment from a roster member containing a
positive-acknowledgement keyword (`agree`, `concur`, `+1`, `confirmed`, `LGTM`)
|
Bulk-mode aggregates the per-tracker close-comment, reporter-
draft, label / close-issue / board-archive actions into one
@@ -222,11 +222,11 @@ fully applied — labels + comment + close + board archive
+ draft
— before the next starts).
`invalidate proposed` is a convenience for the
-"please proceed the agreed NOT-CVE-WORTHY ones in bulk"
+"please proceed the agreed INVALID ones in bulk"
pattern. The team-consensus detection is *necessary but not
sufficient* — the user is still presented with the full list
in the proposal and can override per-item before confirming.
-A NOT-CVE-WORTHY triage proposal that hasn't yet received a
+A INVALID triage proposal that hasn't yet received a
second-roster-member ack is **excluded** from the resolved set
with an explicit *"awaiting consensus on #NNN — skipped"* note
in the recap.
@@ -242,11 +242,11 @@ in Gmail.
**Resolution recipe for `invalidate proposed`:**
```bash
-# Find open trackers with a NOT-CVE-WORTHY triage proposal
+# Find open trackers with a INVALID triage proposal
gh issue list --repo <tracker> --state open --label "needs triage" \
--json number,title,comments \
--jq '.[] | select(.comments | map(.body) | any(
- startswith("**Triage proposal**") and contains("NOT-CVE-WORTHY")
+ startswith("**Triage proposal**") and contains("INVALID")
)) | .number'
```
diff --git a/.claude/skills/security-issue-triage/SKILL.md
b/.claude/skills/security-issue-triage/SKILL.md
index c8f23f6..a946df6 100644
--- a/.claude/skills/security-issue-triage/SKILL.md
+++ b/.claude/skills/security-issue-triage/SKILL.md
@@ -5,7 +5,7 @@ description: |
For each open `<tracker>` issue carrying the `needs triage`
label, read body + comments and classify the candidate
disposition into one of five classes: VALID / DEFENSE-IN-DEPTH
- / INFO-ONLY / NOT-CVE-WORTHY / PROBABLE-DUP. On user confirmation,
+ / INFO-ONLY / INVALID / PROBABLE-DUP. On user confirmation,
posts a triage-proposal comment that invites the security team
to react. Read-only on tracker state — no label flips, closes,
or CVE allocations. Supports `--retriage` for re-litigating
@@ -20,7 +20,7 @@ when_to_use: |
needs re-litigating after new comment activity. Skip when
team consensus on validity has already landed — invoke
`/security-cve-allocate` (VALID),
- `/security-issue-invalidate` (INFO-ONLY / NOT-CVE-WORTHY), or
+ `/security-issue-invalidate` (INFO-ONLY / INVALID), or
`/security-issue-deduplicate` (PROBABLE-DUP) directly.
license: Apache-2.0
---
@@ -58,7 +58,7 @@ It composes with:
- [`security-cve-allocate`](../security-cve-allocate/SKILL.md) —
invoked by hand after the team agrees a tracker is **VALID**.
- [`security-issue-invalidate`](../security-issue-invalidate/SKILL.md) —
- invoked by hand after the team agrees a tracker is **NOT-CVE-WORTHY**
+ invoked by hand after the team agrees a tracker is **INVALID**
or **INFO-ONLY**.
- [`security-issue-deduplicate`](../security-issue-deduplicate/SKILL.md) —
invoked by hand after the team agrees a tracker is a **PROBABLE-DUP**.
@@ -101,7 +101,7 @@ as a normal entry.
**Golden rule 4 — five disposition classes, no more.** The
classification is a proposal, not a verdict; the team's reply may
escalate (`INFO-ONLY` → `VALID` after a clarifying technical
-question lands) or de-escalate (`VALID` → `NOT-CVE-WORTHY` if a
+question lands) or de-escalate (`VALID` → `INVALID` if a
security-team member spots a previously-missed Security Model
carve-out). The skill always proposes exactly one class per
tracker — never two — because a two-class proposal stalls the
@@ -112,7 +112,7 @@ discussion rather than starting it.
| `VALID` | Clear Security Model violation; in-scope attack vector |
[`/security-cve-allocate`](../security-cve-allocate/SKILL.md) |
| `DEFENSE-IN-DEPTH` | Real issue, but outside the Security Model boundary
(e.g. local-user attacks on a worker the model treats as operator-trusted;
old-browser-only XSS that current browsers block) | close as wontfix + file a
public PR for the hardening |
| `INFO-ONLY` | Report is fact-correct but doesn't violate anything; matches a
known canned-response shape (educational reply, no tracker action needed) |
close + reporter-reply via the matching canned response |
-| `NOT-CVE-WORTHY` | Misframed, circular, by-design, or out-of-scope per the
canned-responses precedents |
[`/security-issue-invalidate`](../security-issue-invalidate/SKILL.md) |
+| `INVALID` | Misframed, circular, by-design, or out-of-scope per the
canned-responses precedents |
[`/security-issue-invalidate`](../security-issue-invalidate/SKILL.md) |
| `PROBABLE-DUP` | Substantive overlap with an existing tracker or closed
advisory (same root cause; sibling attack vector with the same fix shape) |
[`/security-issue-deduplicate`](../security-issue-deduplicate/SKILL.md) |
**Golden rule 5 — every `<tracker>` reference is a clickable
@@ -213,7 +213,7 @@ in `docs/prerequisites.md` for the overall setup.
| `triage #NNN`, `triage 212`, `triage #NNN, #MMM`, `triage #NNN-#MMM` |
specific issues by number (verbatim — no resolution) |
| `triage scope:<label>` (e.g. `triage scope:airflow`) | subset by scope
label, when set; useful when scoped-batch triage is split across triagers |
| `triage CVE-YYYY-NNNNN` | the tracker for that allocated CVE — used together
with `--retriage` (below) when a passed-triage decision needs re-litigating |
-| `--retriage` (flag) | force-include trackers that already had `needs triage`
removed but where new comment activity warrants a fresh proposal (e.g. a
reporter follow-up landed a substantive update; a sibling-vector report changed
the team's read on a prior `NOT-CVE-WORTHY` close). Combine with one of the
selectors above; bare `--retriage` without a selector is a hard error — the
skill refuses to re-triage everything ever. |
+| `--retriage` (flag) | force-include trackers that already had `needs triage`
removed but where new comment activity warrants a fresh proposal (e.g. a
reporter follow-up landed a substantive update; a sibling-vector report changed
the team's read on a prior `INVALID` close). Combine with one of the selectors
above; bare `--retriage` without a selector is a hard error — the skill refuses
to re-triage everything ever. |
If the user supplies no selector at all, default to `triage`
(every open `needs triage`). If `--retriage` is passed without
@@ -335,9 +335,9 @@ the inputs the classifier needs. Each tracker gets:
for headings whose name matches the tracker's report shape.
A hit on *"When someone claims Dag author-provided 'user
input' is dangerous"* (or analogous) is a strong signal for
- `NOT-CVE-WORTHY`; a hit on *"Image scan results"* / *"DoS/RCE
+ `INVALID`; a hit on *"Image scan results"* / *"DoS/RCE
via Connection configuration"* signals `INFO-ONLY` or
- `NOT-CVE-WORTHY`. Surface the matching canned-response name
+ `INVALID`. Surface the matching canned-response name
in the proposal so the team can confirm-with-template.
6. **Cross-reference search** — for `PROBABLE-DUP` detection,
@@ -380,19 +380,19 @@ explain how this tracker maps to (or escapes) that
wording.
### Trust-boundary cheat-sheet
Apply mechanically before VALID / DEFENSE-IN-DEPTH /
-NOT-CVE-WORTHY:
+INVALID:
| If the attacker is… | …and the target / effect is… | Default class |
|---|---|---|
-| DAG author | code execution in worker / DAG processor / Triggerer |
NOT-CVE-WORTHY (cite §"DAG Authors executing arbitrary code") |
-| DAG author | cross-DAG effect within shared parser / triggerer / worker pool
| NOT-CVE-WORTHY (cite §"Limiting DAG Author access to subset of Dags") |
-| Worker holding Execution JWT | read or write of another task's data via
Execution API | NOT-CVE-WORTHY (cite the *"Cross-DAG access via the Task
Execution API or Task SDK"* canned: `ti:self` is mutation-only, not per-DAG
access control) |
+| DAG author | code execution in worker / DAG processor / Triggerer | INVALID
(cite §"DAG Authors executing arbitrary code") |
+| DAG author | cross-DAG effect within shared parser / triggerer / worker pool
| INVALID (cite §"Limiting DAG Author access to subset of Dags") |
+| Worker holding Execution JWT | read or write of another task's data via
Execution API | INVALID (cite the *"Cross-DAG access via the Task Execution API
or Task SDK"* canned: `ti:self` is mutation-only, not per-DAG access control) |
| Authenticated UI / REST user with restricted DAG-scoped perms | reads other
DAGs' data via UI / REST | **VALID** (precedent: prior CVEs on this shape —
search closed `cve allocated` trackers in Step 2.6) |
-| Operator / Deployment Manager | misconfigures something with side-effects |
NOT-CVE-WORTHY (cite §"Connection configuration users" / operator-trust
framing) |
-| Authenticated user | DoS or self-XSS | NOT-CVE-WORTHY (cite §"DoS by
authenticated users" / §"Self-XSS by authenticated users") |
+| Operator / Deployment Manager | misconfigures something with side-effects |
INVALID (cite §"Connection configuration users" / operator-trust framing) |
+| Authenticated user | DoS or self-XSS | INVALID (cite §"DoS by authenticated
users" / §"Self-XSS by authenticated users") |
| External actor (email sender, request poster) | exploit via parser on
attacker-controlled input that reaches a supported platform | **VALID** |
-| External actor | exploit only manifests on a non-supported platform |
NOT-CVE-WORTHY (cite the project's supported-platforms section of the Security
Model) |
-| DAG author who deliberately routes user input | injection in operator / hook
/ SQL / shell | NOT-CVE-WORTHY (cite §"DAG Author code passing unsanitized
input") |
+| External actor | exploit only manifests on a non-supported platform |
INVALID (cite the project's supported-platforms section of the Security Model) |
+| DAG author who deliberately routes user input | injection in operator / hook
/ SQL / shell | INVALID (cite §"DAG Author code passing unsanitized input") |
**If the answer is not in the cheat-sheet, stop and ask the
user** rather than guessing. The classifier flags `UNCERTAIN`
@@ -437,10 +437,10 @@ proposal body with a one-line shape summary so the team
sees the
prior call without scrolling the closed list. A STRONG
precedent (same code surface + same vulnerability class) lowers
the proposal's confidence and may swing the disposition from
-VALID → NOT-CVE-WORTHY. Include the citation in the proposal:
+VALID → INVALID. Include the citation in the proposal:
> Direct precedent: [`<tracker>#NNN`](https://github.com/<tracker>/issues/NNN)
-> (closed YYYY-MM-DD as NOT-CVE-WORTHY, same shape: <one-line>).
+> (closed YYYY-MM-DD as INVALID, same shape: <one-line>).
Also search for **positive precedents** — CVE-allocated trackers
with similar shape — via:
@@ -466,7 +466,7 @@ supersedes; the proposal routes to
instead).
**Hard rule**: a rejection precedent in Step 2.6 does **not**
-auto-classify NOT-CVE-WORTHY — the human team reads the precedent
+auto-classify INVALID — the human team reads the precedent
and the new report side-by-side. The skill's job is to surface
the precedent, not to vote for it.
@@ -539,7 +539,7 @@ Propose when **all** of:
results"*, *"When someone claims Dag author-provided 'user
input' is dangerous"*).
-`INFO-ONLY` is distinct from `NOT-CVE-WORTHY`: the latter is
+`INFO-ONLY` is distinct from `INVALID`: the latter is
typically a *misframing* the team has to explain (and may
warrant an inline-augmented canned response); the former is a
clean *educational* reply where the canned template alone fully
@@ -548,7 +548,7 @@ answers the report.
The proposal names the matching canned-response template
explicitly (exact section heading from `canned-responses.md`).
-#### `NOT-CVE-WORTHY`
+#### `INVALID`
Propose when **any** of:
@@ -622,7 +622,7 @@ Severity: <guess>. Final scoring per the team after
assessing
<which load-bearing open question, if any>.
<Fix-shape sentence — what would the fix look like, in one or
-two sentences. For NOT-CVE-WORTHY / INFO-ONLY, this is the
+two sentences. For INVALID / INFO-ONLY, this is the
"why not" framing instead.>
<Optional Action items: numbered list when there's more than
@@ -806,11 +806,11 @@ rate-limit; the user retries the remaining items with the
After the post loop, print a recap with:
- Disposition distribution (e.g. *"3 VALID, 1 DEFENSE-IN-DEPTH,
- 2 NOT-CVE-WORTHY, 1 INFO-ONLY, 0 PROBABLE-DUP"*).
+ 2 INVALID, 1 INFO-ONLY, 0 PROBABLE-DUP"*).
- Per-tracker line: clickable issue link, class, comment URL.
- The set of sibling-skill next-step recommendations, grouped:
- `/security-cve-allocate NNN` for each VALID
- - `/security-issue-invalidate NNN` for each NOT-CVE-WORTHY and
+ - `/security-issue-invalidate NNN` for each INVALID and
INFO-ONLY (the invalidate skill handles both with the right
canned response)
- `/security-issue-deduplicate NNN MMM` for each PROBABLE-DUP
@@ -883,7 +883,7 @@ itself before presenting it.
- [`security-cve-allocate`](../security-cve-allocate/SKILL.md) —
invoked after a `VALID` disposition is confirmed.
- [`security-issue-invalidate`](../security-issue-invalidate/SKILL.md) —
- invoked after a `NOT-CVE-WORTHY` or `INFO-ONLY` disposition is
+ invoked after a `INVALID` or `INFO-ONLY` disposition is
confirmed.
- [`security-issue-deduplicate`](../security-issue-deduplicate/SKILL.md) —
invoked after a `PROBABLE-DUP` disposition is confirmed.
diff --git a/AGENTS.md b/AGENTS.md
index d7c7721..71c6a82 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1280,7 +1280,7 @@ Currently available:
a standalone top-level **triage-proposal comment** that classifies
the candidate disposition into one of five classes (`VALID` →
`security-cve-allocate`, `DEFENSE-IN-DEPTH` → public PR for
- hardening, `INFO-ONLY` / `NOT-CVE-WORTHY` → `security-issue-invalidate`,
+ hardening, `INFO-ONLY` / `INVALID` → `security-issue-invalidate`,
`PROBABLE-DUP` → `security-issue-deduplicate`) and `@`-mentions 2-3
security-team members per scope for input. **Read-only on tracker
state** — never flips `needs triage` to a scope label, never closes,
diff --git a/docs/security/README.md b/docs/security/README.md
index a87e88e..39201d9 100644
--- a/docs/security/README.md
+++ b/docs/security/README.md
@@ -35,7 +35,7 @@ and reuse the skills verbatim.
|
[`security-issue-import`](../../.claude/skills/security-issue-import/SKILL.md)
| Import new reports from `<security-list>` into `<tracker>`. |
|
[`security-issue-import-from-pr`](../../.claude/skills/security-issue-import-from-pr/SKILL.md)
| Open a tracker for a security-relevant fix opened as a public PR. |
|
[`security-issue-import-from-md`](../../.claude/skills/security-issue-import-from-md/SKILL.md)
| Bulk-import findings from a markdown report. |
-|
[`security-issue-triage`](../../.claude/skills/security-issue-triage/SKILL.md)
| Propose an initial-triage disposition (VALID / DEFENSE-IN-DEPTH / INFO-ONLY /
NOT-CVE-WORTHY / PROBABLE-DUP) for each tracker still in `Needs triage`; opens
a discussion comment, never flips the label. |
+|
[`security-issue-triage`](../../.claude/skills/security-issue-triage/SKILL.md)
| Propose an initial-triage disposition (VALID / DEFENSE-IN-DEPTH / INFO-ONLY /
INVALID / PROBABLE-DUP) for each tracker still in `Needs triage`; opens a
discussion comment, never flips the label. |
| [`security-issue-sync`](../../.claude/skills/security-issue-sync/SKILL.md) |
Reconcile a tracker against its mail thread, fix PR, release train, and
archives. |
|
[`security-cve-allocate`](../../.claude/skills/security-cve-allocate/SKILL.md)
| Allocate a CVE for a tracker (Vulnogram URL + paste-ready JSON). |
| [`security-issue-fix`](../../.claude/skills/security-issue-fix/SKILL.md) |
Implement the fix as a public PR in `<upstream>`. |
diff --git a/docs/security/process.md b/docs/security/process.md
index 9feec48..926a7b8 100644
--- a/docs/security/process.md
+++ b/docs/security/process.md
@@ -170,7 +170,7 @@ team consensus lands:
| `VALID` |
[`security-cve-allocate`](../../.claude/skills/security-cve-allocate/SKILL.md)
→ Step 6 |
| `DEFENSE-IN-DEPTH` | Close as wontfix + open a public PR for the hardening |
| `INFO-ONLY` |
[`security-issue-invalidate`](../../.claude/skills/security-issue-invalidate/SKILL.md)
with the matching canned-response template |
-| `NOT-CVE-WORTHY` |
[`security-issue-invalidate`](../../.claude/skills/security-issue-invalidate/SKILL.md)
|
+| `INVALID` |
[`security-issue-invalidate`](../../.claude/skills/security-issue-invalidate/SKILL.md)
|
| `PROBABLE-DUP` |
[`security-issue-deduplicate`](../../.claude/skills/security-issue-deduplicate/SKILL.md)
|
The triage skill is **read-only** on tracker state — it never