//nefariousplan

CVE-2026-34621 Revisited: The 136-Day Detection Lie

pattern

cve

proof of concept

On November 28, 2025, someone uploaded a PDF to VirusTotal. The filename was Invoice540.pdf. Thirteen of sixty-four antivirus engines flagged it. The other fifty-one saw a document.

The person who noticed was Haifei Li, founder of EXPMON. He pulled it apart and wrote down what he found.

"The sample acts as an initial exploit with the capability to collect and leak various types of information, potentially followed by remote code execution and sandbox escape exploits. It abuses zero-day/unpatched vulnerability in Adobe Reader that allows it to execute privileged Acrobat APIs, and it is confirmed to work on the latest version of Adobe Reader."

The latest version of Adobe Reader. In November 2025.

That bug didn't get a name until April 12, 2026. On that day, Adobe shipped APSB26-26 and assigned CVE-2026-34621. Between the VirusTotal upload and the patch: 136 days. In that window, someone was sending invoice-themed PDFs to Russian oil and gas targets, and anyone who opened one ran code inside the boundary Adobe had sold them as a sandbox.

This is not a story about prototype pollution. It is a story about how long prototype pollution ran before anyone called it that.

The 136-day detection gap

The VirusTotal upload was not secret. It is a public hash registry. Anyone searching for suspicious PDFs targeting Adobe Reader on November 28 could have found the sample, read the 13-of-64 detection score, and pulled the hash. Li did. He published the mechanism on his blog: privileged Acrobat APIs invoked from obfuscated JavaScript in the document's open handler, confirmed on the latest Adobe Reader release. Exfiltration went to 169.40.2[.]68:45191.

Four months later, on March 23, 2026, a second sample landed on VirusTotal. Same mechanism, same shape. Researcher Gi7w0rm observed that the PDFs carried Russian-language lures and referenced current events in Russia's oil and gas sector. The campaign had not stopped. It was not a one-shot.

On April 12, 2026, Adobe shipped APSB26-26 and assigned CVE-2026-34621. CVSS 9.6, critical. The advisory-speak that travels with Adobe's Acrobat bulletins, visible in the APSB26-44 update issued two days later for the same product family, is the phrase the industry reads as routine: "not aware of any exploits in the wild." The VirusTotal hashes had been saying otherwise since November.

This is where defender math is supposed to happen. An organization deciding what to patch first reads the CVSS score, reads the exploitation status, reads the advisory, and ranks the queue. When the advisory says no known exploits and the vulnerability class is prototype pollution in a scripting engine, an ops team reasonably ranks it below vulnerabilities with active in-the-wild reports. That is the design of patch prioritization. The advisory text is the signal.

For 136 days, the signal was wrong.

Adobe was not hiding. The PSIRT was behind the signal defenders had already paid for. VirusTotal had the hash and the detection gradient. Li had the mechanism writeup. Gi7w0rm had the targeting. None of it reached the advisory text. Every defender who trusted the vendor's awareness apparatus as a threat-assessment input was, for nearly five months, reading a document that did not reflect what was happening.

The mechanism was not the bottleneck

The mechanism is not exotic. A PDF can carry JavaScript in an open-action handler. Adobe's EScript runtime is a sandboxed JS environment with access to a subset of Acrobat's own APIs, enough to do form validation, field scripting, digital signature flows. The sandbox is the boundary. Behind it sit privileged APIs that can read files, make network calls, invoke OS operations.

A JavaScript prototype chain is shared state. Every object in a running JS context inherits from Object.prototype unless explicitly told otherwise. If attacker code mutates a property on Object.prototype, adding a field or overwriting one, every object in the runtime sees the attacker's value as though it were native. Code that reads someObject.hasOwnProperty or inspects a polyfilled method against the prototype now reads what the attacker wrote.

The Acrobat sandbox's trust checks are JavaScript code. They read from objects. Those objects inherit from the prototype the attacker just polluted. The boundary between "scripted form logic" and "privileged Acrobat API" is enforced by a JS check reading from state the attacker can mutate. Pollute the state, the check reads a lie, the privileged API runs.

