A bulk vulnerability disclosure campaign is one reporter submitting many findings to many unrelated parties at once, on a timeline the reporter sets. Z.ai's public Security Disclosure Ledger records **2,436 findings across 269 open-source projects**, 107 of them critical and 990 high, with an average of **26.6 years** between a defect being written and being found. An independent audit of the ledger's status field found **2,239 of those findings still marked `discovered`** and exactly one marked `sent to maintainer`. Per-report intake, one acknowledgment, one SLA clock, one severity call, breaks on contact with that shape.

This is the third article in a sequence, and the distinction is the whole point. [The slop piece](/blog/ai-slop-flooding-bug-bounty-triage) was about **invalid** reports arriving in volume. [The economics piece](/blog/ai-cheap-vulnerability-research-vdp-triage-economics) was about the cost of finding a real bug collapsing to roughly the price of lunch. This one is about neither: these findings are largely valid, and nobody asked for them. [The multi-vendor piece](/blog/coordinated-disclosure-multi-vendor-vulnerabilities) covered one bug landing on five vendors. This is one reporter landing on 269 projects, the same governance problem turned inside out, with the deadline held by the party that has a product launch.

## 2,436 findings, 269 projects, and one reporter

Z.ai launched GLM-5.3 on 14 August 2026 and published a Security Disclosure Ledger at `cvd.z.ai` the same day. The ledger, not the benchmark score, is the artefact worth reading.

| Metric | Figure |
|---|---|
| Total findings | 2,436 across 269 open-source projects |
| Severity split | 107 critical, 990 high, 1,286 medium, 53 low |
| Publicly disclosed | 53 with CVE identifiers; 2,383 undisclosed |
| Mean bug age | 26.6 years from introduction to discovery |
| Oldest affected code | 1981, a 45-year span |

Named disclosed findings include the Linux kernel's 6lowpan stack, WebKit, FreeBSD's `ptrace`, GStreamer, and Suricata. Z.ai reports GLM-5.3 scoring **84.5% on CyberGym**, up from GLM-5.2's 77.2%. The Hacker News thread ran to 1,170 points and 584 comments, with the sharpest pushback aimed not at the model but at scanning open source at scale with no embargo policy.

Two caveats before you build anything on these numbers.

**The campaign is not one model's work.** Z.ai says it began in the GLM-5.2 era across several security teams and multiple harnesses, and upstream advisories credit various GLM versions. Write "Z.ai's campaign," never "GLM-5.3 found 2,436 bugs."

**Every aggregate here rests on Z.ai's own publication.** Nobody outside the company can audit the 2,383 undisclosed records. That is not a swipe at Z.ai. It is the position you will be in when a batch of forty lands in your inbox: you cannot verify a bulk reporter's claims at intake, and neither can I verify these.

## Why this is not the AI slop story, and not the cheap-discovery story either

The slop problem was about signal-to-noise. The economics problem was about unit cost. This one is about **shape**, and shape is what breaks tooling.

A normal VDP assumes a many-to-one relationship: many independent researchers, each sending one report, each opting into your policy by submitting under it. A bulk campaign inverts that. One reporter addresses 269 receiving parties at once, on a schedule only the reporter controls, and publishes a public record before most receivers have been contacted.

The receiving party did not opt in, did not agree to a timeline, and in most cases has not been told. That is not a bug bounty submission. It is closer to a **mass vulnerability-notification campaign**, which security research has studied for a decade and found to have a dismal response rate.

## The bottleneck is notification, not patching

The most useful fact in the ledger is not the 2,436. It is where those findings are sitting.

An audit of the ledger's own status field, captured on 14 August, recorded: **2,239 `discovered`, 84 `reported`, 53 `revealed`, 29 `acknowledged`, 30 `patched`, and 1 `sent to maintainer`.** That is roughly **92% of the findings still sitting on the reporter's side.**

Anthropic ran the same play two months earlier and got audited for it. VulnCheck's 9 June 2026 analysis of Anthropic's Mythos ledger found **23,019 vulnerability candidates**, of which 467 were validated and reported and 1,129 reported without validation. That is **1,596 findings, 6.9%, reaching maintainers in 60 days**, a pace VulnCheck put at roughly **2.4 years to clear the backlog**. It also found **ten findings already past Anthropic's own 90-day deadline** without publication, and 168 more due within 30 days.

