In February 2023, the maintainers of tough-cookie — the cookie-parsing and cookie-jar library that ships inside request, request-promise, puppeteer-adjacent tooling, cheerio-based scrapers, and countless other Node.js HTTP clients — quietly shipped a fix for a prototype pollution flaw that would later be tracked as CVE-2023-26136. Because tough-cookie is almost never installed directly (it rides in as a transitive dependency, often several layers deep), the vulnerability sat unnoticed in production dependency trees for months after the patch existed. That gap between "fix available" and "fix applied" is exactly the kind of blind spot that turns a medium-severity library bug into an organization-wide remediation scramble.
CVE-2023-26136 affects how tough-cookie's CookieJar indexes cookies internally when rejectPublicSuffixes is disabled. Under the hood, tough-cookie's memory store keys its internal lookup object by cookie domain. When public-suffix rejection is turned off, an attacker-supplied domain value such as __proto__ is accepted without sanitization and used directly as an object key. Because the store used a plain JavaScript object rather than a null-prototype object or Map, writing to that __proto__ key doesn't create a new property — it reaches through to Object.prototype itself. From there, an attacker who can influence a cookie's domain (for example, via a malicious HTTP response processed by a scraper, crawler, or automated HTTP client) can inject arbitrary properties onto every object in the running process that inherits from Object.prototype. In practice that means denial of service is the most reliably achievable outcome, and — depending on what downstream "gadgets" the polluted properties happen to interact with (template engines, ORMs, config mergers, child_process argument builders, etc.) — remote code execution or authorization bypass become plausible secondary impacts.
Affected versions and components
- Vulnerable:
tough-cookieversions prior to 4.1.3, including the older 2.x and 3.x release lines. - Fixed in:
tough-cookie@4.1.3, which replaced the plain-object index with anull-prototype-safe structure and hardened domain validation so suffix-style keys like__proto__can no longer be written into the store. - Indirect exposure: the vulnerability rarely shows up as a direct
package.jsondependency. It is far more commonly pulled in transitively through the deprecatedrequest/request-promise/request-promise-nativepackages, throughcheerio-based scraping stacks, through browser-automation and testing tool chains (Cypress, older Puppeteer/Selenium wrapper packages), and through any internal SDK or CLI that still resolves an oldtough-cookievia a stale lockfile. - Trigger condition: exploitation requires the application to construct a
CookieJarwithrejectPublicSuffixes: false(or to consume such a jar via a dependency that sets this option) and to process cookies from an untrusted or attacker-influenced source, such as scraping arbitrary third-party sites or following redirects to attacker-controlled hosts.
Severity, exploitability, and real-world exposure
NVD scored CVE-2023-26136 as CVSS 3.1 Medium (6.5), reflecting a network-exploitable, low-complexity attack that requires no privileges or user interaction but is scoped to an integrity impact — the attacker can modify state (via prototype pollution) without directly reading confidential data or crashing availability outright. That "Medium" label undersells the risk in practice: prototype pollution scores are notoriously hard to rate consistently because the real-world blast radius depends entirely on what the consuming application does with a polluted Object.prototype, not on tough-cookie in isolation. A scraper that merges HTTP-derived data into a config object, or a service that later does JSON.parse-and-merge on tainted data, can turn this "Medium" library bug into a critical application-level vulnerability.
On the exploit-likelihood side, EPSS scoring for this CVE has stayed low relative to headline vulnerabilities like Log4Shell — consistent with the fact that public, weaponized proof-of-concept exploit chains against real production targets have not been widely reported, and the CVE does not currently appear in CISA's Known Exploited Vulnerabilities (KEV) catalog. That combination — no confirmed active exploitation, but a very large and often-invisible dependency footprint — is precisely the profile security teams should treat as "quietly urgent": low noise today, high potential cost if an application-specific gadget chain surfaces later, and a long tail of stale transitive installs that dependency-graph scanners keep re-flagging for years after the fix shipped.
Timeline
- ~Early February 2023 — tough-cookie maintainers merge a fix hardening the internal cookie store and domain validation; version 4.1.3 is published to npm.
- February 2023 — GitHub Security Advisory GHSA-72xf-g2v4-qvf3 is opened, documenting the prototype pollution root cause and confirming 4.1.3 as the patched release.
- First half of 2023 — CVE-2023-26136 is reserved and subsequently published in NVD, formally cataloguing the issue for vulnerability scanners and SCA tooling.
- Mid-to-late 2023 — the CVE gains wider visibility as automated dependency scanners (Dependabot, Snyk, GitHub code scanning, npm audit) begin flagging it broadly across repositories that depend on the long-deprecated
requestpackage, which never received a first-party patch for its bundled tough-cookie version. Becauserequestwas deprecated in 2020 and receives no further releases, any project still using it inherits the vulnerable tough-cookie transitively unless a lockfile override is applied manually. - Ongoing — the CVE continues to surface in SCA scan results years later, primarily in legacy codebases, CI images, and internal tools that pinned dependency versions long before the fix existed and have not refreshed lockfiles since.
Remediation steps
- Identify every occurrence, not just the top-level one. Run
npm ls tough-cookie,yarn why tough-cookie, orpnpm why tough-cookieacross every service, CLI tool, and CI image in your estate. Because this library is almost always transitive, a singlenpm auditon one repository is not sufficient — check monorepo workspaces, internal SDKs, and containerized build tooling separately. - Upgrade to
tough-cookie@4.1.3or later wherever it appears as a direct dependency. Note that 4.1.3 raised the minimum supported Node.js version, so validate your runtime compatibility before bumping in CI. - Force the resolution when the vulnerable version is transitive. If an unmaintained dependency such as
requestpins an old tough-cookie internally, useoverridesin npm 8.3+/package.json,resolutionsin Yarn, orpnpm.overridesin pnpm to force the entire dependency tree onto the patched version without waiting for the upstream package to update. - Retire the
request/request-promisefamily outright where possible. These packages have been deprecated since 2020 and will not receive further security patches; migrating toundici, nativefetch, oraxiosremoves this entire class of "silently stale transitive dependency" risk going forward, not just this one CVE. - Explicitly set
rejectPublicSuffixes: trueon anyCookieJaryour own code constructs, and validate or normalize any domain/cookie values derived from untrusted HTTP responses before they reach cookie-handling code — defense in depth in case a future dependency reintroduces similar logic. - Add generic prototype-pollution guardrails. Where feasible, run services with hardened object handling (for example,
Object.freeze(Object.prototype)in appropriate contexts, or Node's--disable-proto=throwflag) so that even an undiscovered pollution vector elsewhere in your dependency graph fails safely instead of silently mutating shared state. - Refresh lockfiles and rebuild CI/base images. Vulnerable versions frequently persist in cached Docker layers and old lockfiles well after
package.jsonranges technically allow the fix — a version bump in the manifest without a lockfile refresh and rebuild leaves the old binary in place. - Re-scan after remediation to confirm the patched version resolves everywhere, including inside build-time and test-time dependency trees that don't ship to production but still run untrusted network code (test fixtures, integration harnesses, scraping jobs).
How Safeguard Helps
Finding every instance of tough-cookie across dozens of repositories, transitive dependency layers, and CI images is the hard part of this CVE — patching it is easy once you know where it lives. Safeguard's SBOM generation and ingest pipeline continuously maps every direct and transitive dependency across your codebase and container images, surfacing exactly which services, tools, and internal SDKs still resolve a pre-4.1.3 tough-cookie, including copies buried under deprecated packages like request. Our reachability analysis engine goes a step further than a version match: it determines whether your application actually constructs a CookieJar with public-suffix rejection disabled and processes untrusted cookie data, so your team can prioritize the handful of genuinely exploitable paths instead of triaging every flagged dependency with equal urgency. Griffin, Safeguard's AI security agent, correlates that reachability context with your runtime and deployment topology to produce a plain-language risk explanation and a suggested remediation path for each affected component. Where the fix is a straightforward version bump or an overrides/resolutions entry, Safeguard can open an auto-fix pull request directly against the affected manifest and lockfile, so the vulnerable transitive dependency gets pinned to the patched release without a human having to manually chase down every occurrence across the org.