That is the class. CVE-2026-34621, per Adobe's bulletin, is exactly that class: Improperly Controlled Modification of Object Prototype Attributes, CWE-1321, leading to arbitrary code execution. The exploit chain reported in Invoice540.pdf is the class run in production: obfuscated JS on document open, privileged API execution, exfiltration, secondary payload delivery. Confirmed against the latest Adobe Reader release in November 2025.

A public proof-of-concept now exists. NULL200OK/cve_2026_34621_advanced on GitHub is a cross-platform exploit generator for the class. It produces PDFs that perform the prototype mutation, walk the trust-check chain, and land in privileged Acrobat API territory on Windows and macOS. The code is there. Anyone who wants to understand exactly which property descriptors Adobe failed to freeze can read it.

Adobe's fix for CVE-2026-34621 shipped in APSB26-26. Two days later, APSB26-44 patched two more CWE-1321 bugs in the same Acrobat product family: CVE-2026-34622 (arbitrary code execution) and CVE-2026-34626 (arbitrary file system read). The engineering team did not find one polluting call. They found a family of them. The remediation is the right shape. Freeze the prototypes that the sandbox's trust checks read from. Move security invariants into property descriptors that user-supplied JS cannot overwrite. Audit every check that reads from a mutable prototype chain. The fix is specific and mechanical.

None of that required the patch to exist before it could be written down. Li wrote the mechanism up on November 28 of the prior year, four and a half months before Adobe's engineering team shipped the fix. The mechanism was not hidden. It was not ambiguous. It was not undetectable. It was available, in public, to any defender or vendor who cared to read VirusTotal on the day the hash landed.

The reason the signal was wrong for 136 days is not that the mechanism was hard to understand. It is that the two pipelines producing the signal operate on different evidence standards. Community telemetry reports what it sees: a hash on VirusTotal, a 13-of-64 detection score, a researcher's writeup, an exfil IP. PSIRT advisory text reports what the vendor can confirm through its own evidence chain: private incident reports from customers, internal reverse-engineering of an in-flight campaign, attribution it will stand behind. The first pipeline closed on November 28, 2025. The second did not close until April 12, 2026.

A defender consuming PSIRT text as a threat-assessment input is reading a document that says, in effect, "no evidence the vendor will confirm." The defender thinks they are reading "no exploitation in the wild." Those are not the same sentence. They were, for this bug, 136 days apart.

Trust Inversion at the detection layer

The pattern this fits is Trust Inversion.

The site has written about it before. Authorization tools become the authorization-attack surface. Credential-management systems become credential-exfiltration channels. Revocation infrastructure lags compromise detection. The shape is always the same. A component the defender paid for, as a piece of their security program, turns out to be the component the adversary is operating through.

The Adobe case extends the pattern to the meta-layer. It is not the Acrobat sandbox that got inverted, though it did. It is the detection apparatus around the sandbox. The advisory text a defender reads to decide whether a PDF bug is urgent. The "no known exploits" flag a procurement team reads to justify a patch-window delay. The CVSS exploitation-status field that feeds into a ticket's priority lane. All of these are run by the same vendor whose product is the thing being exploited. The vendor's institutional incentive is to not confirm "exploitation in the wild" until they control the narrative. The defender's assumption is that "no known exploits" means no known exploits.

Those are not the same sentence. They are never the same sentence. For 136 days on CVE-2026-34621, the gap between them was the gap between "your oil and gas executives' laptops are already owned" and "read the bulletin on Tuesday."

Adobe is not uniquely at fault. Every vendor's advisory text operates on this standard. That is the point. A defender's threat-assessment pipeline cannot be built on top of the vendor's willingness to stand behind a claim. That is not a detection pipeline. It is a legal-and-PR pipeline. Treating it as detection is the inversion.

The five months weren't a detection failure. They were a detection lie. Every defender in the blast radius was told the boundary held, and every one of them was wrong.