CWE-377: Insecure Temporary File - Java
Overview
Insecure temporary file creation in Java occurs when applications create files with predictable names, insecure permissions, or without proper cleanup. Java provides Files.createTempFile() and File.createTempFile() methods that should be used instead of manual file creation in shared directories.
Primary Defence: Use Files.createTempFile() with appropriate file attributes, ensure files are deleted after use with try-with-resources or deleteOnExit(), and set restrictive permissions.
Common Vulnerable Patterns
Predictable filename in shared directory
import java.io.*;
// VULNERABLE - Predictable filename
public class InsecureTemp {
public void saveUserData(String userData) throws IOException {
// Predictable filename using PID
long pid = ProcessHandle.current().pid();
File tempFile = new File("/tmp/userdata_" + pid + ".txt");
// Anyone can predict this filename
try (FileWriter writer = new FileWriter(tempFile)) {
writer.write(userData);
}
processFile(tempFile);
// File not deleted - persists in /tmp
}
}
Fixed filename
import java.io.*;
// VULNERABLE - Fixed filename, race condition
public void exportCredentials(String apiKey, String secret) throws IOException {
File tempFile = new File("/tmp/credentials.txt");
// Multiple processes might use same filename
// No atomic creation - race condition
try (FileWriter writer = new FileWriter(tempFile)) {
writer.write("API_KEY=" + apiKey + "\n");
writer.write("SECRET=" + secret + "\n");
}
// File might have insecure permissions
// File not cleaned up
}
Using timestamp for filename
// VULNERABLE - Timestamp-based filename is predictable
public void createTempLog() throws IOException {
long timestamp = System.currentTimeMillis();
File tempFile = new File("/tmp/log_" + timestamp + ".txt");
// Attacker can predict the timestamp
try (FileWriter writer = new FileWriter(tempFile)) {
writer.write("Sensitive log data");
}
}
Insecure permissions on Windows
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
// VULNERABLE - World-readable permissions
public void saveWithInsecurePermissions(String data) throws IOException {
Path tempFile = Paths.get("C:\\Temp\\data.txt");
// Default permissions may be too permissive
Files.write(tempFile, data.getBytes());
// On Windows, file may be readable by Everyone
// On Unix, depends on umask (often 0644)
}
Not cleaning up temp files
import java.io.*;
import java.util.Random;
// VULNERABLE - Temp files accumulate
public String processSensitiveData(String data) throws IOException {
Random random = new Random();
File tempFile = new File("/tmp/data_" + random.nextInt(10000) + ".tmp");
try (FileWriter writer = new FileWriter(tempFile)) {
writer.write(data);
}
String result = analyze(tempFile.getAbsolutePath());
// File never deleted - sensitive data persists
return result;
}
Secure Patterns
Using Files.createTempFile (Java 7+)
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
public class SecureTemp {
public void processSecureData(String data) throws IOException {
// Create temp file with secure random name
Path tempFile = Files.createTempFile("secure_", ".tmp");
try {
// Set restrictive permissions (owner only)
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");
Files.setPosixFilePermissions(tempFile, perms);
// Write sensitive data
Files.write(tempFile, data.getBytes());
// Process the file
processFile(tempFile.toFile());
} finally {
// Always delete the temp file
Files.deleteIfExists(tempFile);
}
}
}
Why this works:
- Cryptographically random filenames:
Files.createTempFile()usesSecureRandominternally, making filenames unpredictable to attackers attempting to pre-create or guess temp file names - Automatic location: Files placed in system's designated temp directory automatically
- Restrictive permissions:
PosixFilePermissionsrw-------(0600) ensures only file owner can read/write, preventing other users from accessing sensitive data - Guaranteed cleanup: Try-finally block ensures deletion even on exceptions, preventing sensitive data persistence in temp directory
- Comprehensive protection: Combination of unpredictable names + restrictive permissions + guaranteed cleanup
When to use: Best default choice for Java applications - built-in, secure, cross-platform.
Using File.createTempFile with deleteOnExit
import java.io.*;
public void processWithAutoCleanup(String data) throws IOException {
// Create temp file with unpredictable name
File tempFile = File.createTempFile("prefix_", ".tmp");
// Register for deletion on JVM exit (backup cleanup)
tempFile.deleteOnExit();
try {
// Write data
try (FileWriter writer = new FileWriter(tempFile)) {
writer.write(data);
}
// Process the file
processFile(tempFile);
} finally {
// Explicit deletion (preferred over deleteOnExit)
if (tempFile.exists()) {
tempFile.delete();
}
}
}
Why this works:
- Unpredictable filenames:
File.createTempFile()uses cryptographic randomness, preventing filename prediction attacks - Backup cleanup:
deleteOnExit()registers file for deletion when JVM exits normally (not sufficient alone - won't delete on crash/kill signals) - Immediate cleanup: Explicit
delete()in finally block provides immediate cleanup, ensuring sensitive data doesn't persist even if process forcibly terminated - Defense in depth: Explicit deletion handles normal execution,
deleteOnExit()serves as backup for abnormal but graceful shutdowns - Default restrictive permissions: On most systems, creates files with 0600 on Unix (explicit permission setting still recommended for sensitive data)
When to use: When you need both immediate cleanup and backup deletion guarantee - good for long-running applications that might be restarted.
Creating temp file with custom directory
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
public void createInSecureDirectory(String data) throws IOException {
// Create user-specific temp directory
Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"),
"myapp-" + System.getProperty("user.name"));
// Create directory with owner-only permissions
if (!Files.exists(tempDir)) {
Set<PosixFilePermission> dirPerms = PosixFilePermissions.fromString("rwx------");
FileAttribute<Set<PosixFilePermission>> attrs =
PosixFilePermissions.asFileAttribute(dirPerms);
Files.createDirectories(tempDir, attrs);
}
// Create temp file in secure directory
Path tempFile = Files.createTempFile(tempDir, "work_", ".dat");
try {
// Set restrictive permissions
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");
Files.setPosixFilePermissions(tempFile, perms);
Files.write(tempFile, data.getBytes());
processFile(tempFile.toFile());
} finally {
Files.deleteIfExists(tempFile);
}
}
Why this works:
- Namespace isolation: User-specific directory (
myapp-username) prevents attackers from predicting/pre-creating files in shared temp directories - Secure permissions:
rwx------ (0700)ensures only owner can list/read/write;Files.createDirectories()withPosixFilePermissions.asFileAttribute()atomically creates with permissions - Inherited protection: Files created inside with
createTempFile(tempDir, ...)inherit directory restrictions; explicitrw-------on files adds defense-in-depth - Batch processing: Valuable for applications processing multiple temp files - all benefit from directory-level isolation with cryptographically random filenames
- Platform note: Works on Unix-like systems with POSIX permissions; requires ACL configuration on Windows for equivalent protection
When to use: Applications that need a dedicated workspace for multiple temporary files with directory-level isolation from other users.
Using try-with-resources and AutoCloseable
import java.io.*;
import java.nio.file.*;
public class TempFileResource implements AutoCloseable {
private final Path tempFile;
public TempFileResource(String prefix, String suffix) throws IOException {
this.tempFile = Files.createTempFile(prefix, suffix);
// Set secure permissions immediately
try {
Set<PosixFilePermission> perms =
PosixFilePermissions.fromString("rw-------");
Files.setPosixFilePermissions(tempFile, perms);
} catch (UnsupportedOperationException e) {
// Platform doesn't support POSIX (e.g., Windows)
// File.createTempFile already creates with restricted access on Windows
}
}
public Path getPath() {
return tempFile;
}
public void write(byte[] data) throws IOException {
Files.write(tempFile, data);
}
@Override
public void close() throws IOException {
Files.deleteIfExists(tempFile);
}
// Usage
public static void processData(String data) throws IOException {
try (TempFileResource temp = new TempFileResource("secure_", ".tmp")) {
temp.write(data.getBytes());
processFile(temp.getPath().toFile());
}
// Automatic cleanup when close() is called
}
}
Why this works:
- Automatic resource management:
AutoCloseableworks with try-with-resources, guaranteeingclose()is called even if exceptions occur - Eliminates cleanup risks: Developers can't forget to clean up temp files
- Unpredictable filenames: Constructor uses
Files.createTempFile()for cryptographically random names - Immediate permission setting: Sets secure permissions (
0600) before returning - file never exists with insecure permissions - Cross-platform compatibility: Catches
UnsupportedOperationExceptionwhen setting POSIX permissions - works on Windows (no POSIX support) and Unix - Encapsulation: Reusable class promotes consistent security practices across codebase
- Prevents security gaps: Developers can't accidentally skip permission setting or cleanup steps
When to use: Java applications needing reusable, foolproof temp file management with automatic cleanup guarantees.
Secure permissions on Windows and Unix
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
public void createSecureMultiplatform(String data) throws IOException {
Path tempFile = Files.createTempFile("secure_", ".tmp");
try {
// Set permissions based on OS
if (tempFile.getFileSystem().supportedFileAttributeViews().contains("posix")) {
// Unix/Linux - use POSIX permissions
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");
Files.setPosixFilePermissions(tempFile, perms);
} else {
// Windows - use ACL
File file = tempFile.toFile();
file.setReadable(false, false); // Remove read for others
file.setReadable(true, true); // Set read for owner only
file.setWritable(false, false); // Remove write for others
file.setWritable(true, true); // Set write for owner only
}
Files.write(tempFile, data.getBytes());
processFile(tempFile.toFile());
} finally {
Files.deleteIfExists(tempFile);
}
}
Why this works:
- Automatic OS detection: Detects filesystem capabilities and applies appropriate permission restrictions for each OS
- Unix/Linux POSIX permissions:
rw-------(0600) provides standard owner-only file access understood by all Unix tools - Windows permission handling:
setReadable(false, false)andsetWritable(false, false)remove permissions for all userssetReadable(true, true)andsetWritable(true, true)grant permissions only to file owner
- Cross-platform deployment: Code works correctly on Linux containers, Windows servers, or macOS without changes
- Platform adaptation:
supportedFileAttributeViews().contains("posix")check automatically adapts to platform
When to use: Applications deployed across different operating systems requiring consistent security without platform-specific code branches.
Using Apache Commons IO TempFile utilities
import org.apache.commons.io.FileUtils;
import java.io.*;
import java.nio.file.*;
public void useCommonsIO(String data) throws IOException {
File tempFile = File.createTempFile("prefix_", ".tmp");
tempFile.deleteOnExit();
try {
// Write data using Commons IO
FileUtils.writeStringToFile(tempFile, data, "UTF-8");
// Set secure permissions
tempFile.setReadable(false, false);
tempFile.setReadable(true, true);
tempFile.setWritable(false, false);
tempFile.setWritable(true, true);
processFile(tempFile);
} finally {
FileUtils.deleteQuietly(tempFile);
}
}
Why this works:
- Convenient wrappers: Apache Commons IO's
FileUtilswraps Java file operations while maintaining security - Unpredictable filenames:
File.createTempFile()generates cryptographically random names - Backup cleanup:
deleteOnExit()provides deletion guarantee on normal JVM shutdown - Proper encoding:
FileUtils.writeStringToFile()handles character encoding properly (UTF-8), preventing encoding-related security issues - Permission restrictions:
setReadable()andsetWritable()restrict access to owner only - Robust deletion:
FileUtils.deleteQuietly()attempts deletion without throwing exceptions if file doesn't exist
Note: While convenient for applications using Commons IO, be aware that setReadable/setWritable on Windows has different semantics than POSIX permissions. For maximum security, explicitly set Windows ACLs as shown in other patterns.
Temporary directory management
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
public class TempDirectoryManager implements AutoCloseable {
private final Path tempDir;
public TempDirectoryManager(String prefix) throws IOException {
// Create temp directory with secure permissions
FileAttribute<Set<PosixFilePermission>> attrs = null;
try {
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwx------");
attrs = PosixFilePermissions.asFileAttribute(perms);
this.tempDir = Files.createTempDirectory(prefix, attrs);
} catch (UnsupportedOperationException e) {
// Platform doesn't support POSIX
this.tempDir = Files.createTempDirectory(prefix);
}
}
public Path createFile(String name, byte[] data) throws IOException {
Path file = tempDir.resolve(name);
// Write data
Files.write(file, data);
// Set secure permissions
try {
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");
Files.setPosixFilePermissions(file, perms);
} catch (UnsupportedOperationException e) {
// Windows - set permissions differently
File f = file.toFile();
f.setReadable(false, false);
f.setReadable(true, true);
f.setWritable(false, false);
f.setWritable(true, true);
}
return file;
}
@Override
public void close() throws IOException {
// Delete directory and all contents
if (tempDir != null && Files.exists(tempDir)) {
Files.walk(tempDir)
.sorted(Comparator.reverseOrder())
.forEach(path -> {
try {
Files.delete(path);
} catch (IOException e) {
// Log error
}
});
}
}
// Usage
public static void processMultipleFiles() throws IOException {
try (TempDirectoryManager manager = new TempDirectoryManager("workdir_")) {
Path file1 = manager.createFile("data1.txt", "content1".getBytes());
Path file2 = manager.createFile("data2.txt", "content2".getBytes());
batchProcess(file1, file2);
}
// All files and directory automatically deleted
}
}
Why this works:
- Complete lifecycle management:
AutoCloseableresources ensure automatic cleanup of entire directory trees - Cryptographically random directory names:
Files.createTempDirectory()generates unpredictable names with restrictive permissions (0700on Unix withPosixFilePermissionsattributes) - Directory-level protection: All temp file operations encapsulated within secure directory
- Multiple file support: Create multiple related temp files protected by directory-level permissions
- Reverse deletion order:
Files.walk()withsorted(Comparator.reverseOrder())ensures files deleted before parent directories (required for successful directory deletion) - Exception-safe cleanup: Try-with-resources makes cleanup automatic and exception-safe
When to use: Complex processing requiring multiple temporary files - manages lifecycle and permissions consistently. Ideal for batch operations generating multiple intermediate files.
Spring Framework temporary file handling
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.file.*;
@RestController
public class FileUploadController {
@PostMapping("/upload")
public ResponseEntity<String> handleFileUpload(
@RequestParam("file") MultipartFile file) throws IOException {
// Create secure temp file
Path tempFile = Files.createTempFile("upload_", ".tmp");
try {
// Set secure permissions
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");
Files.setPosixFilePermissions(tempFile, perms);
// Transfer uploaded file to temp location
file.transferTo(tempFile.toFile());
// Validate and process
if (!isValidFile(tempFile)) {
return ResponseEntity.badRequest().body("Invalid file");
}
String result = processUploadedFile(tempFile);
return ResponseEntity.ok(result);
} finally {
Files.deleteIfExists(tempFile);
}
}
}
Why this works:
- Safe file transfer: Spring's
MultipartFile.transferTo()safely transfers uploaded file data to destination - Unpredictable filenames:
Files.createTempFile()provides cryptographically random names and atomic creation - Immediate permission lockdown: POSIX permissions
rw-------set immediately after creation - only owner can access potentially sensitive uploaded data - Pre-processing validation: Validates files (type, size, content) before processing, preventing malicious uploads
- Guaranteed cleanup: Try-finally ensures temp file deletion even if validation fails or processing throws exceptions
- Framework integration: Integrates seamlessly with Spring's
MultipartFileAPI
When to use: Spring Boot applications handling file uploads - especially user-submitted content. For production, also consider virus scanning and storing valid files in secure permanent location.