Skip to content

Batch scan creates temp dir with predictable name, unchecked mkdir, 0777 mode #120

Description

@sirbrillig

getPhpcsOutputForGitBatch() (ShellRunner.php:441) and getPhpcsOutputForSvnBatch() (ShellRunner.php:478) both do:

$tempDir = sys_get_temp_dir() . '/phpcs-changed-' . uniqid();
mkdir($tempDir);

and writeTempFile() (ShellRunner.php:339) does:

if (! is_dir($dir)) {
    mkdir($dir, 0777, true);
}

Three problems:

  1. Unchecked mkdir() return value. If the directory already exists, mkdir() emits a warning and returns false, and the code proceeds to write into it anyway.
  2. Predictable name. uniqid() is derived from the current microtime and is guessable. On a shared machine (CI runner, shared build box) another local user can pre-create the predicted path and plant new/ and old/ as symlinks. Since the failed mkdir() is ignored, the cmd > tempfile redirect in writeCommandOutputToFile() then writes git/svn file contents through the symlink, or lets the attacker tamper with the temp copies before the single batched phpcs run reads them (forged lint results on a commit gate).
  3. Permissive mode. 0777 & ~umask on the directories, plus default file permissions, transiently expose copies of the scanned source to other local users.

CWE-377 (insecure temporary file) / CWE-378 (creation of temp file with insecure permissions).

Suggested fix

Create the root temp dir with mode 0700 and check the return value, failing loudly if it is already taken; use random_bytes()-derived entropy rather than uniqid(); use 0700 for the nested directories in writeTempFile() too and check that return value as well.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions