"Published" feels like a durable fact. You write a comment, the API returns 200, a screenshot captures the rendered page, and you move on. This field note is about the day three published artifacts on GitHub all returned 404 — and what that experience changed about how we run security outreach.
Everything below is drawn from a real AI/Agent security outreach campaign run in August 2026. Where a number, URL, or timestamp appears, it is taken from the campaign's own send log, response files, or scorecards — no figure here is invented.
The setup: two channels, one campaign
In August 2026 we ran a multi-channel outreach campaign to AI/Agent ecosystem projects (MCP servers, agent frameworks, LLM gateways, vector databases). The goal: offer a free static scan pass of their codebase, backed by pre-verified CVE findings where a project had them.
Two channels carried the load:
-
Email. 26 outreach emails documented in the campaign send log, every address sourced from a public page (SECURITY.md, security.txt, or the GitHub org API), with zero confirmed bounces through IMAP bounce checks. Source:
SENT_LOG_20260813.md(campaign send log, 2026-08-13). - GitHub. Issue comments and discussions on public repositories — the classic "meet maintainers where they are" route.
What disappeared
On 2026-08-13, three GitHub touch points were published and verified at publish time:
| Touch point | Target | Published (UTC) | Verification at publish |
|---|---|---|---|
| Issue comment on issue #22456 | run-llama/llama_index | 02:44 | GitHub API returned the full comment object (HTTP 200), captured to li_comment_response.json
|
| Issue comment on issue #13671 | Significant-Gravitas/AutoGPT | 03:36 | GitHub API returned the full comment object (HTTP 200), captured to autogpt_comment_response.json
|
| Discussion #1868 | openinterpreter/openinterpreter | 06:56 | CDP publish with URL redirect + page-title match + screenshots, captured to openinterpreter_publish_evidence.json
|
Later on the same day, a persistence re-check (anonymized API and plain HTML, both channels) found:
- All three comments/discussion returned 404.
- The issue threads themselves — #22456 and #13671 — also returned 404.
- The publishing account (
github.com/Correctover) returned 404 on both API and web. - Control:
dev.to/correctoverstill returned 200.
Source: SENT_LOG_20260813.md, "第二波(GitHub 通道)— 全部已失效" section (2026-08-13), plus the three evidence files listed above.
The account was removed by the platform. Every public artifact associated with it was deleted along with it. Nothing we had published on that channel survived.
Why "published" and "persistent" are different claims
This experience crystallized a distinction that is easy to miss:
- Publish-time verification (HTTP 200, screenshot, URL redirect) proves the write succeeded. That is all it proves.
- Persistence is a property that only exists later, and it is owned by the platform, not by you.
For security researchers and security tooling companies, the stakes are real. A disclosure that vanishes breaks provenance: downstream scanners cannot resolve the link, a future auditor cannot reconstruct the timeline, and anyone who bookmarked the URL finds a dead end. The same verification discipline we apply to CVE data — real, public, fixed, correct range — has to extend to the durability of the records themselves.
The discipline we now run
- Gate the payload before you send. Every CVE we cite passes a four-gate check: it exists, it is public, it has a fix version, and the version range is correct. One failed gate means we drop the CVE ID and switch to a preventive pitch. (Full write-up on this blog: "AI Agent Security Audit Outreach: CVE Verification Before Cold-Emailing Maintainers" — the campaign scorecard documents 6 CVEs that passed the gate and the corrections caught along the way.)
- Capture the artifact at publish time, locally. For every publish we store the raw response JSON, the screenshot, and the timestamp in a local ledger — the three evidence files above are exactly this. If the platform record vanishes, the proof that the write happened still exists, and so does the content.
- Re-check persistence, not just publish. After the platform settles, re-verify the URLs. A 200 at publish time is not a durable record; a 404 later is the only fact that outlives it. The re-check is a two-line loop we now schedule after every outreach wave:
def verify_persistence(urls):
"""Publish-time 200 is not a durable record. Re-check after the platform settles."""
return {url: http_status(url) for url in urls} # 200 -> ALIVE, 404 -> GONE
- Prefer a durable channel for anything that must last. Email through a public-source address is a channel you can log, archive, and re-verify. A profile on a third-party platform is a channel the platform owns — and can remove.
The takeaway for AI/Agent security
None of this is unique to us. If you publish security disclosures, MCP-server findings, or advisory comments on any platform you do not own, assume the record is temporary. Keep the evidence, keep the audit trail, and treat "published" as a moment — not a fact.
At Correctover (CCS), verification is the product. CCS is the security validation layer for AI applications: it statically scans AI/LLM code for SSRF, prompt injection, and unsafe file access in CI (16 systemic vulnerability patterns), and enforces agent tool-call selection, arguments, and permissions at runtime before a call executes. The same discipline — verify the data, verify the record — is what we run on every engagement.
If you are building an AI agent, an MCP server, or an LLM gateway and want a free static scan pass of your codebase, reach us at correctover.com.
Top comments (0)