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()withfs.mkdtempormkdtempSync, then work inside it. - Use exclusive creation flags such as
'wx'or'ax'and restrictive permissions such as0o600. - Do not pass a predictable path built directly from
os.tmpdir()tofs.writeFile(Sync)orfs.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.txtor a symlink before the write. Default creation permissions may also allow broader access than intended, increasing disclosure and overwrite risks. - After:
fs.mkdtempcreates a unique dedicated directory.'wx'fails rather than overwriting an existing path, and0o600restricts access. Protect the directory against modification by other users and remove it after use.