Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/security-issue-fix/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ If the query returns nothing, **propose creating the milestone**:

```bash
# Write tool: file_path: /tmp/ms-title.txt, content: <target>
# Write tool: file_path: /tmp/ms-desc.txt, content: Airflow <target> release tracking.
# Write tool: file_path: /tmp/ms-desc.txt, content: <product> <target> release tracking.
gh api repos/<tracker>/milestones \
-F title=@/tmp/ms-title.txt \
-f state=open \
Expand Down
19 changes: 10 additions & 9 deletions .claude/skills/security-issue-import-via-forwarder/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,22 +393,23 @@ the skill produces:
1. **`to_recipients`** — the matched adapter's `contact_handle`,
read from the adopter's
[`<project-config>/project.md → forwarders.<adapter>.contact_handle`](../../../<project-config>/project.md#forwarders).
For the ASF-default adapter this is the security-team liaison
(currently `@raboof`, with a rota fallback when configured);
for huntr.com it would be huntr's program contact; for
HackerOne it would be the assigned triager. The adapter MAY
return a list of fallbacks — pick the first available one and
surface the chosen handle in the recap.
For the ASF-default `asf-security` adapter this is the
configured security-team liaison handle (with a rota fallback
when configured); for huntr.com it would be huntr's program
contact; for HackerOne it would be the assigned triager. The
adapter MAY return a list of fallbacks — pick the first
available one and surface the chosen handle in the recap.

2. **`addressing_block`** — the paste-ready block rendered by
the adapter's `reporter_addressing_block()` per
[`tools/forwarder-relay/README.md` § `reporter_addressing_block()`](../../../tools/forwarder-relay/README.md#reporter_addressing_block---string).
Parameters passed in:

- `forwarder_first_name` — derived from the adapter's
`contact_handle` (the first-name part — for `@raboof`,
*"Arnout"*). When the handle is a list, use the first
available contact's first name.
`contact_handle` (the first-name part — e.g. for a handle
like `@some-liaison`, the first name *"Some"* derived from
the GitHub profile). When the handle is a list, use the
first available contact's first name.
- `reporter_first_name` — the first-name part of the credit
extracted at Step 2. Empty when Step 2 returned `null`;
the adapter's wrapper falls back to a generic salutation
Expand Down
9 changes: 5 additions & 4 deletions .claude/skills/security-issue-import/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -552,8 +552,9 @@ user as a candidate in Step 5. Record a one-line entry in the
recap's `dropped` section so the user knows the filter fired:

> Dropped `19d2f402867e957e` *(already answered on-thread
> 2026-03-28 by @potiuk with the DoS-by-authenticated-users
> canned response; reporter silent since)*.
> 2026-03-28 by `<security-team-member>` with the
> DoS-by-authenticated-users canned response; reporter silent
> since)*.

**When to stay cautious.** If the team reply does not match a
canned-response shape cleanly — e.g. the team member wrote a
Expand Down Expand Up @@ -1059,7 +1060,7 @@ if not, fall through to the table below.
| **Automated scanner dump**: SAST/DAST tool output, CodeQL/Dependabot alert paste, a string of "issues" with no human PoC | Body is machine-generated, contains multiple unrelated findings, no explanation of Security Model violation | Surface as a candidate with class `automated-scanner` and **do not** propose auto-import. In Step 5 the skill proposes a Gmail draft from the *"Automated scanning results"* canned response in [`canned-responses.md`](../../../<project-config>/canned-responses.md) instead. |
| **Consolidated multi-issue report**: one email bundles ≥3 unrelated vulnerabilities | The root message has headings like *"Issue 1"*, *"Issue 2"*, each of which would be its own tracker | Surface class `consolidated-multi-issue`; do not auto-import. Propose the "Sending multiple issues in consolidated report" canned reply. |
| **Media / research-disclosure request**: reporter wants to publish a blog or talk about a finding we already know about | Body asks about disclosure timing, mentions a talk / blog / CVE on another vendor | Surface class `media-request`; do not auto-import. Propose the "When someone submits a media report" canned reply. |
| **Obvious spam / scam / phishing / crypto-scheme** | Cryptocurrency addresses, "bug bounty program" framing on a project that does not have one, no actual Airflow-specific content | Surface class `spam`; propose no action (user deletes in Gmail). |
| **Obvious spam / scam / phishing / crypto-scheme** | Cryptocurrency addresses, "bug bounty program" framing on a project that does not have one, no actual `<upstream>`-specific content | Surface class `spam`; propose no action (user deletes in Gmail). |
| **Follow-up on existing thread that Step 2 missed** | Root message mentions a CVE already allocated, or the body is *"re: <existing tracker>"* but with a new threadId because the reporter replied from a different address | Surface class `cross-thread-followup`; do not auto-import. Propose a comment on the existing tracker instead. |
| **Already fixed by a public PR** | Step 2c surfaced a STRONG match: a public PR in `<upstream>` (open or merged, **not** filed in response to this report) already appears to fix the reported behaviour. The reporter sent `<security-list>` independently. | Surface class `fix-already-public`; **do not** create a tracker. Propose a thank-without-credit Gmail draft per the [no-credit-when-fix-is-already-public policy](../security-issue-import-from-pr/SKILL.md#reporter-credit-policy-for-public-pr-imports): thank the reporter, point at the PR, ask them to verify the PR fixes their report, and ask them to come back if it does not. Reply shape is in Step 5; the draft is sent in Step 7 only if the user confirms. **If the reporter later replies saying the PR does not fix their report**, that reply will re-surface in the next skill run (a new thread message will be detected); at that point classify as `Report` and import for proper triage. |

Expand Down Expand Up @@ -1122,7 +1123,7 @@ here.
|---|---|
| **The issue description** | The root email body, **verbatim** (preserve paragraphs, PoC code blocks, and any quoted sections). The body is private — the triager will copy it into a public CVE description only after Step 13. |
| **Short public summary for publish** | Leave `_No response_`. Filled by the release manager at Step 13 in sanitised form. |
| **Affected versions** | Extract `Airflow <version>` / `>= X, < Y` / `<Y` phrases from the body. If the reporter gave only a single version they tested on (e.g. `3.1.5`), record that verbatim; the triager can widen the range later. Leave `_No response_` if no version is mentioned. |
| **Affected versions** | Extract `<product> <version>` / `>= X, < Y` / `<Y` phrases from the body (substitute the adopter's product name — e.g. `Airflow <version>` for the airflow-s adopter). If the reporter gave only a single version they tested on (e.g. `3.1.5`), record that verbatim; the triager can widen the range later. Leave `_No response_` if no version is mentioned. |
| **Security mailing list thread** | **Keep the private thread handle, and — if possible — also link the PonyMail archive entry.** The full URL-construction recipe (search URL template, month-token format, user-pastes-back flow, Gmail-threadId fallback) lives in [`tools/gmail/ponymail-archive.md`](../../../tools/gmail/ponymail-archive.md#use-case--security-issue-import); the adopting project's private-search URL template is declared in [`<project-config>/project.md`](../../../<project-config>/project.md#gmail-and-ponymail). Propose the constructed search URL to the user at Step 5, wait for them to paste back the resolved `lists.apache.org/thread/<hash>?<security-list>` URL, and record both the PonyMail URL and the Gmail `threadId` in this field. The URL is **internal-only** — the `generate-cve-json` script will not export it to `references[]` — see the "CVE references must never point at non-public mailing-list threads" section of [`AGENTS.md`](../../../AGENTS.md). |
| **Public advisory URL** | `_No response_`. Populated at Step 14 by `security-issue-sync` once the advisory is archived. |
| **Reporter credited as** | The reporter's full display name from the email `From:` header (e.g. `Alice Example` from `"Alice Example" <alice@example.com>`). This is a **placeholder** — in direct-reporter mode, the receipt-of-confirmation reply in Step 7 asks the reporter to confirm their preferred credit form. **Apply the [bot/AI credit policy](../../../tools/cve-tool-vulnogram/bot-credits-policy.md) before populating** — if the `From:`-header name or address matches the bot detection rule (`*[bot]` suffix, known-bot list, `*-bot`/`*-ai`/`*-agent`/`*-gpt` suffix patterns, `noreply`/`no-reply`/`donotreply` / `security-alerts@` / `notifications@` service sender), **include** the detected name in the field (the CVE JSON generator emits it with `type: "tool"` per the policy's finder-side rule) and surface *"credited as tool: `<name>` (matches bot policy — `<rule>`)"* in Step 5's proposal. Service-sender addresses (noreply / relays) are still suppressed from the field — they are routing artefacts, not identities; extract the real reporter from the email body instead. **In direct-reporter mode**, also fold the policy's *clarification-reply* into the Step 7 receipt-of-confirmation draft, asking whether a human behind the bot/AI handle should be **additionally** credited as finder (the tool credit stands either way). **In via-forwarder mode** (when the optional [`security-issue-import-via-forwarder`](../security-issue-import-via-forwarder/SKILL.md) sub-skill pre-classified the candidate via a registered forwarder adapter — for the ASF adopter this is the `asf-security` adapter — and the other cases enumerated in [`docs/security/forwarder-routing-policy.md`](../../../docs/security/forwarder-routing-policy.md#when-does-via-forwarder-mode-apply)), the **standalone** bot-credit clarification draft is suppressed — it is a credit-acceptance confirmation message, which the forwarder cannot meaningfully answer. The credit *question* itself is **not** suppressed: it folds as a single best-effort *"if a human was behind the tool, please pass back their preferred attribution"* line into the Step 7 receipt-of-confirmation draft instead, per the [question-vs-confirmation distinction](../../../docs/security/forwarder-routing-policy.md#negative-space--do-not-relay) in the forwarder-routing policy. The same bot-detection rule applies to the forwarder adapter's `extract_credit()` output (the detection runs on the relayed credit string, not on the forwarder's sender address); see [`tools/forwarder-relay/README.md`](../../../tools/forwarder-relay/README.md) for the adapter contract. The user can override per the policy doc. |
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/security-issue-invalidate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,7 @@ Tracker `<tracker>#244` (*DAG author RCE on webserver via
unrestricted import_string() in BaseSerialization.deserialize()*),
import path: `security@`-imported. Step 3 mines five comments
arguing the dag author is already trusted (with quotes from
@potiuk and @ephraimbuddy). Canned: *When someone claims Dag
two security-team members). Canned: *When someone claims Dag
author-provided "user input" is dangerous*. Email draft created
on thread `<threadId>` with the canned spine + augmentation
quoting the team's specific reasoning. Tracker closed as
Expand Down
Loading
Loading