Skip to content

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() uses SecureRandom internally, 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: PosixFilePermissions rw------- (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() with PosixFilePermissions.asFileAttribute() atomically creates with permissions
  • Inherited protection: Files created inside with createTempFile(tempDir, ...) inherit directory restrictions; explicit rw------- 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: AutoCloseable works with try-with-resources, guaranteeing close() 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 UnsupportedOperationException when 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) and setWritable(false, false) remove permissions for all users
    • setReadable(true, true) and setWritable(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 FileUtils wraps 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() and setWritable() 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: AutoCloseable resources ensure automatic cleanup of entire directory trees
  • Cryptographically random directory names: Files.createTempDirectory() generates unpredictable names with restrictive permissions (0700 on Unix with PosixFilePermissions attributes)
  • 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() with sorted(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 MultipartFile API

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.

Additional Resources