disclosure-tracker
Audit of the pending vulnerability disclosure queue — tracks draft advisories in memory/pending-disclosures/, alerts on aging CRITICAL/HIGH findings.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Audit of the pending vulnerability disclosure queue — tracks draft advisories in memory/pending-disclosures/, alerts on aging CRITICAL/HIGH findings.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
| name | disclosure-tracker |
| category | dev |
| description | Audit of the pending vulnerability disclosure queue — tracks draft advisories in memory/pending-disclosures/, alerts on aging CRITICAL/HIGH findings. |
| tags | ["security","meta"] |
Today is ${today}. Read memory/MEMORY.md before starting.
Monitor the pending vulnerability disclosure backlog. The vuln-scanner skill queues draft advisories to memory/pending-disclosures/ when Private Vulnerability Reporting (PVR) auto-submission fails or when the disclosure path is email-only. Without daily visibility, CRITICAL/HIGH advisories silently age past responsible-disclosure windows. This skill surfaces the queue state every morning and escalates when findings have been sitting too long.
Check memory/pending-disclosures/ for draft advisory files.
ls memory/pending-disclosures/ 2>/dev/null
If the directory doesn't exist or is empty:
DISCLOSURE_TRACKER_SKIP: no pending advisories and stop. No notification needed.For each .md file in memory/pending-disclosures/:
From the filename (pattern: {repo-slug}-{YYYY-MM-DD}.md or {repo-slug}-{YYYY-MM-DD}-{ampm}.md):
From the YAML frontmatter (if present) parse:
repo: — overrides the filename slug when present (canonical target)severity: — CRITICAL / HIGH / MEDIUM / LOWstatus: — see step 2.5 for the controlled vocabularyFrom the file content (fallback for files without frontmatter), look for these fields near the top of the file:
Severity: or **Severity:** — one of CRITICAL / HIGH / MEDIUM / LOWCVE/CWE: or similar identifierIf severity is not parseable, treat as MEDIUM.
Compute age: today - filed date in days.
Before counting any draft as a past-threshold escalation, decide whether the draft is genuinely pending or already covered. A draft can be in one of these states:
escalate — pending, no canonical PR found, past the severity-tier thresholdpending — pending, no canonical PR found, within the threshold windowoperator-todo — needs operator-only action (email send, PVR enable nudge); not an agent failurecovered-by-pr — a canonical disclosure PR has already been filed against the target repo and is OPEN or recently mergedsuperseded-upstream — the bypass / vuln is fixed in upstream already, draft is dead-weightsubmitted — already submitted via PVR / GHSA; awaiting maintainer responseResolution rules:
Check frontmatter status: first — map the literal value to a state:
superseded-upstream → superseded-upstreamsubmitted, submitted-via-pvr, disclosed-via-pr-{N} → submitted or covered-by-prpending-operator-send, queued for operator manual send, any string mentioning "operator" → operator-todopending, blank, or missing → fall through to rule 2Cross-reference memory/topics/pr-status.md (if present) — grep for the {repo} slug (frontmatter repo: or filename) in the Open section and Recent Merges section. If a row exists with a fix(security) or chore(security) title against that repo, opened on or after the draft's detected_at / reconstructed_at / filed-date, classify as covered-by-pr and capture the PR number / title for the summary. If memory/topics/pr-status.md doesn't exist, skip this lookup and fall to rule 3.
Fall through — if no status hint and no canonical PR found, classify as pending. Then check age vs the severity-tier threshold (CRITICAL 3d / HIGH 7d / MED-LOW 14d) — if past, promote to escalate.
This is the load-bearing step. Without cross-referencing already-merged fix PRs the tracker generates false-positive escalations for drafts that have already been resolved.
Group advisories by state first, then by severity within each state. The three buckets are:
escalate state only (truly stuck, past threshold, no canonical PR)operator-todo state (email-only sends, PVR-enable nudges, anything awaiting human action)covered-by-pr, submitted, superseded-upstream (draft files that can be removed from memory/pending-disclosures/)Severity tiers and thresholds (only apply to escalate and pending states):
For each advisory, produce one line:
- {repo-slug} | {severity} | {age}d | {short title}{state-suffix}
where {state-suffix} is empty for escalate / pending, [operator-todo: {reason}] for operator-todo, and [covered: PR #{N}] / [superseded-upstream] / [submitted] for cleanup candidates.
Count totals. Identify advisories in the escalate state — those are the only ones that drive the urgent notification path.
Look in memory/issues/INDEX.md for any open issues tagged with pvr, repository_advisories, or missing-secret that explain why advisories are stuck. If such an issue exists, note:
If no such issue exists, treat the queue as routine and skip the "blocked by" line in the notification.
Compute counts from step 3:
escalate_count — drafts in the escalate statepending_count — drafts in pending (in-window) stateoperator_todo_count — drafts awaiting operator actioncleanup_count — drafts in covered-by-pr / submitted / superseded-upstreamDecision:
DISCLOSURE_TRACKER_SKIP: queue empty and stop.escalate_count > 0: send the urgent escalation notification.escalate_count == 0 but cleanup_count > 0: send a daily digest that includes the cleanup-candidate list so operator can prune memory/pending-disclosures/.pending / operator-todo, nothing past threshold, no cleanup candidates: send the daily digest.Coverage from covered-by-pr / submitted / superseded-upstream is never counted as an escalation — those are informational only. Operator-todo is never counted as escalation either; it's surfaced separately so operator knows their inbox.
Write to a temp file, then send with ./notify -f:
mkdir -p .pending-notify-temp
./notify -f .pending-notify-temp/disclosure-tracker-${today}.md
Urgent format (escalate_count > 0):
disclosure queue: {escalate_count} past threshold (of {total} drafts).
ESCALATE:
- {repo} — {severity}, {age}d old (threshold: {N}d)
[... others in `escalate` state ...]
operator-todo ({operator_todo_count}):
- {repo} — {severity}, {age}d — {operator-reason}
cleanup candidates ({cleanup_count}):
- {repo} — [covered: PR #{N} / superseded-upstream / submitted] — safe to delete from memory/pending-disclosures/
{IF blocking issue tracked in memory/issues/INDEX.md}
blocked by {ISS-ID} — {short reason}
fix: {fix estimate} unblocks {N} of {escalate_count + pending_count}
{end}
Daily digest format (no escalation):
disclosure queue: {total} drafts. {critical_count} CRITICAL, {high_count} HIGH, {other_count} MED/LOW.
{pending_count} in-window, {operator_todo_count} operator-todo, {cleanup_count} cleanup candidates.
oldest in-window: {repo} ({age}d).
{cleanup section if cleanup_count > 0}
{IF blocking issue tracked in memory/issues/INDEX.md}
blocked by {ISS-ID} — {short reason}.
{end}
Append to memory/logs/${today}.md:
## Disclosure Tracker
- **Queue:** {total} drafts ({critical_count} CRITICAL / {high_count} HIGH / {other_count} MED/LOW)
- **State breakdown:** {escalate_count} escalate / {pending_count} in-window / {operator_todo_count} operator-todo / {cleanup_count} cleanup-candidates
- **Oldest in-window:** {repo} ({age}d)
- **Escalations:** {escalate_count} past threshold (excludes covered / submitted / superseded)
- **Cleanup candidates:** {list of repos with state-suffix}
- **Blocking issue:** {ISS-ID or "none"}
- **Notification:** {sent|skipped}
- DISCLOSURE_TRACKER_OK
This skill only reads local files (memory/pending-disclosures/, memory/issues/, memory/topics/pr-status.md). No outbound network or auth required. No sandbox workarounds needed.
None. All data comes from local files written by the vuln-scanner skill.
Newer drafts use YAML frontmatter:
---
repo: owner/name
severity: HIGH
cwe: CWE-639
status: pending-operator-send # optional; see controlled vocabulary below
patch_branch: https://github.com/<your-fork-org>/<repo>/tree/<branch>
submit_url: https://github.com/owner/name/security/advisories/new
---
# {Repo}: {Title}
...
Older drafts use inline **Severity:** lines. Parse defensively — grep for severity: and Severity: case-insensitively. If unparseable, default to MEDIUM.
status: controlled vocabularySet by vuln-scanner / operator / cleanup chores. Drives step 2.5 classification:
pending — same as blankpending-operator-send / queued for operator manual send — operator-todosubmitted / submitted-via-pvr — submitted, awaiting maintainerdisclosed-via-pr-<N> — covered-by-pr, draft can be archivedsuperseded-upstream — bypass is already fixed in upstream; draft is deadoperator — operator-todoWhen a canonical PR lands but the draft's status: was never set, the tracker falls through to step 2.5 rule 2 (cross-ref pr-status.md) and classifies as covered-by-pr automatically. The status: shortcut is just an explicit hint that bypasses the grep.
Cleanup candidates in the notification can be removed by the operator with rm memory/pending-disclosures/<file>.md. Safe to do at any time once the canonical PR is open — the patch branch on the fork remains the authoritative artifact.
Audit every enabled skill's upstream file dependencies for staleness — flags chained skills about to consume yesterday's article or a long-dead topic file
Validate skill outputs against assertions, diff vs prior eval to flag regressions, file issues for new failures, and queue concrete fixes
Compare current progress against goals with quantified status, velocity, trend, and a concrete next action per goal
First-touch review of newly opened PRs on [REPLACE: WATCHED_REPO] — verdict + welcoming comment + label
Summary of the [REPLACE: CHANNEL_PLATFORM] channel [REPLACE: CHANNEL_NAME] — top [REPLACE: TOP_N_THREADS] threads + open questions
Price and volume tracker for [REPLACE: TOKEN_SYMBOL] with anomaly alerts above [REPLACE: ALERT_THRESHOLD_PCT]% movement