Two vendors, two ledgers, one structural result: **discovery scales and notification does not.** A model can find a heap overflow in a 1994 codebase in minutes. Finding the maintainer, writing a report a human can act on, and shepherding it to a patch is unchanged human work.

For the receiving end that is good news with an expiry date. The wave has not hit you yet, and when it does it will arrive as a **batch**, because the reporter is clearing a queue rather than filing a bug.

## What breaks when 40 reports arrive from one sender

Three mechanical failures, none of them a judgment call. All three are your existing automation working exactly as designed.

**Acknowledgment fan-out.** A per-report auto-reply is correct for one report and abusive for forty. The sender gets forty emails nobody wanted, your domain sends forty near-identical messages to one address, and after all that the sender still does not know who owns the batch or when a human will look.

**SLA aggregation.** Forty acknowledgment clocks start at once, each satisfiable within 72 hours on its own, together a triage load nobody sized the rota for. Your queue reads green per report and hopeless in aggregate. That is the failure mode the [multi-vendor article](/blog/coordinated-disclosure-multi-vendor-vulnerabilities) documented, inverted: there, one case had many clocks; here, many cases share one capacity ceiling.

**Severity before root cause.** Per-report triage asks "how bad is this one?" first. For a campaign that is the second question. The first is "is this reporter's method sound, and do these findings share a root cause?" Forty findings from one harness against one parser are often one bug class with forty call sites. Triaging them independently costs forty times as much and gives a worse answer, because the pattern is only visible in aggregate.

All three failures come from one modelling decision: **the report is the unit of work.** For a campaign, it is not.

## A campaign is not a report: what your intake needs to model

The fix is a batch object sitting above the report. Five fields carry most of the value.

1. **One batch, one acknowledgment.** One reply that names the batch, states how many findings arrived, and commits to a first substantive response date. Suppress the per-report mail when a batch id is present.
2. **One owner.** A named human accountable for the batch, not forty round-robin assignments.
3. **One shared clock for the batch**, with per-finding clocks underneath. Acknowledgment is a batch obligation; remediation is per finding.
4. **A method assessment recorded once.** Is the harness sound? Are the PoCs runnable? Answer for the batch, inherit it, revise only where a finding contradicts it.
5. **Root-cause grouping before severity.** Cluster first, then score the clusters rather than the rows.

Kit does not ship this yet. Its `Csirt::` vertical treats `Csirt::Report` as the top-level record: no campaign object, no submission batch. Forty reports are forty rows, forty acknowledgment mails, forty SLA clocks, forty on-call pings. That is this article's central argument, and it is a gap in our own product rather than a feature of it. The five fields above are the shape we think it should take.

## Who owns the disclosure clock when the reporter is a model vendor?

Nobody, unless you write it down.

No law fixes coordinated disclosure at 90 days. There is convention, such as Project Zero's 90+30 and ZDI's 90+14 for engaged vendors, and there is whoever publishes first. When the reporter is a model vendor, the deadline is entangled with **launch marketing**, because the ledger is a capability demonstration as much as a disclosure artefact.

Z.ai has published no embargo policy on the ledger: no policy page, no per-finding deadline, no countdown. Only status, severity, and identifiers. That is more transparent than silent scanning, and it still leaves you with no stated date.

Anthropic did publish a 90-day deadline, and VulnCheck found ten findings that had blown through it while still unpublished. So the choice is not between a vendor with a policy and a vendor without one. It is between a date on **your** record and a date in someone else's publication pipeline.

Three fields close that gap: `requested_embargo_at` (what the reporter asked for), `agreed_embargo_at` (what you negotiated), and `published_at` (what happened). Kit does not have them, and says so on its own comparison page: *"Kit models no disclosure timers or embargo dates at all. An embargo-date field is a fair ask; today Kit tracks acknowledgment, not disclosure."* The only 90-day constant in the codebase is a receipt-token expiry, not a disclosure clock.

## Rate limits are the wrong defence: what Apple's cap actually bought

The first instinct on reading all this is to throttle the sender. Apple ran that experiment in public, and the result is more interesting than the headline.

