T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- scripts/canary-test.sh:141
- Finding
- Privileged Arbitrary File Overwrite Through Predictable Temporary Storage<![CDATA[ ## Vulnerability Details **File Location**: `scripts/canary-test.sh:14-20, 141-147`; `scripts/critical-update.sh:11-12, 39, 53-56` **Vulnerability Type**: Predictable temporary directory, untrusted rollback metadata, and privileged file overwrite **Risk Level**: High ### Vulnerable Code ```bash CANARY_DIR="${CANARY_DIR:-/tmp/canary-deploy}" BASELINE_FILE="$CANARY_DIR/baseline.json" BACKUP_DIR="$CANARY_DIR/backups" ACTION="${1:-help}" mkdir -p "$CANARY_DIR" "$BACKUP_DIR" ``` ```bash if [ -d "$BACKUP_DIR" ] && [ "$(ls -A "$BACKUP_DIR" 2>/dev/null)" ]; then for f in "$BACKUP_DIR"/*; do ORIGINAL=$(cat "$f.path" 2>/dev/null || echo "") if [ -n "$ORIGINAL" ] && [ -f "$f" ]; then sudo cp "$f" "$ORIGINAL" echo " ✅ Restored: $ORIGINAL" fi done ``` The corresponding backup creation logic is: ```bash CANARY_DIR="${CANARY_DIR:-/tmp/canary-deploy}" BACKUP_DIR="$CANARY_DIR/backups" mkdir -p "$CANARY_DIR" "$BACKUP_DIR" for f in "${BACKUP_FILES[@]}"; do if [ -f "$f" ]; then SAFE_NAME=$(echo "$f" | tr '/' '_') cp "$f" "$BACKUP_DIR/$SAFE_NAME" echo "$f" > "$BACKUP_DIR/$SAFE_NAME.path" echo " ✅ Backed up: $f" else echo " ⚠️ File not found: $f" fi done ``` ### Technical Analysis The scripts use the fixed, globally predictable path `/tmp/canary-deploy` for backup data and destination metadata. They create this path with `mkdir -p` but do not verify: - Whether the directory existed before execution. - Whether it is owned by the current trusted user. - Whether its permissions prevent modification by other local users. - Whether any component is a symbolic link. - Whether backup files and `.path` metadata are regular, trusted files. - Whether a rollback destination belongs to the set of files backed up during the current operation. Rollback treats the contents of `"$f.path"` as an authoritative destination and passes that value to `sudo cp`. This creates ...[truncated 2289 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace the predictable directory with a private directory created using `mktemp -d`: ```bash CANARY_DIR="$(mktemp -d "${TMPDIR:-/tmp}/canary-deploy.XXXXXXXX")" chmod 700 "$CANARY_DIR" ``` 2. If rollback state must survive between invocations, use a dedicated state directory owned by the trusted operator, such as a directory under `/var/lib` or `$XDG_STATE_HOME`, and verify: - Expected owner UID. - Mode `0700`. - No symbolic links in any path component. - The directory is not group- or world-writable. 3. Reject pre-existing storage whose ownership or permissions are unsafe: ```bash [ "$(stat -c '%u' "$CANARY_DIR")" -eq "$(id -u)" ] || exit 1 [ "$(stat -c '%a' "$CANARY_DIR")" = "700" ] || exit 1 ``` 4. Do not trust a standalone `.path` file to select an unrestricted privileged destination. Maintain an authenticated manifest created during the current transaction and only restore destinations explicitly included in that manifest. 5. Canonicalize and validate every destination with `realpath` before restoration. Reject destinations outside an explicit allowlist established from the original `--backup` arguments. 6. Open files defensively and reject symbolic links. Use checks such as `test -f`, `test ! -L`, owner validation, and secure file descriptors where practical. 7. Avoid invoking `sudo` internally. Require the complete script to run under a clearly documented privilege model, or use a narrowly scoped privileged helper that only restores previously registered files. 8. Give each update transaction a unique backup directory to prevent stale or attacker-injected files from being included in a later rollback. ]]>
