Fix arbitrary file read via restore upload path (security)

stageRestoreUploadFromDirectAdminTemp() accepted the raw
source_file_upload POST value as a literal filesystem path with only
an is_file() check - no ownership or allowed-root validation, unlike
the sibling queueRestoreFromFilePath(). isAllowedSqlFile() only checks
the attacker-controlled display filename, never the real source path.
Since the whole plugin runs as root, any authenticated DirectAdmin user
could stage and restore-import any file readable by root on the
server (e.g. other users' alt-mysql.conf credentials), leaking its
contents via MySQL import error output or the resulting database.

Remove the unsafe raw-path candidate entirely; only accept files whose
basename matches one inside the already-safe, fixed set of known
DirectAdmin/system temp directories.
This commit is contained in:
Marek Miklewicz
2026-07-04 21:53:21 +02:00
parent b077425f93
commit 60ae1e1697
2 changed files with 101 additions and 3 deletions
+5 -3
View File
@@ -437,10 +437,12 @@ final class BackupQueueService
throw new RuntimeException('Nie można odczytać przesłanego pliku backupu.');
}
// Security: never trust $uploadReference as a literal path - it comes
// straight from user-controlled POST data, and this whole plugin runs
// as root. Only accept a file whose *basename* matches one of the
// known DirectAdmin/system temp directories below, never an
// arbitrary absolute path chosen by the caller.
$sourceCandidates = [];
if (str_starts_with($uploadReference, '/') && is_file($uploadReference)) {
$sourceCandidates[] = $uploadReference;
}
$tmpDirs = [
(string)(getenv('UPLOAD_TMP_DIR') ?: ''),
(string)(getenv('DA_UPLOAD_TMP_DIR') ?: ''),