Deno's permission system enforces filesystem and execution restrictions by
comparing the requested path against the path supplied to --deny-read,
--deny-write, --deny-run, or --deny-ffi. On macOS, that comparison was
done at the raw-byte level while the APFS filesystem treats different Unicode
spellings of the same name as the same file.
That means a program could reach a denied path by spelling it differently than
the deny rule. For example, with --deny-read=/secrets/passwörter.txt, a
script could still read the file by opening /secrets/passwo\u0308rter.txt
(NFD instead of NFC), or /SECRETS/PASSWÖRTER.txt (different case, since
default APFS volumes are case-insensitive). Other forms include ligature
characters (fi vs fi, ff vs ff, …) and German ß vs ss.
The denied path and the requested path differed at the byte level, so Deno's
permission check passed; the kernel then resolved them to the same inode and
served the file anyway. The same flaw affected --deny-write, --deny-run,
and --deny-ffi, which share the same path-comparison code.
You are potentially affected if all of the following are true:
--deny-read, --deny-write, --deny-run, or --deny-ffi
as a security boundary against less-trusted code — a dependency, plugin,
or attacker-controlled input.é, ñ, ö, …), German
ß, or Latin ligatures — or you rely on case-sensitivity on a default
APFS volume.If you only run fully trusted code, or your deny rules cover paths that are pure ASCII with no case-sensitive aliases, you are not exposed to this specific bypass.
A program running with broad --allow-read (or --allow-write /
--allow-run / --allow-ffi) but with --deny-* carve-outs for specific
paths could read, write, execute, or load via FFI those denied paths by
referring to them through a Unicode- or case-equivalent spelling. The sandbox
model on macOS was weaker than the flags suggested.
If you cannot upgrade immediately:
--allow-* allowlists over --deny-* denylists. Allow rules match
against the original specifier, so an attacker-supplied alternate spelling
will not match a path you didn't explicitly grant.On macOS, Deno now normalizes both the deny-rule path and the requested path to NFC and applies Unicode case folding before comparing them. This matches how APFS resolves paths at the inode level, so byte-different but equivalent spellings are now rejected by the same deny rule.
{
"license": "CC-BY-4.0",
"sources": [
{
"published": "2026-06-23T18:18:03.033Z",
"database_specific": {
"status": "Analyzed"
},
"id": "CVE-2026-49401",
"url": "https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2026-49401",
"html_url": "https://nvd.nist.gov/vuln/detail/CVE-2026-49401",
"imported": "2026-06-27T08:36:01.311Z",
"modified": "2026-06-26T17:43:03.033Z"
},
{
"published": "2026-06-16T19:11:52Z",
"url": "https://api.github.com/advisories/GHSA-8xpq-cjcf-3wh9",
"id": "GHSA-8xpq-cjcf-3wh9",
"html_url": "https://github.com/advisories/GHSA-8xpq-cjcf-3wh9",
"imported": "2026-06-27T08:36:14.648Z",
"modified": "2026-06-16T19:11:54Z"
},
{
"published": "2026-06-23T17:22:32Z",
"url": "https://euvdservices.enisa.europa.eu/api/enisaid?id=EUVD-2026-38547",
"id": "EUVD-2026-38547",
"html_url": "https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-38547",
"imported": "2026-06-27T08:36:01.407Z",
"modified": "2026-06-23T17:35:51Z"
}
]
}