Creation of Temporary File in Directory with Insecure Permissions
Description
Creation of Temporary File in Directory with Insecure Permissions is a vulnerability that occurs when an application creates temporary files in a directory whose permissions allow unintended actors to determine the file's existence or otherwise access that file. Common shared directories like /tmp on Unix or C:\Windows\Temp on Windows are accessible to all users, making any files created there potentially visible to attackers. Even if individual file permissions are secure, the directory permissions may allow attackers to enumerate files or perform symbolic link attacks.
Risk
Creating temporary files in world-accessible directories exposes information about application behavior. Attackers can determine which applications are in use by monitoring the directory for new files. By correlating temporary files with running processes, adversaries may deduce user activities and plan targeted attacks. Even if file contents are protected, file names and timing of creation can leak sensitive information. Symbolic link attacks in shared directories can redirect file operations to attacker-controlled locations. This reconnaissance capability aids in privilege escalation and targeted exploitation.
Solution
Store sensitive temporary files in non-world-readable directories, preferably per-user directories within the user's home folder. Create a private directory with restrictive permissions (0700) for the application's temporary files. Avoid using system-wide temporary directories for sensitive operations. Use modern language APIs that support specifying custom directories for temporary files. Ensure the parent directory has appropriate permissions before creating temporary files. Consider using memory-based temporary storage for highly sensitive data.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Attackers gain information about what the user is doing through visibility of application temporary files. |
Example Code
Vulnerable Code
// Vulnerable: Creates temp file in world-readable /tmp
void vulnerable_shared_dir() {
char template[] = "/tmp/myapp.XXXXXX";
int fd = mkstemp(template);
if (fd >= 0) {
// Even with 0600 permissions, attackers can:
// - See the file exists in /tmp
// - Know the application is running
// - Attempt timing attacks
write(fd, secret_data, strlen(secret_data));
close(fd);
unlink(template);
}
}
// Vulnerable: Predictable subdirectory in /tmp
void vulnerable_predictable_dir() {
char dirname[] = "/tmp/myapp";
mkdir(dirname, 0755); // World-readable directory!
char filepath[256];
snprintf(filepath, sizeof(filepath), "%s/data.tmp", dirname);
int fd = open(filepath, O_CREAT | O_WRONLY, 0600);
// Directory exposes that myapp is running
}
// Vulnerable: Using system temp directory
import java.io.*;
import java.nio.file.*;
public class VulnerableTempDir {
public void processSecret(String data) throws IOException {
// Vulnerable: System temp dir is world-accessible
Path temp = Files.createTempFile("sensitive", ".tmp");
// File is in /tmp or C:\Windows\Temp
// Other users can see it exists
Files.writeString(temp, data);
}
public void createWorkDir() throws IOException {
// Vulnerable: Creates directory in shared /tmp
Path workDir = Files.createTempDirectory("myapp");
// Directory listing shows myapp is running
Path dataFile = workDir.resolve("data.txt");
Files.writeString(dataFile, "secret");
}
}
# Vulnerable: Using shared /tmp directory
import tempfile
import os
def vulnerable_default_temp():
# Vulnerable: tempfile.gettempdir() returns /tmp
with tempfile.NamedTemporaryFile(delete=False) as f:
f.write(b"sensitive data")
# File visible in /tmp to all users
return f.name
def vulnerable_tmp_socket():
# Vulnerable: Socket in world-accessible directory
import socket
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind("/tmp/myapp.sock") # Any user can see this exists
Fixed Code
// Fixed: Create temp file in private user directory
#include <pwd.h>
#include <unistd.h>
void secure_private_dir() {
struct passwd *pw = getpwuid(getuid());
char dirpath[PATH_MAX];
char filepath[PATH_MAX];
// Fixed: Use private directory in user's home
snprintf(dirpath, sizeof(dirpath), "%s/.myapp/tmp", pw->pw_dir);
// Create private directory
mkdir(pw->pw_dir, 0700); // Ensure home dir exists
snprintf(dirpath, sizeof(dirpath), "%s/.myapp", pw->pw_dir);
mkdir(dirpath, 0700);
snprintf(dirpath, sizeof(dirpath), "%s/.myapp/tmp", pw->pw_dir);
mkdir(dirpath, 0700);
// Create temp file in private directory
snprintf(filepath, sizeof(filepath), "%s/data.XXXXXX", dirpath);
int fd = mkstemp(filepath);
if (fd >= 0) {
write(fd, secret_data, strlen(secret_data));
close(fd);
unlink(filepath);
}
}
// Fixed: Use XDG runtime directory if available
void secure_runtime_dir() {
const char *runtime_dir = getenv("XDG_RUNTIME_DIR");
char template[PATH_MAX];
if (runtime_dir && access(runtime_dir, W_OK) == 0) {
// Fixed: XDG_RUNTIME_DIR is user-private
snprintf(template, sizeof(template), "%s/myapp.XXXXXX", runtime_dir);
} else {
// Fallback to home directory
struct passwd *pw = getpwuid(getuid());
snprintf(template, sizeof(template), "%s/.myapp.XXXXXX", pw->pw_dir);
}
int fd = mkstemp(template);
// ...
}
// Fixed: Use private directory for temp files
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.util.Set;
public class SecureTempDir {
private Path privateTempDir;
public SecureTempDir() throws IOException {
// Fixed: Create private temp directory in user home
Path userHome = Paths.get(System.getProperty("user.home"));
Path appDir = userHome.resolve(".myapp").resolve("tmp");
if (!Files.exists(appDir)) {
Set<PosixFilePermission> perms =
PosixFilePermissions.fromString("rwx------");
Files.createDirectories(appDir,
PosixFilePermissions.asFileAttribute(perms));
}
this.privateTempDir = appDir;
}
public void processSecret(String data) throws IOException {
// Fixed: Create temp file in private directory
Set<PosixFilePermission> perms =
PosixFilePermissions.fromString("rw-------");
Path temp = Files.createTempFile(privateTempDir, "sensitive", ".tmp",
PosixFilePermissions.asFileAttribute(perms));
try {
Files.writeString(temp, data);
processFile(temp);
} finally {
Files.deleteIfExists(temp);
}
}
}
# Fixed: Use private directory for temp files
import os
import tempfile
import stat
def get_private_temp_dir():
"""Get or create a private temp directory for this app."""
# Try XDG_RUNTIME_DIR first (user-private on Linux)
runtime_dir = os.environ.get('XDG_RUNTIME_DIR')
if runtime_dir and os.access(runtime_dir, os.W_OK):
private_dir = os.path.join(runtime_dir, 'myapp')
else:
# Fall back to home directory
private_dir = os.path.expanduser('~/.myapp/tmp')
# Create with restrictive permissions
os.makedirs(private_dir, mode=0o700, exist_ok=True)
# Verify permissions
mode = os.stat(private_dir).st_mode
if mode & (stat.S_IRWXG | stat.S_IRWXO):
raise SecurityError("Temp directory has insecure permissions")
return private_dir
def secure_temp_file():
# Fixed: Use private directory
private_dir = get_private_temp_dir()
with tempfile.NamedTemporaryFile(dir=private_dir, delete=True) as f:
f.write(b"sensitive data")
process_file(f.name)
def secure_unix_socket():
import socket
# Fixed: Socket in private directory
private_dir = get_private_temp_dir()
socket_path = os.path.join(private_dir, 'myapp.sock')
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(socket_path)
os.chmod(socket_path, 0o600)
CVE Examples
- CVE-2022-27818 — Rust hotkey daemon creates domain socket in /tmp accessible to any user.
- CVE-2021-21290 — Java framework uses File.createTempFile() with insecure default permissions in shared directory.
References
- MITRE Corporation. "CWE-379: Creation of Temporary File in Directory with Insecure Permissions." https://cwe.mitre.org/data/definitions/379.html
- freedesktop.org. "XDG Base Directory Specification." https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html