GitHub Advisoryadvisory · crates.io
GHSA-8xpq-cjcf-3wh9 Deno: Permission Bypass via Unicode Normalization Mismatch on macOS (APFS)
HIGH
Official page ↗
- Aliases
- CVE-2026-49401
- Ecosystem
- crates.io
- Packages
- deno
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:N
- Weaknesses
- CWE-176, CWE-41
- Reviewed
- 2026-06-16
Affected packages
• crates.io deno: < 2.7.14 → fixed in 2.7.14
Description
Summary
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.
Am I affected?
You are potentially affected if all of the following are true:
1. You run Deno on macOS (the issue is specific to APFS path-equivalence
rules; Linux and Windows are not affected by this variant).
2. You rely on `--deny-read`, `--deny-write`, `--deny-run`, or `--deny-ffi`
as a security boundary against less-trusted code — a dependency, plugin,
or attacker-controlled input.
3. The protected path contains characters that have alternate Unicode
spellings — most commonly accented characters (`é`, `ñ`, `ö`, …), 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.
Impact
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.
Workaround
If you cannot upgrade immediately:
• Prefer `--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.
• Do not rely on case-sensitivity of paths on macOS for security boundaries;
default APFS volumes are case-insensitive.
Fix
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.
Related
Alias · CVE (1)
- CVE-2026-49401 Deno is a JavaScript, TypeScript, and WebAssembly runtime. vulnerability