{"record":{"id":"fd2bb4efd221e532","repo":"denoland/deno","slug":"native-addon-cache-directory-is-not-private","errorCode":null,"errorMessage":"Native addon cache directory '{}' is not private","messagePattern":"Native addon cache directory '(.+?)' is not private","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ext/rt_helper/lib.rs","lineNumber":274,"sourceCode":"  {\n    use std::os::unix::fs::MetadataExt;\n    use std::os::unix::fs::PermissionsExt;\n\n    if metadata.uid() != current_uid() {\n      return Err(std::io::Error::new(\n        ErrorKind::PermissionDenied,\n        format!(\n          \"Native addon cache directory '{}' is not owned by the current user\",\n          path.display()\n        ),\n      ));\n    }\n\n    if metadata.permissions().mode() & 0o777 != 0o700 {\n      fs::set_permissions(path, fs::Permissions::from_mode(0o700))?;\n      let metadata = fs::symlink_metadata(path)?;\n      if metadata.permissions().mode() & 0o777 != 0o700 {\n        return Err(std::io::Error::new(\n          ErrorKind::PermissionDenied,\n          format!(\n            \"Native addon cache directory '{}' is not private\",\n            path.display()\n          ),\n        ));\n      }\n    }\n  }\n\n  Ok(())\n}\n\n#[cfg(test)]\nmod test {\n  #![allow(clippy::disallowed_methods, reason = \"test code\")]\n\n  use super::*;","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/rt_helper/lib.rs#L256-L292","documentation":"Final Unix privacy check for Deno's native addon cache dir: the permission bits must be exactly 0o700. If they are looser, Deno attempts to chmod 0700 and re-stat; if the mode still is not 0700 (chmod failed or silently ignored by the filesystem), it errors with ErrorKind::PermissionDenied. Escaping to the user means the preferred dir was not salvageable and the fallback tempdir hit the same wall.","triggerScenarios":"The cache directory has group/other bits set and the filesystem ignores or rejects set_permissions: NFS with root_squash, some FUSE/filesystem mounts, WSL drvfs mounts without metadata, or read-only filesystems where the repairing chmod fails.","commonSituations":"TMPDIR on an NFS home or shared volume; WSL1/NTFS-mounted temp dirs where POSIX modes do not stick; container volumes mounted with forced modes; umask-independent cases where an external tool loosened permissions.","solutions":["Move the temp dir to a POSIX filesystem that honors chmod: export TMPDIR=$(mktemp -d) under ext4/tmpfs.","Manually repair the existing dir: chmod 700 \"$TMPDIR\"/deno-native-addon-cache, then rerun.","For WSL, store the temp dir inside the Linux filesystem (not /mnt/c) or enable drvfs metadata.","For NFS/shared volumes, use a per-user subdirectory created with 0700."],"exampleFix":"# before\nTMPDIR=/mnt/nfs-shared deno run app.ts # chmod does not stick -> not private\n\n# after\nexport TMPDIR=/tmp/$(id -un)\nmkdir -p \"$TMPDIR\" && chmod 700 \"$TMPDIR\"\ndeno run app.ts","handlingStrategy":"validation","validationCode":"import { statSync, chmodSync, mkdirSync } from \"node:fs\";\nconst t = process.env.TMPDIR ?? \"/tmp\";\ntry { mkdirSync(t, { recursive: true, mode: 0o700 }); chmodSync(t, 0o700); } catch { throw new Error(`temp fs ignores chmod — use a POSIX filesystem for TMPDIR`); }\nif ((statSync(t).mode & 0o777) !== 0o700) throw new Error(`temp dir not private: ${t}`);","typeGuard":null,"tryCatchPattern":"try { await run(); } catch (e) { if (/is not private/.test(String(e))) throw new Error(`temp fs does not enforce 0700 (${t}) — remount TMPDIR on tmpfs/ext4`); throw e; }","preventionTips":["Avoid NFS/FUSE/drvfs locations for TMPDIR; prefer tmpfs or the container writable layer.","Proactively chmod 700 the per-user temp dir in container entrypoints.","Smoke-test the deployment image's temp dir permissions before shipping."],"tags":["native-addons","cache","permissions","unix","filesystem","chmod"],"backgroundTag":"insecure-temp-directory","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}