Salesforce’s widely used Node.js cookie library tough-cookie was found to contain a prototype pollution vulnerability (CVE‑2023‑26136) that affects every release before 4.1.3 when a CookieJar is created with the option
tough-cookie is a small but foundational library that implements RFC‑6265 cookie parsing, serialization, and a CookieJar abstraction for Node.js applications. It is commonly embedded inside HTTP clients, scrapers, automation tools, and many server-side integrations that need cookie handling. While the package itself is compact, libraries that depend on it inherit its behavior, making a flaw in cookie storage potentially far-reaching across the Node ecosystem.
The vulnerability was publicly disclosed in mid‑2023 and recorded in standard vulnerability databases; maintainers published a targeted fix and a release (v4.1.3) addressing the problem. The public advisories and vulnerability trackers consistently identify the trigger condition as using a CookieJar with
In tough-cookie’s memory cookie store, the code created nested plain objects to index cookies by domain and path. When CookieJar operates with
Why
The
Exploit complexity is low: no special privileges are required, and the attacker does not need human interaction once they can ensure a vulnerable CookieJar instance processes the malicious cookie. The biggest practical hurdle is finding an attacker-controlled channel to inject such a cookie into the target application’s cookie processing path. For some deployments — proxies, web scrapers, headless browser automation, or misconfigured backends that accept arbitrary Set‑Cookie values — that channel exists. Scanners and vulnerability trackers rate the impact as medium overall (CVSS 3.1: 6.5), with some vendor advisories flagging higher potential impact when combined with downstream issues.
Organizations should treat low‑level libraries in their SBOMs seriously: automated alerts, quick triage, and an established emergency patch workflow are essential. In many enterprise contexts the cost of a rapid update to a small package is far lower than the potential impact of letting a prototype‑pollution flaw remain unpatched. Advisory feeds and distribution maintainers have already integrated the fix into their supervised release streams.
CVE‑2023‑26136 is a reminder that even tiny utilities deserve rigorous scrutiny and that supply‑chain hygiene — inventory, scanning, and fast patching — remains one of the most effective defenses against subtle but exploitable software errors.
Source: MSRC Security Update Guide - Microsoft Security Response Center
rejectPublicSuffixes=false; the flaw allows specially crafted cookie domains (for example Domain=[B]proto[/B]) to leak or modify properties on JavaScript’s object prototype, and a stable fix was published in version 4.1.3.
Background
tough-cookie is a small but foundational library that implements RFC‑6265 cookie parsing, serialization, and a CookieJar abstraction for Node.js applications. It is commonly embedded inside HTTP clients, scrapers, automation tools, and many server-side integrations that need cookie handling. While the package itself is compact, libraries that depend on it inherit its behavior, making a flaw in cookie storage potentially far-reaching across the Node ecosystem.The vulnerability was publicly disclosed in mid‑2023 and recorded in standard vulnerability databases; maintainers published a targeted fix and a release (v4.1.3) addressing the problem. The public advisories and vulnerability trackers consistently identify the trigger condition as using a CookieJar with
rejectPublicSuffixes=false and cookies whose domain components are crafted to target object prototype keys.What happened — a plain‑English explanation
At the core of the issue is a common JavaScript pitfall: plain object literals ({}) inherit from Object.prototype. If an application stores untrusted keys directly on such an object, an attacker who can control those keys can write to special properties like [B]proto[/B], constructor, or prototype, thereby modifying the prototype used by many objects — this is prototype pollution.In tough-cookie’s memory cookie store, the code created nested plain objects to index cookies by domain and path. When CookieJar operates with
rejectPublicSuffixes=false, the library accepts cookies with public-suffix-like domains; an attacker who can get a victim to accept or process a cookie whose domain is [B]proto[/B] or another prototype name can cause the CookieJar implementation to assign properties into Object.prototype. Because those properties are then visible from otherwise independent objects, application code that later reads from or writes to those names can behave in unexpected and possibly dangerous ways. The original issue report and public proof‑of‑concept show exactly this pattern.Technical anatomy — where the code went wrong
The vulnerable pattern
The vulnerable store used nested plain objects to represent the cookie index:this.idx = {}— top-level domain mapthis.idx[cookie.domain] = {}— per-domain path mapthis.idx[cookie.domain][cookie.path] = {}— per-path cookie map
this.idx[cookie.domain] = {} is dangerous if cookie.domain equals [B]proto[/B] (or similar), because this.idx.[B]proto[/B] references the global prototype slot. Setting that slot effectively writes into Object.prototype, which is shared across the process. The original issue reporter included a short proof‑of‑concept demonstrating how setting a cookie with Domain=[B]proto[/B] creates a seemingly innocuous cookie entry while simultaneously causing a second object to gain new properties.Why rejectPublicSuffixes=false matters
The rejectPublicSuffixes option controls whether cookies with domains that are public suffixes (for example, .com, .co.uk, or other registry-controlled domains) are rejected. When this option is set to false, the CookieJar is more permissive and will accept cookies that would otherwise be rejected. Attackers can abuse this permissive setting to register or inject cookies with unusual domain strings, including the special tokens used to target prototypes. Several advisories and the upstream issue make clear that the exploit requires this permissive configuration.The fix (high level)
The maintainers fixed the issue by changing how internal maps were created so they no longer inherit fromObject.prototype. The straightforward hardening is to allocate objects with no prototype: Object.create(null). That change isolates stored keys from JavaScript’s prototype chain and prevents prototype slots like [B]proto[/B] from being hijacked via cookie domains. The corrected logic was released in v4.1.3.Proof‑of‑Concept and exploitability
A public proof‑of‑concept (PoC) demonstrates the attack pattern in a few lines: set a cookie withDomain=[B]proto[/B] using a CookieJar created with rejectPublicSuffixes=false, then observe that an independent plain object now appears to have properties it should not. The PoC is simple, deterministic, and automatable, which raises the real‑world risk profile for applications that expose cookie ingestion from untrusted sources (for example, proxied HTTP responses, user‑supplied headers, or forged requests).Exploit complexity is low: no special privileges are required, and the attacker does not need human interaction once they can ensure a vulnerable CookieJar instance processes the malicious cookie. The biggest practical hurdle is finding an attacker-controlled channel to inject such a cookie into the target application’s cookie processing path. For some deployments — proxies, web scrapers, headless browser automation, or misconfigured backends that accept arbitrary Set‑Cookie values — that channel exists. Scanners and vulnerability trackers rate the impact as medium overall (CVSS 3.1: 6.5), with some vendor advisories flagging higher potential impact when combined with downstream issues.
Risk assessment — what prototype pollution can lead to here
Prototype pollution is a meta vulnerability: by itself it alters object properties, but the real damage depends on how application code uses those properties. Typical follow‑on risks include:- Data integrity issues — polluted prototypes can change behavior of utility code that iterates or expects certain keys to be absent.
- Privilege escalation or logic bypasses — if code relies on object structure for authorization checks, prototype properties can subvert those checks.
- Denial of service — unexpectedly mutated prototypes may cause crashes or infinite loops in some code paths.
- Remote code execution (RCE) — while prototype pollution does not equate to RCE directly, in some complex applications polluted properties can be chained into code execution (for example, if polluting a function pointer, or influencing deserialization logic).
Who is affected
- Any Node.js application that includes a vulnerable tough-cookie version (< 4.1.3) and uses CookieJar instances created with
rejectPublicSuffixes=falseis directly affected. - Indirectly affected projects include any dependencies that vendor or depend on tough-cookie; package managers and enterprise distributions that ship the vulnerable version should update their package builds.
- Containerized services, web proxies, headless browsing automation, and server‑side scrapers are examples of components where CookieJar instances may be exposed to untrusted or attacker-controlled cookie inputs.
Practical remediation checklist — step by step
- Inventory
- Search code repositories for direct dependencies on
tough-cookieand for transitive references in lockfiles (package-lock.json, yarn.lock, pnpm-lock.yaml). - Scan containers and images for installed
tough-cookiepackages. - Upgrade
- For direct dependencies, update to at least tough-cookie@4.1.3. Example:
- npm:
npm install --save-exact [email]tough-cookie@4.1.3[/email] - yarn:
yarn add [email]tough-cookie@4.1.3[/email] --exact - For transitive dependencies, update the top‑level dependency that brings in tough-cookie or use tooling (npm/yarn resolutions, selective upgrades) to force the patched version.
- Temporary mitigations (only if you cannot immediately upgrade)
- Ensure
CookieJarinstances do not userejectPublicSuffixes=false. Prefer the defaulttruebehavior where possible. - Sanitize or validate incoming Set‑Cookie headers, rejecting cookies whose domain contains reserved prototype tokens such as
[B]proto[/B],constructor, orprototype. - Test
- Run unit and integration tests, and exercise cookie handling code paths.
- Verify that toxics (or Fuzzing harnesses) do not crash on malformed cookie domains.
- Deploy
- Roll out upgrades in stages with monitoring and quick rollback capability.
- Patch CI pipelines and container images to ensure builds use the fixed package.
- Monitor
- Look for anomalous cookie headers in logs: search for strings like
Domain=[B]proto[/B]or suspicious domain values. - Enable dependency scanning alerts and add
tough-cookieto your internal SBOM watchlist.
Detection guidance and forensic indicators
A small set of easily automatable detections will catch common exploitation attempts:- Log and alert on Set‑Cookie or Cookie header values containing
[B]proto[/B],prototype, orconstructorin the domain attribute. - In services that expose cookie ingestion endpoints, record raw Set‑Cookie strings for a brief window to allow retrospective review.
- Instrument test harnesses to run the public PoC against a staging CookieJar instance to confirm it is no longer vulnerable.
- Use dependency scanning tools (OSS scanners, SCA tooling) to flag versions earlier than 4.1.3 and to find transitive inclusions.
Domain=[B]proto[/B] are high‑value first steps in any incident investigation related to this vulnerability. Several advisories explicitly cite the PoC and recommend these same detection approaches.Why this matters for software supply chains
Even small, utility libraries like tough-cookie can be critical choke points in large dependency graphs. Prototype pollution is a classic example of a vulnerability that begins in innocuous code (cookie indexing) but can ripple outward into high‑impact problems when chained with other bugs or when an application’s logic assumes a clean prototype environment.Organizations should treat low‑level libraries in their SBOMs seriously: automated alerts, quick triage, and an established emergency patch workflow are essential. In many enterprise contexts the cost of a rapid update to a small package is far lower than the potential impact of letting a prototype‑pollution flaw remain unpatched. Advisory feeds and distribution maintainers have already integrated the fix into their supervised release streams.
Developer notes — secure coding and defensive patterns
- Never use untrusted strings as keys on plain objects that participate in shared state. Prefer
MaporObject.create(null)for ad‑hoc maps intended to carry arbitrary keys. - When you must accept client‑supplied domain values, canonicalize and validate them strictly: accept only legitimate hostnames and reject tokens that are not valid domain labels.
- Hardening primitives:
- Use
Object.create(null)to avoid prototype inheritance for internal maps. - Use
Mapwhen map semantics are needed and you want to avoid prototype interactions. - Where possible, adopt secure defaults: disable permissive options like
rejectPublicSuffixes=falseunless you have a concrete need.
Responsible disclosure, timeline and vendor response
The issue was reported and tracked upstream in the tough-cookie project, with a clear problem report and a small, targeted fix. The maintainers released version 4.1.3 that eliminates prototype inheritance from internal maps and addresses the root cause. Public vulnerability databases (NVD), security vendors (Snyk), and package advisory databases (GitHub Advisory Database) catalog the CVE and list the patched version. A public PoC has circulated, which is why operators are advised to treat the vulnerability as actionable even if widespread exploitation has not been reported.Putting the severity in context
Different security trackers assign different scores: the NVD entry records this as CVSS 3.1 = 6.5 (Medium), while some scanning feeds express higher impact ratings for specific deployment contexts. The right interpretation depends on where and how tough-cookie is used in your environment:- For a standalone web server that never processes untrusted Set‑Cookie headers, the practical risk is lower.
- For a proxy, scraper, or multi‑tenant middleware that processes cookies from arbitrary web sites or from users, the risk is higher because an attacker may be able to inject malicious cookies into the processing path.
Final recommendations — a short checklist for WindowsForum readers
- Audit: Search for tough-cookie in your projects’ dependency graphs and lockfiles.
- Patch: Upgrade direct and transitive dependencies to tough-cookie@4.1.3 or later as soon as possible.
- Harden: Move
CookieJarusage away fromrejectPublicSuffixes=falseunless necessary; sanitize incoming cookies. - Detect: Implement quick log searches for
Domain=[B]proto[/B]and similar prototype tokens. - Automate: Add this CVE to your automated dependency scanning and alerting rules so future regressions are caught early.
- Educate: Make prototype pollution a coding review talking point — it’s subtle and easily introduced.
CVE‑2023‑26136 is a reminder that even tiny utilities deserve rigorous scrutiny and that supply‑chain hygiene — inventory, scanning, and fast patching — remains one of the most effective defenses against subtle but exploitable software errors.
Source: MSRC Security Update Guide - Microsoft Security Response Center