Insecure temporary file creation

Insecure temporary file creation

Description

Writing predictable filenames directly in a shared temporary directory such as os.tmpdir() can collide with other processes or users. An attacker may pre-create a symbolic link or other filesystem entry and redirect the write. Depending on the application's permissions and how the affected file is used, this may expose data, overwrite files, or enable privilege escalation or code execution. For example, a pre-created /tmp/report.txt symlink may point to an important system file.

Potential impact

  • Other users may read temporary logs, tokens, or sensitive data.
  • A pre-created symlink may redirect writes to important configuration or key files.
  • Modified files that are later executed or loaded may enable code execution or privilege escalation.
  • Filename collisions or permission errors may interrupt temporary work or service availability.

Remediation

  • Use a reviewed temporary-file library such as tmp.
  • Create a unique private directory under os.tmpdir() with fs.mkdtemp or mkdtempSync, then work inside it.
  • Use exclusive creation flags such as 'wx' or 'ax' and restrictive permissions such as 0o600.
  • Do not pass a predictable path built directly from os.tmpdir() to fs.writeFile(Sync) or fs.createWriteStream.
  • Clean up files and directories after use, and check ownership and permissions where needed.
  • Prefer a secure secret store to temporary files for tokens and private keys.

Examples

Before

javascript
const fs = require("fs");
const os = require("os");
const path = require("path");

function saveReport(data) {
  // Before: write a predictable name directly in shared TMP
  const p = path.join(os.tmpdir(), "report.txt");
  fs.writeFileSync(p, data); // Default permissions/flags may allow races or excessive access
  return p;
}

After

javascript
const fs = require("fs");
const os = require("os");
const path = require("path");
const crypto = require("crypto");

function saveReportSafely(data) {
  // 1) Create a unique temporary directory with a random suffix
  const base = path.join(os.tmpdir(), "myapp-");
  const tmpDir = fs.mkdtempSync(base); // Example: /tmp/myapp-abc123

  // 2) Use a random filename inside the directory to avoid collisions
  const name = "report-" + crypto.randomBytes(8).toString("hex") + ".log";
  const filePath = path.join(tmpDir, name);

  // 3) Fail if the path exists and create with minimal permissions
  fs.writeFileSync(filePath, data, { flag: "wx", mode: 0o600 });

  return filePath;
  // Clean up after use with fs.rmSync(tmpDir, { recursive: true, force: true }); as needed
}

Explanation:

  • Before: Another user may create report.txt or a symlink before the write. Default creation permissions may also allow broader access than intended, increasing disclosure and overwrite risks.
  • After: fs.mkdtemp creates a unique dedicated directory. 'wx' fails rather than overwriting an existing path, and 0o600 restricts access. Protect the directory against modification by other users and remove it after use.

References