| name | uid-gid-privilege-drop |
| description | UID/GID privilege dropping for safe agent subprocess execution. setuid/setgid before exec, running commands as nobody/unprivileged user, Node.js uid/gid options on spawn, and preventing privilege re-escalation. Sources: stephenmathieson/node-uid, Linux credentials(7). |
/uid-gid-privilege-drop
When to Use
- Running untrusted agent commands as
nobody (uid 65534) instead of current user
- Subprocess must not inherit root's filesystem permissions
- Pair with [[capability-dropping-linux]] for defense in depth
- Codespaces: drop to dedicated agent UID before running sandbox workloads
Do NOT use for
- Replacing capability dropping (UID change alone doesn't drop capabilities)
- Multi-user auth (use proper session management)
Node.js spawn with UID/GID drop
import { spawn } from 'child_process'
const NOBODY_UID = 65534
const NOBODY_GID = 65534
function spawnAsNobody(cmd: string, args: string[], cwd: string) {
return spawn(cmd, args, {
cwd,
uid: NOBODY_UID,
gid: NOBODY_GID,
stdio: 'pipe',
env: {
PATH: '/usr/local/bin:/usr/bin:/bin',
HOME: '/tmp',
TMPDIR: '/tmp',
},
})
}
Bash privilege drop
drop_to_nobody() {
local cmd=("$@")
if [[ "$(id -u)" -ne 0 ]]; then
echo "[uid] Not root — cannot drop to nobody" >&2
return 1
fi
exec su -s /bin/sh -c "${cmd[*]}" nobody
}
capsh --user=nobody --inh='' --addamb='' -- -c "${cmd[*]}"
Verify effective UID in subprocess
verify_uid_drop() {
local expected_uid="${1:-65534}"
local actual_uid; actual_uid="$(id -u)"
if [[ "$actual_uid" -ne "$expected_uid" ]]; then
echo "[uid] FAIL: running as UID $actual_uid, expected $expected_uid" >&2
exit 1
fi
echo "[uid] OK: running as UID $actual_uid"
}
Runuser / su patterns
runuser -u agent-sandbox -- /bin/bash agent-script.sh
Anti-Fake-Pass Checklist
❌ uid set but gid not set → process still in root group, can read group-root files
❌ Supplemental groups not cleared → inherited group memberships bypass drop
❌ setuid without noNewPrivileges → SUID binaries restore root via exec
❌ HOME not set to /tmp → process reads/writes to root's home directory
❌ PATH includes /root/bin → privilege escalation via PATH hijack
❌ spawn uid option requires Node.js to be running as root first
❌ /etc/passwd entry for nobody must exist — missing entry causes auth failure