Skip to main content

Fake CVE Reports: 54 of 55 SQLite Advisories Were AI Slop

Fake CVE reports are now cheaper to write than to disprove. JFrog found 54 of 55 SQLite advisories fabricated by an LLM. How to spot them before you patch.

12 min read
A fabricated CVE advisory flowing unverified into the public vulnerability database pipeline

Six critical SQLite vulnerabilities appeared in the public CVE feeds. One carried a CVSS score of 10.0. All six were fake CVE reports — advisories holding real, published CVE identifiers that describe code which does not exist. SQLite ships in every Android phone, every iOS device, every browser and most of the embedded world, so a genuine remote use-after-free in its expression parser would rank among the most consequential bugs of the year. This was not one.

JFrog’s security research team pulled the advisories apart and found the referenced functions did not exist in the versions named, the cited line numbers pointed past the ends of the files, and the supplied proof-of-concept payloads either failed to parse or ran to completion without crashing anything. Then they checked the rest of the GitHub account that filed them: 55 advisories published in four days, of which 54 were entirely fabricated. The one survivor was a real bug wrapped in CVE metadata nobody had verified either.

This is the moment the vulnerability pipeline stopped being merely slow and started being actively poisoned. And the mechanism is not a clever attack — it is arithmetic.

TL;DR

  • 54 of 55 advisories from a single GitHub account (programmervuln) were fabricated, spanning SQLite, libraw and ESP32-audioI2S. MITRE has since rejected the entire repository.
  • The six SQLite entries — CVE-2026-51302, -51303, -51300, -51297, -51296 and -51304 — claimed use-after-free bugs scored from 7.5 to 9.8. Red Hat initially rated one at 10.0, then downgraded it to 7.6.
  • Every advisory failed the same four checks: nonexistent functions, impossible line numbers, non-reproducing PoCs, and absence from SQLite’s own security page.
  • The cause is an effort asymmetry: generating a plausible advisory now costs approximately nothing, while verifying one still costs a code review, a build and a reproduction attempt.
  • The real damage is downstream. Automated remediation agents treat the CVE feed as ground truth, so a fake CVE report becomes a patch against code that does not exist.

What are fake CVE reports?

A fake CVE report is a vulnerability advisory that has been assigned a legitimate CVE identifier but describes a defect that does not exist in the affected software at all. It is not a disputed severity score, not a bug that turns out to be unreachable in practice, and not a duplicate. The vulnerability itself is fiction, and the identifier around it is real.

That distinction matters because the security industry already has a vocabulary for imperfect CVEs — disputed, unreachable, vendor-rejected — and all of it assumes a human looked at something real and drew the wrong conclusion. Fake CVE reports break that assumption. There is no underlying observation to argue about.

What makes them newly abundant is that large language models are extremely good at the form of a security advisory. The genre is highly templated: a function name, a memory-safety class, a call path, a line reference, a snippet of trigger input, a severity justification. A model that has read thousands of real advisories reproduces that structure convincingly while getting every specific fact wrong. JFrog ran the text through AI-detection tooling and it flagged as machine-generated, which is corroboration rather than proof — but the technical failures are not ambiguous.

What JFrog actually found

The six SQLite advisories all claimed use-after-free conditions in the expression and JSON handling code:

CVEClaimed CVSSClaimed flawReality
CVE-2026-513029.8 CriticalUAF in exprComputeOperands()Function does not exist
CVE-2026-513039.8 CriticalUAF via ExprListDelete() back-refsCode does not match claim
CVE-2026-513009.1 CriticalUAF in sqlite3ExprDelete()PoC does not reproduce
CVE-2026-512978.8 HighUAF via jsonBlobEdit()Line references invalid
CVE-2026-512967.5 HighUAF in jsonRemoveFuncNot in SQLite advisories
CVE-2026-513047.5 HighUAF in pOrderBy expression listPoC fails to parse

Four failure modes recur across all of them, and each one is individually disqualifying:

  1. The functions are not there. Some names never existed in SQLite; others were introduced years after the version the advisory names as vulnerable. A grep against a shallow clone settles this in seconds.
  2. The line numbers are impossible. Several citations point beyond the end of the file they name. Others land on comments or unrelated code.
  3. The proofs of concept do not work. The supplied SQL either failed at the parser or executed normally. Not “crashed differently” — nothing happened.
  4. SQLite’s own security page never listed them. The project that would have to ship the fix had no record of the issue.

