Jul 29, 2026·6 min read·4 visits
style-dictionary is vulnerable to prototype pollution via convertTokenData. An incomplete patch in v5.4.4 can be bypassed using constructor.prototype, allowing global runtime pollution.
A critical prototype pollution vulnerability (CVE-2026-54639) exists in style-dictionary versions 4.3.0 through 5.4.3 due to unsafe object traversal in the convertTokenData utility. Although a patch was released in version 5.4.4 targeting '__proto__', a complete bypass is possible using 'constructor.prototype', leading to persistent global prototype pollution and potential remote code execution.
The NPM package style-dictionary serves as a build system to translate design tokens across platforms, including Sass, iOS Swift, and Android XML. The utility function convertTokenData is exposed to allow conversion between flat arrays, objects, and maps. This utility introduces an entry point for processing structure-modifying token properties, elevating the attack surface.
During translation, a flat structure containing malicious token keys can manipulate the global prototype chain. The vulnerability belongs to the class of Improperly Controlled Modification of Object Prototype Attributes (CWE-1321). This vulnerability was introduced in version 4.3.0 and remained present in subsequent releases.
In scenarios where style-dictionary executes dynamically within web applications, CI/CD runners, or continuous deployment pipelines that process user-defined styles, the threat vector shifts from local execution to arbitrary execution. This vulnerability exposes the host runtime to remote exploit opportunities depending on downstream object evaluation practices.
The core flaw resides in lib/utils/convertTokenData.js within the convertToTokenObject utility. When a user instructs the engine to export token data as an object format (output: 'object'), the application processes an array of tokens and reconstructs a nested object based on the property paths in the token's key property.
The logic parses keys by stripping curly braces and splitting the remaining string with a dot (.) separator. The engine then recursively traverses a base object literal obj = {} using the split path segments. If a path segment points to an inherited property (such as __proto__ or constructor), the traversal code fails to safely isolate modifications to own-properties of the object.
// Vulnerable snippet of path resolution
if (slice[k] === undefined) {
slice[k] = {};
}Because __proto__ evaluates to the standard Object.prototype (and is therefore not undefined), the assignment block is skipped, and slice is updated to point directly to Object.prototype. The subsequent loop iteration then assigns values directly to the global prototype, affecting every object instance within the Node.js runtime environment.
The introduction of the vulnerable utility occurred in commit 209085d9782cfc0783c4d983f3f1bb2c515954ec. The original vulnerable structure recursively assigned paths using arbitrary user input without sanitization.
// Vulnerable function in lib/utils/convertTokenData.js (v4.3.0)
function convertToTokenObject(tokenArray) {
const obj = ({});
tokenArray.forEach((token) => {
const { key } = token;
const keyArr = (key).replace('{', '').replace('}', '').split('.');
let slice = obj;
keyArr.forEach((k, i, arr) => {
if (slice[k] === undefined) {
slice[k] = {};
}
if (i === arr.length - 1) {
slice[k] = token;
}
slice = slice[k];
});
});
return obj;
}In version 5.4.4, the library attempted to mitigate the issue via commit 23b5e8dda143441f0d6b8e2b4222e2da98058bc5 by introducing a check: if (key?.includes('__proto__')) { return; }.
This remediation relies on blacklist-based input validation, which is vulnerable to alternative property traversal paths. An attacker can completely bypass this check by supplying a key such as {constructor.prototype.polluted_property}. In this scenario, the string verification fails to trigger the exit condition, while the inner traversal evaluates slice['constructor'] (the Object constructor function) and slice['constructor']['prototype'] (the global Object.prototype), achieving identical prototype modification.
To exploit this vulnerability, an attacker must control or inject content into a design token structure processed by style-dictionary. This typically occurs when applications accept user-defined themes, external configuration packages, or user-submitted asset bundles.
The attack begins by crafting a payload structure where the key field points to a prototype path. The diagram below illustrates how the recursive path resolver traverses from an empty object through the constructor function to reach and modify the global Object.prototype namespace.
This sequence bypasses the __proto__ blacklist guard and injects the attacker-defined token structure directly into the global object prototype. Consequently, any plain JavaScript object subsequently initialized during the application's lifecycle will inherit the malicious properties.
A successful prototype pollution attack in a Node.js runtime has broad security implications. An attacker who is able to inject properties into the standard prototype chain can disrupt application workflow logic, cause Denial of Service (DoS) via crash conditions, or execute arbitrary code.
In Node.js applications, remote code execution (RCE) can be achieved by polluting options passed to sub-process creation functions. If the application or its dependencies spawn shell commands using APIs like child_process.spawn or child_process.fork, parameters such as shell, env, or execArgv can be polluted. This forces the underlying operating system interpreter to execute arbitrary code defined in the payload.
The CVSS v3.1 metric is rated as 8.8 (High) under local execution contexts. However, if style-dictionary functions within an automated SaaS environment or dynamically processes user uploads online, the impact shifts to an unauthenticated Remote Code Execution vulnerability.
To secure applications using style-dictionary, relying on string-based blacklists is insufficient. The most robust remediation involves preventing keys that do not belong to the object's own properties from being recursively resolved, or using null-prototype objects.
The inner resolver must explicitly block the keys __proto__, constructor, and prototype. A structurally sound implementation of the convertToTokenObject utility would resemble the following pattern:
function secureConvertToTokenObject(tokenArray) {
// Create a base object that does not inherit from Object.prototype
const obj = Object.create(null);
tokenArray.forEach((token) => {
const { key } = token;
if (typeof key !== 'string') return;
const keyArr = key.replace('{', '').replace('}', '').split('.');
let slice = obj;
for (let i = 0; i < keyArr.length; i++) {
const k = keyArr[i];
// Enforce strict property checks to block traversal paths
if (k === '__proto__' || k === 'constructor' || k === 'prototype') {
return;
}
if (slice[k] === undefined) {
slice[k] = {};
}
if (i === keyArr.length - 1) {
slice[k] = token;
}
slice = slice[k];
}
});
// Convert back to standard object structure safely if downstream consumption requires it
return Object.assign({}, obj);
}For temporary runtime mitigation where dependency updates are restricted, implement validation schemas using JSON Schema or restrict incoming token keys via matching regex patterns like /("key"\s*:\s*"{.*(?:__proto__|constructor|prototype).*}")/ before passing inputs to the builder.
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
style-dictionary Amazon | >= 4.3.0, <= 5.4.3 | 5.4.4 (Incomplete fix) |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1321 |
| Vulnerability Class | Prototype Pollution |
| CVSS v3.1 Score | 8.8 (High) |
| Attack Vector | Local (escalatible to Remote) |
| EPSS Score | 0.00132 (3.12 percentile) |
| Patch Status | Incomplete (v5.4.4 bypass identified) |
| CISA KEV Status | Not listed |
The software initializes or populates an object with user-controlled keys or paths without restricting modifications to the object prototype, allowing attackers to inject or modify properties of the global Object prototype.
A critical path traversal vulnerability (CWE-22) in openhole-server version 0.1.1 and earlier allows remote, unauthenticated attackers to traverse directories and access restricted files or endpoints on local backend services exposed via the tunnel proxy. The issue stems from improper handling of decoded URL paths inside the proxy handler, which are then reconstructed and executed literally by the CLI client.
CVE-2025-6120 is a critical memory corruption vulnerability in the Open Asset Import Library (Assimp) affecting versions up to and including 5.4.3. The flaw is located in the Half-Life 1 MDL file format loader, specifically within the read_meshes function in HL1MDLLoader.cpp. It arises due to a lack of verification checks on array, bone, skin, or vertex indices parsed directly from a binary stream, resulting in a heap-based buffer overflow or out-of-bounds memory access.
A local file disclosure vulnerability exists in the Rust-based package skilo. When copying files during skill installation, the application recursively traverses directories but dereferences symbolic links, resulting in unauthorized local file reading.
Pagy, an agile pagination gem for plain Ruby, contains a directory traversal vulnerability in its internationalization (I18n) module prior to version 43.5.6. An unauthenticated remote attacker can exploit this flaw by submitting path traversal sequences to the locale setter, allowing them to probe the server filesystem. The resulting behavior creates a highly reliable file existence and readability side-channel oracle for YAML files.
CVE-2026-66064 is an access control list (ACL) and blocklist bypass vulnerability in the goshs file server prior to version 2.1.5. Due to an inconsistency between uncleaned raw URI path evaluation and normalized file access, remote unauthenticated attackers can retrieve protected files, including the configuration file containing password hashes, by appending a trailing slash to the requested path.
CVE-2026-54719 is a high-severity Access Control List (ACL) authorization bypass vulnerability in goshs, a lightweight HTTPS-capable server used for file sharing. The issue allows unauthenticated network attackers to completely bypass file-level and directory-level authentication mechanisms and blocklists by requesting protected resources via the bulk ZIP-download route (?bulk). This vulnerability represents a residual flaw following a partial remediation attempt for CVE-2026-40189.