Chapter 18Lesson 03~100 minutes

Secure Temporary Files, Permissions, and Cleanup

Temporary files sit directly on a filesystem trust boundary. Secure automation must create them atomically, protect them while they exist, clean them up without hiding errors, and never assume cleanup is guaranteed.

IntermediateSecurity & portabilityHands-on lab

Learning objectives

By the end of this lesson

  • Avoid predictable temporary-file races.
  • Use private temporary directories.
  • Control umask, modes, and ownership.
  • Preserve status through cleanup.
  • Stage important files safely before promotion.

1. Predictable temporary filenames create race conditions

# Unsafe:
# tmp=/tmp/myapp.$$
# : > "$tmp"

# Safe:
tmp=$(mktemp) || exit 1

mktemp creates a unique file atomically enough for the intended temporary-file use case, avoiding the check-then-create race of hand-built names.

2. Prefer private temporary directories for multi-file work

umask 077
tmpdir=$(mktemp -d) || exit 1

cleanup() {
  local status=$?
  rm -rf -- "$tmpdir"
  exit "$status"
}
trap cleanup EXIT

A private workspace lets multiple scratch files share one protected directory and one cleanup boundary.

3. umask defines default permission removal

old_umask=$(umask)
umask 077

tmp=$(mktemp) || exit 1

umask "$old_umask"

077 removes group and other permissions from newly created files and directories.

4. Set final permissions deliberately

install -m 0644 -- generated.conf /etc/myapp/generated.conf

Temporary privacy and final deployment permissions solve different problems.

6. Ownership is part of the security contract

install \
  -o root \
  -g myapp \
  -m 0640 \
  generated.conf \
  /etc/myapp/generated.conf

A file with the right contents but wrong owner or group can be unusable or overly exposed.

7. Cleanup should preserve the original status

cleanup() {
  local status=$?
  rm -rf -- "${tmpdir:-}"
  exit "$status"
}
trap cleanup EXIT

8. Cleanup is best effort, not guaranteed

SIGKILL, power loss, kernel crashes, or abrupt runtime termination can bypass traps. Sensitive temporary state should therefore be protected even while it exists, not merely deleted later.

9. Stage and promote important files atomically

target=/etc/myapp/config
dir=$(dirname -- "$target")

tmp=$(mktemp "$dir/.config.XXXXXX") || exit 1
chmod 0640 -- "$tmp"

render_config > "$tmp"
validate_config "$tmp"
mv -- "$tmp" "$target"

Creating the temporary file in the destination directory improves the chance that final rename stays on the same filesystem.

10. Directory permissions control traversal too

For directories, execute permission means traversal. A secret file inside a world-traversable directory may still be protected by its own mode, but directory modes affect discoverability and access patterns.

11. Hands-on lab: private temporary workspace

mkdir -p "$HOME/devops-academy/bash/chapter18/lesson03"
cd "$HOME/devops-academy/bash/chapter18/lesson03"

cat > secure-temp.sh <<'EOF'
#!/usr/bin/env bash
set -u

old_umask=$(umask)
umask 077

tmpdir=$(mktemp -d) || exit 1

cleanup() {
  local status=$?
  rm -rf -- "$tmpdir"
  umask "$old_umask"
  exit "$status"
}
trap cleanup EXIT

secret_file="$tmpdir/token"
printf '%s\n' 'demo-secret' > "$secret_file"

printf 'tmpdir=%s\n' "$tmpdir"
printf 'dir_mode=%s\n' "$(stat -c '%a' "$tmpdir" 2>/dev/null || printf platform-specific)"
printf 'file_created=yes\n'
EOF

chmod u+x secure-temp.sh
bash secure-temp.sh

Verification checklist

12. Knowledge check

Question 1. Why is /tmp/file.$$ weaker than mktemp?

Question 2. What does umask 077 do?

Question 3. Why place a staged final file in the destination directory?

Question 4. Is cleanup guaranteed to run?

13. Summary

Secure temporary-state handling starts with atomic creation, private directories, restrictive umask, deliberate ownership/modes, status-preserving cleanup, and same-directory staging for final promotion. Protect temporary data even if cleanup never runs.

14. Further reading

  • GNU Coreutils documentation — mktemp, install, chmod, chown.
  • POSIX file permission concepts.
  • Linux filesystem and symlink security documentation.
  • OWASP secure file-handling guidance.
Next lesson

Bash versus POSIX sh and Portability Tradeoffs

Continue Chapter 18 by strengthening Bash trust boundaries, security assumptions, and portability guarantees.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.