None of these require deep expertise in SQLite’s internals. They require someone to look, once, before publication — which is precisely what nobody in the chain is resourced to do.

Why the pipeline let this through

MITRE accepts vulnerability submissions through a public web form with no identity verification and no requirement to demonstrate a reproducible proof of concept. Severity, in practice, is anchored to the submitter’s own account of impact. Once an identifier is minted, downstream consumers — vendor feeds, scanners, SBOM tools, GitHub Security Advisories — ingest it programmatically.

The manual layer that used to catch some of this is gone. NIST stepped back from full manual enrichment of NVD records in February 2024 under a submission volume it could not process, and The Register reports the unprocessed backlog grew from roughly 17,000 records in late 2024 to more than 27,000 by the end of 2025. Authorized Data Publishers absorbed some of the load, but they inherited the volume problem rather than solving it.

JFrog’s Afek Berger put the underlying dynamic in one sentence:

“Generative AI has lowered the effort required to produce a plausible-looking advisory to close to zero, while the effort required to verify one, review the source code, build the affected version, reproduce the PoC, is unchanged.”

That is the whole story. Every institutional defence in the CVE system was designed around an implicit cost model in which writing a convincing false advisory was expensive enough that few people would bother. That model is now void, and nothing has replaced it. Fifty-five submissions in four days from one account is not a sophisticated operation — it is an afternoon.

The part that should worry you: automated remediation

If fake CVE reports only wasted human attention, they would be an annoyance on the scale of spam. The reason this is a genuine security problem is what sits at the other end of the feed.

A growing share of vulnerability response is now automated. Scanners ingest CVE data, agents map it to dependencies, and increasingly those agents are expected to produce the fix — locate the vulnerable function, generate a patch, open a pull request. That pipeline is built on the assumption that a CVE record describes something that exists.

Hand a fabricated advisory to an LLM-driven remediation agent and it will not stop and say the function is missing. It will do what these systems always do under contradiction: find the nearest plausible match and proceed. The output is a real diff, against real code, addressing a bug that was never there — arriving in a pull request wearing the authority of a 9.8 CVSS score, into a queue where the reviewer is under pressure to merge security fixes quickly.

That is the same structural failure I wrote about in why your AI shouldn’t DM coworkers: an agent that cannot distinguish a claim from a fact will act on both with equal confidence, and the surrounding process treats its output as vetted because a machine produced it consistently. The AI agent that attacked a developer after a Matplotlib PR rejection was the loud version of this. Fake CVE reports are the quiet version, and the quiet version scales better.

The commenters on the Hacker News thread — 667 points, 299 comments — landed on a sharper framing: the CVE process has become a denial-of-service vector. Where policy, insurance or a compliance regime mandates “remediate all critical CVEs,” an attacker does not need a vulnerability. They need an identifier.

How to verify a CVE before you act on it

The good news is that the detection cost is low if you spend it deliberately. Run these in order and stop at the first failure:

  1. Does the function exist? git clone --depth 1, checkout the version named as vulnerable, grep for the symbol. This alone killed most of the SQLite set.
  2. Do the line numbers land inside the file? Open the file at the cited offset. If the file is shorter than the citation, you are done.
  3. Does the upstream project acknowledge it? Check the project’s own security page and commit history, not just the aggregator. Real fixes leave commits.
  4. Does the PoC reproduce on your own build? Not the reporter’s asciinema, not a screenshot — your build, your run.
  5. Who filed it, and what else have they filed? A submitter with dozens of advisories across unrelated projects in a single week is the signal that broke this case open.

For teams, the policy change matters more than the checklist: a CVE identifier is an unverified claim until someone reproduces it. Treat severity scores in automated feeds as a triage hint, not an SLA trigger. If your remediation agents open PRs directly from CVE data, gate them on step 1 — an automated existence check for the named symbol is trivial to implement and would have caught all six of these.

This is the same evidence-over-assumption discipline that the 138-repo AGENTS.md study demonstrated for agent configuration: the industry’s confident consensus about what works frequently does not survive somebody actually checking.

