Harden restore-archive extraction against path traversal

extract_payload_from_archive() relied entirely on tar's own default
path-traversal protection when extracting a DirectAdmin restore
archive to locate the plugin's backup/alt_mysql payload. Explicitly
inspect the archive listing first and refuse to extract at all if any
member has an absolute path or a ".." segment, rather than trusting
that the wildcard extraction pattern happens to filter out an unsafe
member.
This commit is contained in:
Marek Miklewicz
2026-07-04 22:53:21 +02:00
parent f472a7abfc
commit b4fbd46cc1
2 changed files with 83 additions and 2 deletions
@@ -85,13 +85,24 @@ find_payload_in_dir() {
extract_payload_from_archive() {
local archive="$1"
local tmp_dir payload_member
local tmp_dir payload_member listing
[ -r "$archive" ] || return 1
command -v tar >/dev/null 2>&1 || return 1
payload_member="$(tar -tf "$archive" 2>/dev/null | grep -E '(^|/)backup/alt_mysql/manifest\.json$' | head -n 1 || true)"
listing="$(tar -tf "$archive" 2>/dev/null || true)"
[ -n "$listing" ] || return 1
payload_member="$(printf '%s\n' "$listing" | grep -E '(^|/)backup/alt_mysql/manifest\.json$' | head -n 1 || true)"
[ -n "$payload_member" ] || return 1
# Security: never trust tar's own default path-traversal protection alone -
# refuse to extract archives containing any absolute-path or ".." member,
# even if the offending member wouldn't otherwise match our own wildcard.
if printf '%s\n' "$listing" | grep -Eq '(^|/)\.\.(/|$)|^/'; then
log "refusing to extract archive with unsafe member paths: $archive"
return 1
fi
tmp_dir="$(mktemp -d)"
tar -xf "$archive" -C "$tmp_dir" --wildcards '*/backup/alt_mysql/*' 'backup/alt_mysql/*' 2>/dev/null \
|| tar -xf "$archive" -C "$tmp_dir" 2>/dev/null