In June 2026 Apple added a submission cap plus a **30-day cool-off** on its security research portal, with further submissions requiring a special request. The cap number is unpublished. Bynario, who had filed **13 reports across all of 2025 and early 2026**, built an AI harness and filed **50-plus macOS reports in three weeks**. They tripped the cap and were locked out of the portal at the moment they had a critical finding in hand.

Here is the part usually left out: the throttle did not stop the finding. Apple received the details through another channel and patched **CVE-2026-43760** on 27 July, a confused-deputy flaw in the legacy VNC path that let a VNC-authenticated viewer read and create files as root. Bynario published its analysis two days later, after the patch shipped. That is ordinary post-patch research publication, not a frustrated zero-day drop.

Then came the part the cap could not touch. Bynario's write-up put researcher attention on a legacy Screen Sharing code path. Within 48 hours a separate **pre-authentication** flaw in the same daemon was disclosed with a proof of concept. Four days later it was weaponised, then exploited in the wild for cryptomining against internet-exposed port 5900. Apple emergency-patched on 6 August. CISA rescored it from 7.1 to **9.8 on 14 August** and added it to the Known Exploited Vulnerabilities catalogue on 18 August, with a federal fix-by date of 21 August 2026.

Ten days from a post-auth privilege bug to a KEV-listed pre-auth RCE in the same component.

The moral is not that throttling causes zero-days; that overreads the evidence. It is narrower and more useful: **a submission cap governs how fast reports enter your queue, not how fast the world learns.** Intake capacity is the only variable you control on that timeline, and the cap added none.

## GitHub's better answer: four submissions and a door out

GitHub hit the same wall and chose tiering over throttling. For reports filed on or after 27 July 2026, it runs a fixed-payout public tier at **$250 / $2,000 / $5,000 / $10,000** for low through critical, and an invite-only VIP tier at **$1,000 / $7,500 / $20,000 / $30,000+**.

The interesting mechanism is the entrance. Researchers below the platform signal threshold get **up to four initial submissions** to establish themselves, and the VIP door opens on **one valid critical**, or two high, or four medium, or seven low.

That is a rate limit with an exit. Bynario's harness would have burned four submissions and then, on any one of the criticals it later reported, earned the fast lane. Apple's cap has no door: it counts submissions, hits its number, and the only way back in is the calendar.

The design distinction is worth stating flatly: **a throughput limit is defensible only when clearing it is a function of being right, rather than of waiting 30 days.** GitHub's own summary of its restructure is the line to steal: *"you don't earn more by submitting more. You earn more by submitting better."*

Kit implements the trust half of that idea and needs to fix the throttle half. `Csirt::Researcher#karma_tier` buckets researchers by accumulated karma, reaching `trusted` at 200 points, fed by signed `Csirt::KarmaEvent` values: `report_validated` +5, `bounty_awarded` +10, against `spam_dismissed` -10, `ai_slop_confirmed` -15, `policy_violation` -25. Karma is per account by design, so one program's judgment does not follow a researcher around the internet.

Kit's defaults would still have locked out a Bynario. `SpamConfig` blocks after 5 reports in 300 seconds, and the rate limiter caps CSIRT submissions at **10 per hour per IP**. A reporter with forty verified findings hits both. That is the Apple failure mode living in our own defaults, and the fix is not a bigger number. It is to count the **batch** rather than the request, and to let `karma_tier` raise the ceiling for a reporter who earned it.

## Reproduction-first triage: five fields your policy must require

Sophos's CISO Ross McKerchar and Ryan Westman put the standard crisply: programs need *"clear PoCs, logs, traces, impacted versions, and reproducible steps. If a claim can't be reproduced, it doesn't belong in the pipeline."*

Turn that into form fields, not policy prose. Require:

1. **A working proof of concept.** A script, a request, or a trace. Prose describing an exploit is not an exploit.
2. **Affected versions, exactly.** A commit SHA or a release tag. Never "latest."
3. **Reproduction steps a stranger can run**, from clean state to observed impact.
4. **Was any part of this finding model-generated?** Yes or no, plus which system. Not to penalise, to route.
5. **Did a human verify this finding end to end?** Yes or no, plus who.

Field 5 does the real work. It is the difference between the Bynario case, where AI output was human-verified and produced a critical, and slop. Almost nobody asks it today, and it costs two booleans and a text field.

