denoland/deno · error · AnyError
temporary directory ancestor '{}' is writable by other users
Error message
temporary directory ancestor '{}' is writable by other users without the sticky bit What it means
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.
Source
Thrown at cli/util/temp.rs:140
// SAFETY: geteuid has no preconditions.
let current_uid = unsafe { libc::geteuid() };
for ancestor in path.ancestors() {
let dir = std::fs::OpenOptions::new()
.read(true)
.custom_flags(libc::O_NOFOLLOW | libc::O_DIRECTORY)
.open(ancestor)?;
let metadata = dir.metadata()?;
if metadata.uid() != current_uid && metadata.uid() != 0 {
bail!(
"temporary directory ancestor '{}' is owned by uid {}, not current uid {} or root",
ancestor.display(),
metadata.uid(),
current_uid
);
}
let mode = metadata.mode();
if mode & 0o022 != 0 && mode & 0o1000 == 0 {
bail!(
"temporary directory ancestor '{}' is writable by other users without the sticky bit",
ancestor.display()
);
}
}
Ok(())
}
#[cfg(not(unix))]
fn ensure_secure_temp_parent(path: &Path) -> Result<(), AnyError> {
let metadata = std::fs::symlink_metadata(path)?;
if metadata.file_type().is_symlink() || !metadata.is_dir() {
bail!("'{}' is not a directory", path.display());
}
Ok(())
}
#[cfg(unix)]View on GitHub (pinned to 9ad36f7a2c)
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.
Example fix
# before: ancestor is 0775 (group-writable, no sticky bit) stat -c '%a %n' /srv/scratch # 775 /srv/scratch export TMPDIR=/srv/scratch/tmp deno install # error: temporary directory ancestor '/srv/scratch' is writable by other users without the sticky bit # after chmod go-w /srv/scratch # or: chmod +t /srv/scratch deno install
Defensive patterns
Strategy: validation
Validate before calling
# pre-check TMPDIR ancestors for group/world-writable without sticky bit
d="$(cd "${TMPDIR:-/tmp}" && pwd -P)"
while [ "$d" != "/" ]; do
if [ -n "$(find "$d" -maxdepth 0 -perm /022 2>/dev/null)" ] && [ ! -k "$d" ]; then
echo "writable non-sticky temp ancestor: $d ($(stat -c %a "$d"))"
fi
d="$(dirname "$d")"
done Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- temporary directory ancestor '{}' is owned by uid {}, not cu
- '{}' is owned by uid {}, not current uid {}
- '{}' is writable or readable by other users
- Native addon cache path '{}' is not a private directory
- You don't have write permission to {} because it's owned by
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/d90735d6d62f0d40.
Report an issue: GitHub.