Locutus Prototype Pollution due to incomplete fix for CVE-2026-25521
Summary
A prototype pollution vulnerability exists in the parse_str function of the npm package locutus. An attacker can pollute Object.prototype by overriding RegExp.prototype.test and then passing a crafted query string to parse_str, bypassing the prototype pollution guard.
This vulnerability stems from an incomplete fix for CVE-2026-25521. The CVE-2026-25521 patch replaced the String.prototype.includes()-based guard with a RegExp.prototype.test()-based guard. However, RegExp.prototype.test is itself a writable prototype method that can be overridden, making the new guard bypassable in the same way as the original — trading one hijackable built-in for another.
Package
locutus (npm)
Affected versions
= 2.0.39, <= 3.0.24
Tested and confirmed vulnerable on 2.0.39 and 3.0.24 (latest). Version 2.0.38 (pre-fix) uses a different guard (String.prototype.includes) and is not affected by this specific bypass.
Description
Details
The vulnerability resides in parse_str.js where the RegExp.prototype.test() function is used to check whether user-provided input contains forbidden keys:
if (/__proto__|constructor|prototype/.test(key)) {
break
}
The previous guard (fixed in CVE-2026-25521) used String.prototype.includes():
if (key.includes('__proto__')) {
break
}
The CVE-2026-25521 fix correctly identified that String.prototype.includes can be hijacked. However, the replacement guard using RegExp.prototype.test() suffers from the same class of weakness — RegExp.prototype.test is a writable method on the prototype chain and can be overridden to always return false, completely disabling the guard.
The robust fix is to use direct string comparison operators (===) in native control flow (for/if) instead of prototype methods like RegExp.prototype.test(), since === is a language-level operator that cannot be overridden.
PoC
Steps to reproduce
- Install locutus using
npm install locutus - Run the following code snippet:
const parse_str = require('locutus/php/strings/parse_str');
// Hijack RegExp.prototype.test (simulates a prior prototype pollution gadget)
const original = RegExp.prototype.test;
RegExp.prototype.test = function () { return false; };
// Payload
const result = {};
parse_str('__proto__[polluted]=yes', result);
// Check
RegExp.prototype.test = original;
console.log(({}).polluted); // 'yes' — prototype is polluted
Expected behavior
Prototype pollution should be prevented and ({}).polluted should print undefined.
undefined
Actual behavior
Object.prototype is polluted. This is printed on the console:
yes
Impact
This is a prototype pollution vulnerability with the same impact as CVE-2026-25521. The attack requires a chaining scenario — an attacker needs a separate prototype pollution gadget (e.g., from another npm package in the same application) to override RegExp.prototype.test before exploiting parse_str. This is realistic in Node.js applications that use multiple npm packages, where one package's vulnerability can disable another package's defenses.
Any application that processes attacker-controlled input using locutus/php/strings/parse_str may be affected. It could potentially lead to:
- Authentication bypass
- Denial of service
- Remote code execution (if polluted property is passed to sinks like
evalorchild_process)
Resources
- Original advisory: https://github.com/locutusjs/locutus/security/advisories/GHSA-rxrv-835q-v5mh
- Fix commit (incomplete): https://github.com/locutusjs/locutus/commit/042af9ca7fde2ff599120783e720a17f335bb01c
- Vulnerable file: https://github.com/locutusjs/locutus/blob/main/src/php/strings/parse_str.js#L77
Maintainer response
Thank you for the follow-up report. This issue was reproduced locally against locutus@3.0.24, confirming that the earlier parse_str guard was incomplete: if RegExp.prototype.test was already compromised, the guard could be bypassed and parse_str('__proto__[polluted]=yes', result) could still pollute Object.prototype.
This is now fixed on main and released in locutus@3.0.25.
Fix Shipped In
- PR: locutusjs/locutus#597
- Merge commit on
main:345a6211e1e6f939f96a7090bfeff642c9fcf9e4 - Release: v3.0.25
What the Fix Does
The new fix no longer relies on a regex-prototype guard for safety. Instead, src/php/strings/parse_str.ts now rejects dangerous key paths during parsed-segment assignment, so the sink itself is hardened even if RegExp.prototype.test has been tampered with beforehand.
Tested Repro Before the Fix
- Override
RegExp.prototype.testto always returnfalse - Call
parse_str('__proto__[polluted]=yes', result) - Observe
({}).polluted === 'yes'
Tested State After the Fix in 3.0.25
- Dangerous key paths are skipped during assignment
- The same chained repro no longer pollutes
Object.prototype - The regression is covered by
test/custom/parse_str-prototype-pollution.vitest.ts
The locutus team is treating this as a real package vulnerability with patched version 3.0.25. The vulnerable range should end at < 3.0.25.
Czego dotyczy
Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.
| Platforma | Paczka | Podatne wersje | Poprawka w wersji |
|---|---|---|---|
| Paczka npm | locutus | >= 2.0.39, < 3.0.25 | 3.0.25 |
Odnośniki
- https://github.com/locutusjs/locutus/security/advisories/GHSA-rxrv-835q-v5mh
- https://github.com/locutusjs/locutus/security/advisories/GHSA-vc8f-x9pp-wf5p
- https://nvd.nist.gov/vuln/detail/CVE-2026-33994
- https://github.com/locutusjs/locutus/pull/597
- https://github.com/locutusjs/locutus/commit/345a6211e1e6f939f96a7090bfeff642c9fcf9e4
- https://github.com/locutusjs/locutus
- https://github.com/locutusjs/locutus/releases/tag/v3.0.25
- Wektor CVSS
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N- Słabość (CWE)
CWE-1321- Platforma
- npm
- Paczka
locutus- Ujawniono
- 27.03.2026
- Aktualizacja
- 11.10.2026 10:22
Źródła i licencje
OSV / GitHub Advisory Database - GHSA-vc8f-x9pp-wf5p - CC BY 4.0
Historia podatności: locutus
Wszystkie opisane podatności tej paczki (Paczka npm), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.
- Wszystkich wpisów
- 8
- Pierwsza → ostatnia
- 05.2021 03.2026
- Bez poprawki
- 1
- Wykorzystywana w atakach
- 0
Rozkład istotności
- Krytyczna 4
- Wysoka 2
- Średnia 2
Ujawnienia w latach
- 2021: 3
- 2022: 0
- 2023: 0
- 2024: 0
- 2025: 0
- 2026: 5
-
Locutus Prototype Pollution due to incomplete fix for CVE-2026-25521 ten wpis
Dowiedz się, które podatności dotyczą Twojej aplikacji
Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.