The moment you accept campaigns, add two more: **batch id or campaign name**, and **requested disclosure date**, so the reporter states their clock inside your record rather than in their blog.

<div class="blog-inline-cta">
  <p><strong>Running a VDP with a real ledger?</strong> Kit's CSIRT module ships structured intake, AI-origin screening, duplicate detection, per-severity SLA tiers, and a generated security.txt.</p>
  <p><a href="/users/sign_up">Start your free trial</a></p>
</div>

## The regulator's clock starts on 11 September 2026

If you sell connected products into the EU, one inbound report can start a legal timer that has nothing to do with your queue. From **11 September 2026**, the Cyber Resilience Act requires an early warning within **24 hours**, a full notification within **72 hours**, and a final vulnerability report within **14 days** of a corrective measure, filed to your national CSIRT through the CRA Single Reporting Platform and shared simultaneously with ENISA.

That clock keys to your awareness of active exploitation. It does not care that the report arrived as item 23 of 40, that no human had read it, or that a model wrote it. A batch sitting unread for four days is a compliance exposure, not just a backlog. Our [EU Cyber Resilience Act guide](/blog/eu-cyber-resilience-act-mandatory-vulnerability-disclosure) covers the obligation in full.

## No intake means the ledger is your disclosure channel

If a reporter cannot find a way to contact you, they do not stop reporting. They publish.

`security.txt` is the cheapest fix in security and the least adopted. A 2025 survey of the top million domains found **1.25% (12,510 sites)** publishing one, up from 0.7% in April 2024, and only **44% of those** conforming to RFC 9116. Roughly 99% of the web has no machine-readable security contact, and over half the exceptions have a malformed one.

Kit generates a conformant file from `Csirt::SecurityTxtConfig`, with `Contact`, `Policy`, `Acknowledgments`, `Encryption`, and a rolling 365-day `Expires`. If you have no program at all, start with our [guide to setting up a vulnerability disclosure program](/blog/how-to-set-up-vulnerability-disclosure-program) before you worry about batching.

## How Kit's CSIRT handles a campaign, and what it doesn't yet

Some of what this moment demands already ships in Kit. Some does not, and the split is more useful than a feature list.

**What holds up today:**

- **Structured intake, not a prose box.** `Csirt::Report` requires `title`, `description`, `vulnerability_type` from a fixed list, and `affected_endpoint`, plus a dedicated `reproduction_steps` column. That column is nullable, which the checklist above argues is wrong. Making it required is the first config change to make.
- **AI-origin screening as a first-class record.** `Csirt::AiScreening` scores every inbound report and returns an `ai_confidence_score` plus signals from a closed enum (`hallucinated_functions`, `fabricated_cves`, `no_specific_poc`, `vague_reproduction_steps`, and more) with a `pass` / `review` / `flag` recommendation. That is the Sophos reproduction test implemented as a column rather than a paragraph.
- **Root-cause grouping already exists as a primitive.** Reports carry a 3,072-dimension embedding, and duplicate detection runs cosine nearest-neighbour within a program. Where forty findings are one bug class, that is the mechanism that collapses forty tickets into one.
- **Reputation instead of throttles**, via `karma_tier`.
- **SLA split between acknowledgment and resolution.** `Csirt::SlaConfig` defaults to a 72-hour acknowledgment window with per-severity resolution targets from 24 hours at `super_critical` to 720 at low, plus repeating breach alerts and on-call escalation for criticals.

**What is missing, stated as roadmap and not as features:**

1. **No campaign object.** Forty reports are still forty rows with forty clocks.
2. **No disclosure timeline fields.** The lifecycle runs `submitted` through `resolved` and `paid`, with no vocabulary for the reporter's clock.
3. **No declared model-generated or human-verified flags.** Screening infers AI origin after the fact; nothing asks the submitter.
4. **Throttle defaults that would lock out a good-faith bulk reporter**, exactly as Apple's cap did.

Every other article about this ledger treats it as a story about a model. It is a story about an inbox. The findings are mostly real, mostly unreported, and coming. The change that prepares you is small: make the **campaign**, not the report, the thing your program acknowledges, owns, and clocks. Then write the reporter's date into your record before they write it into their blog.