{"uuid": "884ddf62-19f5-4955-a6bb-aaba52b5ad21", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2025-29927", "type": "seen", "source": "https://gist.github.com/MarisollieNULL/91df2a5b8be5f9f07e9a52a1b572afe4", "content": "Confession Density Isn't Bug Density\n\n# Confession Density Isn't Bug Density\n\n_A counter-intuitive read on AGENTS.md, CLAUDE.md, and SECURITY.md files in OSS repos. The repos that loudly admit they're rough usually aren't._\n\nCloudflare's [`vinext`](https://github.com/cloudflare/vinext) confesses, on the first page of its AGENTS.md, that it has _\"repeatedly shipped fixes that diverged from Next.js because this step was skipped.\"_ The README labels the project _\"experimental, under heavy development. This project is an experiment in AI-driven software development.\"_ Both labels read like a bug-density advertisement. I audited under that assumption and found nothing payable. The codebase isn't actually rough. The AGENTS.md is. That's a different thing.\n\nThis is a writeup of that mismatch, and of the replacement heuristic I should have been using.\n\n## What the repo confesses\n\nThe [AGENTS.md](https://github.com/cloudflare/vinext/blob/main/AGENTS.md) reads like an unusually candid postmortem. Under \"Fixing Bugs\":\n\n&gt; \"We have repeatedly shipped fixes that diverged from Next.js because this step was skipped.\"\n\nThe \"step\" is searching the Next.js test suite for an existing test before reimplementing behavior. The cited concrete failure is _\"middleware failing open on invalid exports instead of throwing an error (which Next.js tests explicitly).\"_\n\nUnder \"Next.js Request Execution Order\" there's an open parity-gap admission:\n\n&gt; \"Current vinext gap: vinext evaluates config headers at step 6 (after middleware) instead of step 1 (before middleware) ... a known parity gap tracked for future work.\"\n\nAnd the document calls out four parallel server implementations that have to stay in sync:\n\n```\nentries/app-rsc-entry.ts\nserver/dev-server.ts\nserver/prod-server.ts\ncloudflare/worker-entry.ts\n```\n\nThe instruction is direct: _\"When fixing a bug in any of these files, check whether the same bug exists in the others. Do not leave known bugs as 'follow-ups', fix them in the same PR.\"_\n\nRead at face value, this is a parallel-implementation anti-pattern with admitted past divergences in a codebase the maintainers are framing as AI-codegen-experimental. The bug-density priors all point up.\n\nI picked one of the candidate bug classes (middleware bypass via request-header forgery, which had a recent expensive precedent in Next.js's own [CVE-2025-29927](https://github.com/advisories/GHSA-f82v-jwr5-mffw)) and started auditing.\n\n## What actually shipped\n\nSix probe families across roughly thirty live requests to four deployed test apps under `*.vinext.workers.dev`:\n\n```\n%2e%2e URL traversal in static asset paths\nx-middleware-request-* header forgery (CVE-2025-29927 vector)\nImage-optimizer SSRF via _next/image?url=\n.rsc suffix path-confusion against the middleware matcher\nInternal-header echo (x-vercel-forwarded-*, x-vinext-*)\nBody-content-type swap through middleware response handling\n```\n\nEvery primitive had a wrapper in source. The image optimizer goes through an allowlist plus origin check plus protocol check. The middleware loader explicitly rejects unknown exports, and the test suite asserts the throw. The static asset handler normalizes paths before serving. The CVE-2025-29927 vector ships with a hard reject for the documented header name plus a per-environment origin verification.\n\nThe defensive code paths cite specific advisories inline. `grep -r 'GHSA-' src/` returns hits like `GHSA-jcc7-9wpm-mj36` (origin-null bypass) and `GHSA-mq59-m269-xvcx` (CSRF) in defensive code paths. `grep -r '// Ported from Next.js:' src/` returns dozens of matches with `file:line` references back into the upstream test corpus. There's a `.nextjs-ref/` directory containing a clone of upstream Next.js for behavioral parity validation.\n\nThe thing the AGENTS.md describes _used to be true_. The codebase fixed it.\n\n## Why the inversion\n\nConfession density measures something real. It just doesn't measure unfixed bugs.\n\nA team that writes _\"we have repeatedly shipped fixes that diverged from Next.js\"_ is a team that knows what its bug-class history looks like. The next paragraph in the AGENTS.md is the protocol they instituted to stop the bleed: search the upstream test suite first, port the relevant tests. That protocol isn't decoration. It's wired into the contributor workflow, and the cite-density in the source confirms it.\n\nIf you map the confessions in AGENTS.md against the audit-surface of the deployed app, each one either has a defense at the audit point or it represents a known parity-gap that's been triaged into a backlog with a tracked work item. The case where a confession matches an unfixed audit-surface bug, the case I was hunting, didn't show up.\n\nWhat the confession actually predicts is dispositional maturity. The team can articulate which classes of bugs they used to ship. That articulation is paid for in time spent doing root-cause analysis, which is the same time you spend writing tests for the failure mode, which is the same time you spend hardening the surface against the next class. The team that confesses density is the team that did that work. The team that doesn't confess is either the team that hasn't shipped enough yet to know, or the team that shipped plenty and never looked back.\n\nReading AGENTS.md as a bug-density predictor inverts the actual correlation.\n\n## What to read instead\n\nA two-question replacement heuristic, both verifiable in five minutes of `grep`:\n\n```\n1. In security-sensitive modules (auth, middleware, URL parsing,\n   image-opt, deserialization, request validation), how often does\n   a defensive code path cite a specific CVE or GHSA by ID?\n\n2. Are there parity tests or vendored upstream-reference checks\n   against the closest reference implementation? (vinext: .nextjs-ref/;\n   a SAML library: against a named conformance suite; a TLS impl:\n   against the IETF test corpus.)\n```\n\nBoth yes: the confessions are retrospective documentation. Move on.\n\nBoth no: the confessions are a real density signal, the audit is worth running.\n\nOne yes, one no: investigate the asymmetry. The yes axis is the place where the bug is least likely. The no axis is the lane.\n\nThis isn't a kill rule. The lane still gets a binary-verdict first probe and runs to a clear outcome. But the rule should shift the dup-risk prior up and the tier-ceiling prior down for high-confession-density targets. Don't commit five sessions to a target where the second question comes back yes.\n\n## When the read flips\n\nThree cases where confession density does become a real bug-density signal:\n\n1. **Stale confessions.** AGENTS.md or CLAUDE.md sections that haven't been touched in 12+ months probably describe pre-fix state. Read the recent commit log first, then the docs.\n\n2. **Unfixed-and-untracked.** A confession that admits a bug with no cited issue, no work-item link, no commit reference. That's an explicit \"we know this is wrong and aren't tracking it\" signal, and it's different from \"we know this is wrong and #237 is the followup.\"\n\n3. **Selective confession.** The repo confesses one class loudly and is silent on a parallel class with obvious analogues. If the team writes a section on path-traversal but never mentions URL-parsing differences from upstream, audit URL-parsing.\n\nNone of these hit on vinext. The confessions were uniform, recent, cited in source with file paths, and the parity tests were present. So the lane closed.\n\n## Calibration\n\nI ran six probe families plus source-grep against the audit lens, not an exhaustive sweep. The next vinext audit might still pay if it picks a different lens (RSC payload handling under specific config combinations, cache surface under post-deploy edge config), but the AGENTS.md confessions wouldn't predict that and I should stop reading them as if they did.\n\nWhat burned was the planning step, not the audit itself. The fix is at the planning step.\n\n---\n\n_From a `cloudflare/vinext` audit, May 2026. The middleware-bypass hypothesis closed without a finding after ~30 live probes across four deployed test apps, source-grep clean across the parallel server implementations._\n", "creation_timestamp": "2026-05-18T11:49:53.000000Z"}