| name | insecure-temp-files-anti-pattern |
| description | Security anti-pattern for insecure temporary files (CWE-377). Use when generating or reviewing code that creates temporary files, handles file caching, or processes uploads through temp storage. Detects predictable paths, insecure permissions, and missing cleanup. |
Insecure Temp Files Anti-Pattern
Severity: Medium
Summary
Insecure temporary file creation exposes three attack vectors: predictable file names enabling symlink attacks, insecure permissions allowing unauthorized access, and missing cleanup leaving sensitive data on disk. Attackers exploit these to read sensitive data, inject malicious content, or cause denial of service. AI-generated code frequently suggests simplistic file handling vulnerable to these attacks.
The Anti-Pattern
Never create temporary files without securing their location, naming, permissions, and lifecycle management.
1. Predictable File Names
Using a predictable name for a temporary file creates a race condition. An attacker can guess the file name and create a symbolic link (symlink) at that location pointing to a sensitive system file. When the application writes to its "temporary" file, it is actually overwriting the linked file.
BAD Code Example
import os
def process_user_data(user_id, data):
temp_path = f"/tmp/userdata_{user_id}.txt"
with open(temp_path, "w") as f:
f.write(data)
os.remove(temp_path)
GOOD Code Example
import tempfile
def process_user_data(user_id, data):
fd, temp_path = tempfile.mkstemp(prefix="userdata_", suffix=".txt")
try:
with os.fdopen(fd, 'w') as f:
f.write(data)
finally:
os.remove(temp_path)
2. Insecure Permissions and Missing Cleanup
Creating a temporary file with default permissions can make it world-readable, allowing other users on the system to access its contents. Failing to delete the temporary file after use means that sensitive data may be left behind on the disk.
BAD Code Example
import uuid
def generate_report(data):
temp_path = f"/tmp/{uuid.uuid4()}.pdf"
with open(temp_path, "w") as f:
f.write(data)
return temp_path
GOOD Code Example
import tempfile
def generate_report(data):
with tempfile.NamedTemporaryFile(mode='w', suffix='.pdf', delete=True) as temp_f:
temp_f.write(data)
temp_f.flush()
result = send_file_to_storage(temp_f.name)
return result
Language-Specific Examples
JavaScript/Node.js:
const fs = require('fs');
const path = require('path');
function processUpload(userId, data) {
const tempPath = `/tmp/upload_${userId}.dat`;
fs.writeFileSync(tempPath, data);
return tempPath;
}
const tmp = require('tmp');
function processUpload(userId, data) {
const tempFile = tmp.fileSync({ prefix: 'upload-', postfix: '.dat' });
try {
fs.writeFileSync(tempFile.name, data);
return processFile(tempFile.name);
} finally {
tempFile.removeCallback();
}
}
Java:
public void processData(String userId, byte[] data) throws IOException {
File tempFile = new File("/tmp/data_" + userId + ".tmp");
Files.write(tempFile.toPath(), data);
}
import java.nio.file.*;
import java.nio.file.attribute.*;
public void processData(String userId, byte[] data) throws IOException {
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");
FileAttribute<Set<PosixFilePermission>> attr =
PosixFilePermissions.asFileAttribute(perms);
Path tempFile = Files.createTempFile("data-", ".tmp", attr);
try {
Files.write(tempFile, data);
} finally {
Files.deleteIfExists(tempFile);
}
}
Go:
func processData(userID string, data []byte) error {
tempPath := fmt.Sprintf("/tmp/data_%s.tmp", userID)
if err := os.WriteFile(tempPath, data, 0644); err != nil {
return err
}
return nil
}
import "os"
func processData(userID string, data []byte) error {
tempFile, err := os.CreateTemp("", "data-*.tmp")
if err != nil {
return err
}
defer os.Remove(tempFile.Name())
defer tempFile.Close()
if _, err := tempFile.Write(data); err != nil {
return err
}
return nil
}
Detection
- Search for insecure temp directories: Grep for hardcoded temp paths:
rg 'open\s*\(\s*["\']/(tmp|var/tmp)/'
rg 'File\.createTempFile|mktemp|tmpfile' (check if used correctly)
- Identify predictable file names: Find patterns based on user IDs or timestamps:
rg 'f"/tmp/{user_id}' 'f"/tmp/{username}'
rg 'new File\("/tmp/" \+ userId'
- Check file permissions: Audit permission settings:
rg 'os\.chmod.*0o[67]' (world-readable/writable)
- Review code for missing
os.umask(0o077) or tempfile usage
- Verify cleanup logic: Ensure files are always deleted:
rg 'open\(' | rg -v 'with|try.*finally|NamedTemporaryFile'
- Check for missing
defer f.Close() (Go) or using (C#)
Prevention
Related Security Patterns & Anti-Patterns
References