What has to change upstream

Three fixes, in ascending order of difficulty:

  • Require a reproducible PoC for memory-safety claims before assignment. Not review — just a submitted artifact and an assertion, which at least creates a falsifiable record.
  • Rate-limit and attribute anonymous submissions. Fifty-five advisories in four days from one unverified account should have tripped something.
  • Give CNAs and ADPs a fast rejection path with propagation. MITRE rejected this repository, but the downstream copies lag. Retraction has to travel as fast as publication, and right now it does not.

None of this requires solving AI detection, which is a losing arms race — the JFrog analysis did not need a classifier to conclude the advisories were false. It needed someone to check whether the code existed.

FAQ

What are fake CVE reports?

Fake CVE reports are vulnerability advisories that carry a real, published CVE identifier but describe a flaw that does not exist in the affected software. They are not the same as a disputed or over-scored CVE, where a genuine bug is argued about — the underlying defect is simply invented. The current wave is generated by large language models, which produce advisory prose, fake stack traces and plausible-looking proof-of-concept code faster than any human can review it.

How did fake SQLite CVEs get published with critical severity scores?

MITRE accepts vulnerability submissions through a public web form that performs no identity verification and does not require a reproducible proof of concept. Once an identifier is assigned, downstream databases and vendors ingest the record automatically, and severity is derived from the submitter’s own description of impact. That means an advisory can reach a 9.8 CVSS rating in public feeds without anybody having compiled the affected version, let alone reproduced a crash.

How can I tell if a CVE is real before patching?

Check four things in order: whether the named function actually exists in the affected version, whether the cited line numbers fall inside the file at all, whether the project’s own security page acknowledges the issue, and whether the supplied proof of concept reproduces on a build you made yourself. In the SQLite case every one of those checks failed, and the first two take about a minute each with a shallow git clone and grep.

Why are fake CVE reports especially dangerous for AI-driven remediation?

Automated triage and patching agents are built to trust the CVE feed as ground truth, so a fabricated advisory becomes a work order rather than a claim to evaluate. An agent asked to fix a use-after-free in a function that does not exist will not stop and report the contradiction — it will find the nearest plausible code, change it, and open a pull request. That converts a fake report into a real, unreviewed diff in your codebase.

Is this the same problem that hit curl’s bug bounty?

It is the same economics at a different point in the pipeline. curl shut its HackerOne bug bounty in February 2026 because AI-generated submissions were consuming maintainer triage time faster than genuine reports arrived, and its confirmed-vulnerability rate had fallen from above 15 percent to below 5 percent. In the SQLite case the slop skipped the maintainers entirely and went straight into the CVE database, which is worse — nobody with knowledge of the code ever saw it.

Does this mean the CVE system is broken?

It means the system’s one implicit assumption — that writing a convincing advisory costs real effort — no longer holds. The CVE pipeline was designed around scarce, expensive submissions and manual enrichment, and NIST stepped back from that manual analysis in February 2024 under a backlog that exceeded 27,000 records by the end of 2025. The identifiers are still useful; treating them as verified findings rather than unverified claims is the part that has to stop.

Final take

The instinct on reading this story is to blame the model, and that is the wrong lesson. No LLM decided to publish anything. A person pointed a generator at a submission form that asks for prose and returns authority, and the system did exactly what it was built to do — at a volume it was never built to withstand.

What died here is not the CVE system’s usefulness but its default trust setting. An identifier used to be weak evidence that a human with some knowledge of the code had looked at a problem. It is now evidence only that somebody filled in a form. That is a smaller thing, and everything downstream — scanners, compliance regimes, remediation agents, the engineer who gets paged at 2am about a 9.8 — is still priced for the larger one.

Reprice it now. Before you patch anything, confirm the function exists. It is the cheapest security control you will implement this year, and for these six advisories it was the only one that would have worked.

For more on where AI systems fail in security contexts, read the $100M model distillation attack next.

Sources

Share this article:
X LinkedIn

Keep reading

Get new posts on AI, Claude Code & LLMs

New deep-dives on AI engineering, Claude Code, and developer tooling — follow along however you prefer.