CVE-2025-4609 is an insufficient-permissions check in Chrome's Mojo IPC layer. Google patched the original in Stable 136.0.7103.113 in May 2025, scored it 9.6 under CVSS 3.1 with vector AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H, and closed Chromium issue tracker entry 412578726. The vulnerability intelligence pipeline resurfaced the identifier on November 12, 2026, because five separate GitHub accounts, publishing under five separate repository slugs that each contain the exact string cve-2025-4609-mojo-poc, registered on scanner polling inside a 48-hour window. The scanner's reasons for raising the candidate's score to 11 included multi-poc×3+1. One of the five repositories now returns 404. The four that survive share the same git object history, the same author email addresses, and a report file whose §7 Limitations tells its own reader, in the researcher's words, Submit this as an incomplete-fix bug report, not as a confirmed sandbox escape / full-chain exploit, unless a real trigger is demonstrated first.
CVE-2025-4609: Chrome's Mojo Sandbox Escape Resurfaces With Five PoC Repositories. One Is A 404. Four Share The Same Git History. Their Author's Own Report Says Not To Call It A Sandbox Escape.
pattern
cve
proof of concept
multi-poc×3 counted repository namespace entries, not independent weaponizations
The scanner's grading rule summed five public PoC repositories against CVE-2025-4609 and rewarded the plural. The accounts, as they appeared in the scanner's poc_urls field:
nek-3231/cve-2025-4609-mojo-poc
r44029395/cve-2025-4609-mojo-poc
vobando007/cve-2025-4609-mojo-poc
santiagovillalobos6900-commits/cve-2025-4609-mojo-poc
vobando0077/cve-2025-4609-mojo-pocr44029395/cve-2025-4609-mojo-poc returns HTTP/2 404 as of this writing; the account or repository was deleted after the scanner's crawl. The four that remain live respond HTTP/2 200 and clone cleanly.
The four live clones are not forks. GitHub forks carry a parent reference and share the upstream's object database; these do not. They are four independent git push destinations fed from the same working tree. Compare sha256 on every source file:
=== README.md ===
6dbeda9b44dd4b1884a5229ad48f511257e41c3e44b277e464cdb30c872e4d43
=== IMPACT.md ===
5dc50409897a552cf9eb9b6290d08c64eff8538417b5cf0f8bad2b7d6a924c8c
=== poc.html ===
2ede83f9198da55d6527f4c06c304166da8a5dfc4cf00dfb6f7f3fd5cdc7ed26
=== poc_mojo_final.py ===
dbc45b4f912b97439581967b437825a6b9a5be3c0f24f37aad53bd612f4137c6
=== transport.cc ===
85e5ab4deb3363702cc60061ef8bfc32b93ed5f19b8fa9b477e5763886fe2981
=== vrp-report-v2.md ===
a0a649cbfd55ba9cb3ae2b3badaf70c707e78b13abf256980b39cf3ef9f4df27One hash per file across all four accounts. Byte-identical content, pushed to four GitHub namespaces, surfaced to a scanner as four independent PoCs.
The git log makes the republication explicit. The earliest commits, in each of the four live clones, are signed Victor Hugo Obando Gonzalez. (nek) <[email protected]> and were authored between 2026-11-06 and 2026-11-07 on the alexlingerie origin named inside vrp-report-v2.md. Later commits appear under nek-3231 <[email protected]> and r63737778-lab <[email protected]>, two different login handles against the same email. The 2026-11-12 commit sequence that produced the five scanner-visible repositories carries this commit message verbatim:
b9eb50e nek-3231 <[email protected]> 2026-11-12 mover PoC Mojo caso 4 a r63737778-labmover PoC Mojo caso 4 a r63737778-lab reads in Spanish as move the Mojo case-4 PoC to r63737778-lab. The commit documents, inside the git history the scanner never reads, the act of relocating the artifact from one of the author's accounts to another. vrp-report-v2.md §2 names santiagovillalobos6900-commits directly, as old V8 Codespace bookish-dollop-g4vvxv46x7953vppx (santiagovillalobos6900-commits), the second account the scanner summed. The scanner counted five surface names. The git history inside each of the four live surfaces counts one working tree, two email addresses belonging to a single researcher, and an explicit log entry labelling the move.
The researcher wrote Limitaciones honestas and then shipped it five times
Inside every one of those four live repositories, IMPACT.md carries this section:
## Limitaciones honestas
- Este test reproduce la logica en C++ y en Chrome 157 con MojoJS, no demuestra
aun una fuga de handles real en un proceso privilegiado.
- Falta un trigger Mojo real que entregue ese transport a Deserialize en Chrome.
Transport::Deserialize es C++ interno, sin interfaz publica MojoJS.
- Falta un primitivo V8 15.9 RW verificado (addrOf/fakeObj).
- ASAN exit 0: no hay error de memoria en el modelo. Es bypass de logica, no
corrupcion demostrada.
- Paso 5 (escape) sigue conceptual. No hay handle privilegiado ni RW demostrado.vrp-report-v2.md §7 Limitations is longer and more explicit:
1. Model reproduction, not a real ipcz trigger from the web. Transport::Deserialize
is internal C++ with no public MojoJS interface to call directly. poc.html /
mojo_157.html reproduce its logic in JS. They do not send a real ipcz transport
from a web page to the browser process.
2. No demonstrated handle leak / privileged read-write. Case 4 ACCEPT is shown in
the model, but no handle obtained from the browser process, and no privileged
file/process action, has been demonstrated in Chrome 157.
3. ASAN exit 0. No memory error was found in the model test.
4. Full chain is conceptual only.
5. V8 RW claim is not proven.
...
Submit this as an incomplete-fix bug report, not as a confirmed sandbox escape /
full-chain exploit, unless a real trigger is demonstrated first.The researcher knows what their artifact is and what it isn't. The researcher wrote the §7 that says so. The researcher then pushed that same IMPACT.md and vrp-report-v2.md to five GitHub namespaces whose names contain the CVE identifier the scanner was polling for. The pipeline downstream of the scanner reads has_poc: true and poc_urls: [...5...] and lifts the candidate above its publication threshold. The caveats inside the artifact never reach the pipeline. The pipeline reads the names.
The claim the author did build is a trust-matrix model against transport.h:114
The Mojo transport header cited in the repository is the current Chromium main source:
// transport.h:114
bool is_source_trusted() const {
return is_peer_trusted_ ||
(destination_type() == kBroker && source_type() != kBroker);
}The author's poc_mojo_final.py reproduces the surrounding Transport::Deserialize logic in Python and walks a five-case trust matrix against it. Case 4, in the author's labelling, is NonBroker recibe relay de Broker with from_src=kNonBroker, from_dst=kBroker, hdr=kBroker, peer_trusted=false, elevated=false. The disjunction in is_source_trusted() evaluates destination_type() == kBroker && source_type() != kBroker to true. Without is_elevated, is_source_at_least_as_privileged is also true. The header's destination_type == kBroker check in Deserialize passes. The transport is accepted.
The same case is re-run in transport_test.cc compiled with g++ -std=c++17 and again with -fsanitize=address,undefined. Both runs print RESULTADO: VULNERABLE - caso 4 ACCEPT vuln_count=1. The ASAN run's exit code is 0. No memory corruption. The author's own §4.3 notes that the ASAN exit does not prove a memory-safety exploit. The result is a logic bypass of a checker modelled in C++.
Case 4b, identical to case 4 but with is_elevated=True, prints REJECT OK in every reproduction. The author's proposed fix follows from that observation:
is_source_trusted = is_peer_trusted || (source_type()==kBroker && destination_type()==kNonBroker)The order of the operands reverses. destination_type == kBroker is no longer sufficient; the check now requires that the source is a Broker and the destination is a NonBroker. The author argues this closes case 4 in the model. The author also notes, in §7 point 1, that Transport::Deserialize has no public MojoJS entry point reachable from a renderer. The model is correct. The path from a web page to Transport::Deserialize is not demonstrated.
vrp-flag.json in every repository declares:
{
"flag": "read",
"params": {
"process": "browser",
"poc": "poc.html",
"chrome_version": "157.0.8103.38",
"os": "linux",
"arch": "x64",
"command_line": ["--enable-blink-features=MojoJS,MojoJSTest"]
}
}A real Mojo sandbox-escape PoC against Chrome does not require --enable-blink-features=MojoJS,MojoJSTest. That flag loads the test-only Mojo JS bindings that ship disabled in production builds. The flag is how renderer-side Mojo research gets conducted; it is also how a researcher admits that the scenario they modelled does not reach Mojo from a stock Chrome without it. poc.html run inside a browser launched with that flag executes a Python file's logic in JavaScript. The author's own note at the bottom of poc.html says so: Transport::Deserialize es C++ interno, no hay interfaz MojoJS publica para llamarlo directo. Esto reproduce su logica, no es un exploit en Chrome.
The pattern, this quarter, keeps counting the same way
CVE-2025-4609 is the third consecutive post this week whose scanner grade was wrong about the state of the PoC supply. CVE-2026-121529 landed on November 11 with a multi-poc count of two. One of the two was a Mastodon re-share whose linked article told its own readers No exploit code has been publicly released. The other was a README advertising ten source files that had never been committed. CVE-2026-125350 landed on November 10 with a multi-poc count of two. One of the two flagged patched Extended Stable users as vulnerable. The other named an affected-versions range that closed twenty months before the bug was reported. CVE-2025-4609 lands on November 12 with a multi-poc count of five, four of which share a git log and one of which is a 404.
The named pattern in our catalog is Placeholder PoC. The short description says, in part, A scanner polling GitHub for CVE-named repositories registers it as "PoC available"; the script's own comments confirm the registration is wrong. CVE-2025-4609 is the pattern expressed at the distribution layer rather than the code layer. The author's comments do not place placeholder parameters inside a would-be weaponizer. The author's comments do something harder to score: they describe, section by section, which steps of a full Mojo-plus-V8 chain have not been built, and then the author's output is republished across five namespaces whose names contain the CVE identifier the pipeline was polling for. The code inside is honest research. The folders those codes live in are a five-way broadcast of that research under a slug the scanner treats as a weaponization signal.
The distribution pattern is not malicious in the way a cve-as-lure ClickFix repo is malicious. The researcher has filed Chromium issue 536924725 against an adjacent Mojo bug ([Mojo] Apply recursion depth limit in MessageFragmentArrayTraits, P2/S2, status New) under the email that signs these commits. The researcher has a working relationship with the Chromium VRP that predates this upload. What the distribution pattern is, instead, is a documented example of what the scanner's multi-poc×3 edge actually measures when the person on the other end of the pipe is one researcher iterating across multiple accounts and codespaces. The scanner has no way to know that vobando007, vobando0077, nek-3231, santiagovillalobos6900-commits, and the deleted r44029395 are a single working researcher's publishing surfaces. The scanner has poc_urls.length >= 3 and a +1 on the candidate's score, and that is enough to lift a six-month-old patched Chrome bug into the breaking-publication slot.
The scanner counted names. The §7 counted limitations.
Both counts are correct. They are not counting the same thing. multi-poc×3+1 reads the width of the GitHub namespace that contains a CVE identifier; the researcher's §7 reads the depth of the technical chain that the artifact actually delivers. The scanner's grade of 11 for CVE-2025-4609 is honest about the width. The grade is silent about the depth because the depth lives inside the markdown files the scanner does not parse. The grade is also silent about the fact that one of the five name-widths has already deleted itself since the crawl.
The research is substantive. The author identified a case in transport.h:114's disjunction, built a reproducible model in Python, C++, C++ ASAN, and a flag-enabled Chrome 157 session, and proposed a two-operand reorder that closes the case in the model. The author also wrote, in §7 point 4 of their own report, Full chain is conceptual only. An incomplete-fix report is a legitimate contribution to a VRP program. A multi-poc×3+1 candidate score is a signal to a defender that the CVE is being actively weaponized. Those are not the same claim. When a single researcher's working tree reaches the scanner as five independent PoC repositories, the defender reads the louder claim and never sees the quieter one.
PoCs:
- nek-3231/cve-2025-4609-mojo-poc
- vobando007/cve-2025-4609-mojo-poc
- santiagovillalobos6900-commits/cve-2025-4609-mojo-poc
- vobando0077/cve-2025-4609-mojo-poc
r44029395/cve-2025-4609-mojo-poc(404 as of publication)
The scanner counted names. The §7 counted limitations. The defender reads the louder claim and never sees the quieter one.