CVE-2021-41641
Description
Deno <=1.14.0 file sandbox does not handle symbolic links correctly. When running Deno with specific write access, the Deno.symlink method can be used to gain access to any directory.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Deno <=1.14.0 allows sandbox escape via symlinks, enabling arbitrary directory access with partial write permissions.
Vulnerability
Overview
CVE-2021-41647 affects Deno versions up to 1.14.0, where the file system sandbox fails to properly handle symbolic links. The core issue is that the Deno.symlink method could be used to create symlinks that point outside the allowed sandboxed directories, bypassing permission controls [1]. This occurs because the runtime did not correctly validate the resolved path of symlinks when checking permissions.
Exploitation
Prerequisites
An attacker needs to run Deno with at least specific write access permissions (e.g., limited to a subdirectory). By creating a symbolic link using Deno.symlink, they can craft a link that points to a target outside the permitted directory. For example, creating a symlink to ../../etc and then moving an ancestor directory could cause the symlink to resolve outside the sandbox [2]. The attack does not require full filesystem permissions, only the ability to create symlinks within a directory where partial write access is granted [3].
Impact
Successful exploitation allows an attacker to read or write to arbitrary files and directories on the file system, effectively achieving a full sandbox escape. This could lead to data exfiltration, system modification, or privilege escalation depending on the Deno process's environment [1].
Mitigation
The vulnerability was addressed in Deno commit d44011a69e0674acfa9c59bd7ad7f0523eb61d42, which requires both full read and full write permissions to create symlinks [4]. This fix was merged in pull request #12554 and is included in Deno versions after 1.14.0 [2]. Users should upgrade to a patched version immediately.
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
denocrates.io | < 1.16.0 | 1.16.0 |
Affected products
2- Deno/Denodescription
Patches
1d44011a69e06fix(runtime): require full read and write permissions to create symlinks (#12554)
3 files changed · +34 −4
cli/dts/lib.deno.ns.d.ts+2 −2 modified@@ -2347,7 +2347,7 @@ declare namespace Deno { * Deno.symlinkSync("old/name", "new/name"); * ``` * - * Requires `allow-write` permission. */ + * Requires full `allow-read` and `allow-write` permissions. */ export function symlinkSync( oldpath: string | URL, newpath: string | URL, @@ -2364,7 +2364,7 @@ declare namespace Deno { * await Deno.symlink("old/name", "new/name"); * ``` * - * Requires `allow-write` permission. */ + * Requires full `allow-read` and `allow-write` permissions. */ export function symlink( oldpath: string | URL, newpath: string | URL,
cli/tests/unit/symlink_test.ts+28 −0 modified@@ -108,3 +108,31 @@ unitTest( ); }, ); + +unitTest( + { permissions: { read: true, write: ["."] } }, + async function symlinkNoFullWritePermissions() { + await assertRejects( + () => Deno.symlink("old", "new"), + Deno.errors.PermissionDenied, + ); + assertThrows( + () => Deno.symlinkSync("old", "new"), + Deno.errors.PermissionDenied, + ); + }, +); + +unitTest( + { permissions: { read: ["."], write: true } }, + async function symlinkNoFullReadPermissions() { + await assertRejects( + () => Deno.symlink("old", "new"), + Deno.errors.PermissionDenied, + ); + assertThrows( + () => Deno.symlinkSync("old", "new"), + Deno.errors.PermissionDenied, + ); + }, +);
runtime/ops/fs.rs+4 −2 modified@@ -1370,7 +1370,8 @@ fn op_symlink_sync( let oldpath = PathBuf::from(&args.oldpath); let newpath = PathBuf::from(&args.newpath); - state.borrow_mut::<Permissions>().write.check(&newpath)?; + state.borrow_mut::<Permissions>().write.check_all()?; + state.borrow_mut::<Permissions>().read.check_all()?; debug!( "op_symlink_sync {} {}", @@ -1432,7 +1433,8 @@ async fn op_symlink_async( { let mut state = state.borrow_mut(); - state.borrow_mut::<Permissions>().write.check(&newpath)?; + state.borrow_mut::<Permissions>().write.check_all()?; + state.borrow_mut::<Permissions>().read.check_all()?; } tokio::task::spawn_blocking(move || {
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-67hm-27mx-9cg7ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2021-41641ghsaADVISORY
- github.com/denoland/deno/commit/d44011a69e0674acfa9c59bd7ad7f0523eb61d42ghsaWEB
- github.com/denoland/deno/issues/12152ghsax_refsource_MISCWEB
- github.com/denoland/deno/pull/12554ghsaWEB
- hackers.report/report/614876917a7b150012836bb8ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.