CVE-2024-38358
Description
Wasmer is a web assembly (wasm) Runtime supporting WASIX, WASI and Emscripten. If the preopened directory has a symlink pointing outside, WASI programs can traverse the symlink and access host filesystem if the caller sets both oflags::creat and rights::fd_write. Programs can also crash the runtime by creating a symlink pointing outside with path_symlink and path_opening the link. This issue has been addressed in commit b9483d022 which has been included in release version 4.3.2. Users are advised to upgrade. There are no known workarounds for this vulnerability.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
wasmercrates.io | <= 4.3.1 | — |
Affected products
1Patches
1b9483d022c60Merge pull request from GHSA-55f3-3qvg-8pv5
4 files changed · +71 −4
lib/wasix/src/syscalls/wasi/path_open.rs+16 −4 modified@@ -330,11 +330,13 @@ pub(crate) fn path_open_internal( // once we got the data we need from the parent, we lookup the host file // todo: extra check that opening with write access is okay let handle = { + // We set create_new because the path already didn't resolve to an existing file, + // so it must be created. let open_options = open_options .read(minimum_rights.read) .append(minimum_rights.append) .write(minimum_rights.write) - .create_new(minimum_rights.create_new); + .create_new(true); if minimum_rights.read { open_flags |= Fd::READ; @@ -349,9 +351,19 @@ pub(crate) fn path_open_internal( open_flags |= Fd::TRUNCATE; } - Some(wasi_try_ok_ok!(open_options - .open(&new_file_host_path) - .map_err(|e| { fs_error_into_wasi_err(e) }))) + match open_options.open(&new_file_host_path) { + Ok(handle) => Some(handle), + Err(err) => { + // Even though the file does not exist, it still failed to create with + // `AlreadyExists` error. This can happen if the path resolves to a + // symlink that points outside the FS sandbox. + if err == FsError::AlreadyExists { + return Ok(Err(Errno::Perm)); + } + + return Ok(Err(fs_error_into_wasi_err(err))); + } + } }; let new_inode = {
tests/wasi-fyi/fs_sandbox_symlink.rs+53 −0 added@@ -0,0 +1,53 @@ +#[link(wasm_import_module = "wasi_snapshot_preview1")] +extern "C" { + pub fn path_open( + fd: i32, + dirflags: i32, + path: i32, + path_len: i32, + oflags: i32, + fs_rights_base: i64, + fs_rights_inheriting: i64, + fdflags: i32, + result_fd: i32, + ) -> i32; +} + +const ERRNO_PERM: i32 = 63; +const LOOKUPFLAGS_SYMLINK_FOLLOW: i32 = 1; +const OFLAGS_CREAT: i32 = 1; +const RIGHTS_FD_WRITE: i64 = 64; + +fn main() { + let link_path = "fyi/fs_sandbox_symlink.dir/link"; + let link_path_non_existant = "fyi/fs_sandbox_symlink.dir/link-non-existant"; + let mut fd: i32 = 0; + + unsafe { + let errno = path_open( + 5, + LOOKUPFLAGS_SYMLINK_FOLLOW, + link_path.as_ptr() as i32, + link_path.len() as i32, + OFLAGS_CREAT, + RIGHTS_FD_WRITE, + 0, + 0, + &mut fd as *mut i32 as i32, + ); + assert_eq!(errno, ERRNO_PERM, "symlink cannot escape fs sandbox"); + + let errno = path_open( + 5, + LOOKUPFLAGS_SYMLINK_FOLLOW, + link_path_non_existant.as_ptr() as i32, + link_path_non_existant.len() as i32, + OFLAGS_CREAT, + RIGHTS_FD_WRITE, + 0, + 0, + &mut fd as *mut i32 as i32, + ); + assert_eq!(errno, ERRNO_PERM, "symlink cannot escape fs sandbox"); + } +}
tests/wasi-fyi/test_fs/fyi/fs_sandbox_symlink.dir/link+1 −0 added@@ -0,0 +1 @@ +../../README.md \ No newline at end of file
tests/wasi-fyi/test_fs/fyi/fs_sandbox_symlink.dir/link-non-existant+1 −0 added@@ -0,0 +1 @@ +../../non-existant \ No newline at end of file
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.