{"record":{"id":"d90735d6d62f0d40","repo":"denoland/deno","slug":"temporary-directory-ancestor-is-writable-by-o","errorCode":null,"errorMessage":"temporary directory ancestor '{}' is writable by other users without the sticky bit","messagePattern":"temporary directory ancestor '(.+?)' is writable by other users without the sticky bit","errorType":"exception","errorClass":"AnyError","httpStatus":null,"severity":"error","filePath":"cli/util/temp.rs","lineNumber":140,"sourceCode":"  // SAFETY: geteuid has no preconditions.\n  let current_uid = unsafe { libc::geteuid() };\n  for ancestor in path.ancestors() {\n    let dir = std::fs::OpenOptions::new()\n      .read(true)\n      .custom_flags(libc::O_NOFOLLOW | libc::O_DIRECTORY)\n      .open(ancestor)?;\n    let metadata = dir.metadata()?;\n    if metadata.uid() != current_uid && metadata.uid() != 0 {\n      bail!(\n        \"temporary directory ancestor '{}' is owned by uid {}, not current uid {} or root\",\n        ancestor.display(),\n        metadata.uid(),\n        current_uid\n      );\n    }\n    let mode = metadata.mode();\n    if mode & 0o022 != 0 && mode & 0o1000 == 0 {\n      bail!(\n        \"temporary directory ancestor '{}' is writable by other users without the sticky bit\",\n        ancestor.display()\n      );\n    }\n  }\n  Ok(())\n}\n\n#[cfg(not(unix))]\nfn ensure_secure_temp_parent(path: &Path) -> Result<(), AnyError> {\n  let metadata = std::fs::symlink_metadata(path)?;\n  if metadata.file_type().is_symlink() || !metadata.is_dir() {\n    bail!(\"'{}' is not a directory\", path.display());\n  }\n  Ok(())\n}\n\n#[cfg(unix)]","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/cli/util/temp.rs#L122-L158","documentation":"Second check in `ensure_secure_temp_parent`: each ancestor of the canonicalized temp dir is inspected for permission bits. Any ancestor that is group- or world-writable (mode & 0o022) and lacks the sticky bit (0o1000) is rejected — without the sticky bit, anyone with write access can rename or replace Deno's temp entries, so the path is treated as untrusted.","triggerScenarios":"TMPDIR located under a group-writable directory (e.g. `chmod 775 /opt/scratch`) or a world-writable `chmod 777` dir that never got the sticky bit. `/tmp` itself is fine (1777 = sticky), but nested mounts and shared workspace dirs commonly fail this check.","commonSituations":"Teams sharing group-writable scratch volumes; Docker images that `chmod 777` a path without `+t`; CI agents with permissive TMPDIR configurations; bind-mounted host directories with relaxed modes.","solutions":["Set the sticky bit on the writable ancestor: `chmod +t /path/to/dir` (this mirrors /tmp's 1777).","Or remove group/other write: `chmod go-w /path/to/dir`.","Or export TMPDIR to a private directory you own with default permissions."],"exampleFix":"# before: ancestor is 0775 (group-writable, no sticky bit)\nstat -c '%a %n' /srv/scratch        # 775 /srv/scratch\nexport TMPDIR=/srv/scratch/tmp\ndeno install\n# error: temporary directory ancestor '/srv/scratch' is writable by other users without the sticky bit\n\n# after\nchmod go-w /srv/scratch             # or: chmod +t /srv/scratch\ndeno install","handlingStrategy":"validation","validationCode":"# pre-check TMPDIR ancestors for group/world-writable without sticky bit\nd=\"$(cd \"${TMPDIR:-/tmp}\" && pwd -P)\"\nwhile [ \"$d\" != \"/\" ]; do\n  if [ -n \"$(find \"$d\" -maxdepth 0 -perm /022 2>/dev/null)\" ] && [ ! -k \"$d\" ]; then\n    echo \"writable non-sticky temp ancestor: $d ($(stat -c %a \"$d\"))\"\n  fi\n  d=\"$(dirname \"$d\")\"\ndone","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Apply `chmod +t` to any shared writable directory used for temp, mirroring /tmp's 1777.","Prefer `chmod go-w` over group-writable scratch dirs when sharing is not required.","Audit container images that chmod 777 paths — add the sticky bit or tighten modes."],"tags":["security","temp-dir","sticky-bit","permissions","unix"],"backgroundTag":"insecure-temp-directory","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}