|
| 1 | +# Mktemp Statement |
| 2 | + |
| 3 | +The `tempfile.mktemp()` function in Python's standard library is **deprecated and insecure**. Its use introduces a critical **Time-of-Check to Time-of-Use (TOCTOU)** vulnerability that can be exploited by attackers to compromise your application. |
| 4 | + |
| 5 | +:::{danger} |
| 6 | +**Never use `tempfile.mktemp()` in new code.** The function has been deprecated since Python 2.3 (2003) and removed from Python 3.12+ documentation as a recommended practice. Its continued use represents a significant security risk with no valid justification in modern applications. |
| 7 | +::: |
| 8 | + |
| 9 | +## Security Concerns |
| 10 | + |
| 11 | +### Time-of-Check to Time-of-Use (TOCTOU) Vulnerability |
| 12 | + |
| 13 | +The fundamental flaw in `mktemp()` is the gap between generating a filename and actually using it: |
| 14 | + |
| 15 | +```python |
| 16 | +# VULNERABLE PATTERN |
| 17 | +filename = tempfile.mktemp() # Step 1: Generate unique-sounding name |
| 18 | +# --- TIME GAP --- Attacker can create file here |
| 19 | +with open(filename, 'w') as f: # Step 2: Use the filename |
| 20 | + f.write(data) |
| 21 | +``` |
| 22 | + |
| 23 | +During this time gap, an attacker can: |
| 24 | +1. **Create the file** with malicious content before your application does |
| 25 | +2. **Create a symbolic link** pointing to a critical system file (e.g., `/etc/passwd`) |
| 26 | +3. **Replace the file** after your application creates it but before it's fully written |
| 27 | +4. **Create a directory** with the same name, causing your application to fail or behave unexpectedly |
| 28 | + |
| 29 | +### Race Condition Exploitation |
| 30 | + |
| 31 | +The TOCTOU vulnerability enables several attack vectors: |
| 32 | + |
| 33 | +- **Symlink Attacks**: An attacker creates a symbolic link from the temporary filename to a sensitive file. When your application opens the file for writing, it overwrites the target instead. |
| 34 | +- **File Pre-creation**: An attacker creates the file before your application, potentially with malicious content or permissions that your application later reads. |
| 35 | +- **Denial of Service**: An attacker creates the file or directory, causing your application to crash or fail when attempting to create it. |
| 36 | +- **Data Leakage**: An attacker reads the file contents after creation but before your application secures them. |
| 37 | + |
| 38 | +### No Atomicity Guarantees |
| 39 | + |
| 40 | +`mktemp()` provides **no guarantees** about: |
| 41 | +- **Uniqueness**: The generated name is based on predictable patterns |
| 42 | +- **Exclusivity**: The file may not exist at creation time but could be created by an attacker |
| 43 | +- **Permissions**: Default permissions may be too permissive, exposing sensitive data |
| 44 | +- **Path Security**: The function does not verify the security of the parent directory |
| 45 | + |
| 46 | +### Predictable Name Generation |
| 47 | + |
| 48 | +The name generation algorithm in older Python versions was predictable, allowing attackers to: |
| 49 | +- Pre-emptively create files with known names |
| 50 | +- Calculate future filenames and exploit them |
| 51 | +- Create denial-of-service conditions by pre-creating many files |
| 52 | + |
| 53 | +```python |
| 54 | +import tempfile |
| 55 | + |
| 56 | +# These patterns might be predictable |
| 57 | +file1 = tempfile.mktemp() # /tmp/tmp123456 |
| 58 | +file2 = tempfile.mktemp() # /tmp/tmp123457 |
| 59 | +# Attacker could guess the pattern and pre-create files |
| 60 | +``` |
| 61 | + |
| 62 | + |
| 63 | +## Preventive Measures |
| 64 | + |
| 65 | +### Use `tempfile.mkstemp()` Instead |
| 66 | + |
| 67 | +The safe alternative to `mktemp()` is `tempfile.mkstemp()`, which atomically creates a temporary file with exclusive access: |
| 68 | + |
| 69 | +```python |
| 70 | +import tempfile |
| 71 | +import os |
| 72 | + |
| 73 | +# SECURE: mkstemp() creates the file atomically |
| 74 | +fd, filename = tempfile.mkstemp(suffix='.txt', prefix='myapp_', dir='/secure/temp') |
| 75 | + |
| 76 | +try: |
| 77 | + # Write data using the file descriptor |
| 78 | + with os.fdopen(fd, 'w') as f: |
| 79 | + f.write("Secure data") |
| 80 | + |
| 81 | + # Use the filename if needed |
| 82 | + print(f"Created secure temp file: {filename}") |
| 83 | +finally: |
| 84 | + # Clean up |
| 85 | + os.unlink(filename) |
| 86 | +``` |
| 87 | + |
| 88 | +### Use Context Managers for Automatic Cleanup |
| 89 | + |
| 90 | +For even better security and resource management, use `tempfile.TemporaryFile()` or `tempfile.NamedTemporaryFile()`: |
| 91 | + |
| 92 | +```python |
| 93 | +import tempfile |
| 94 | + |
| 95 | +# SECURE: Automatic cleanup and secure creation |
| 96 | +with tempfile.TemporaryFile(mode='w+', suffix='.txt', prefix='myapp_') as f: |
| 97 | + f.write("Sensitive data") |
| 98 | + f.seek(0) |
| 99 | + data = f.read() |
| 100 | +# File is automatically closed and deleted on context exit |
| 101 | + |
| 102 | +# With a named file (visible in filesystem) |
| 103 | +with tempfile.NamedTemporaryFile(mode='w+', delete=True, suffix='.txt') as f: |
| 104 | + f.write("Another secure use case") |
| 105 | + # File remains accessible via f.name, but is deleted on close |
| 106 | +``` |
| 107 | + |
| 108 | +### Use `tempfile.TemporaryDirectory` for Secure Directories |
| 109 | + |
| 110 | +For temporary directories, use the secure context manager: |
| 111 | + |
| 112 | +```python |
| 113 | +import tempfile |
| 114 | +import os |
| 115 | + |
| 116 | +# SECURE: Creates and automatically cleans up temporary directory |
| 117 | +with tempfile.TemporaryDirectory(prefix='myapp_') as temp_dir: |
| 118 | + temp_file = os.path.join(temp_dir, 'data.txt') |
| 119 | + with open(temp_file, 'w') as f: |
| 120 | + f.write("Secure temporary data") |
| 121 | + # Directory and all contents are removed on exit |
| 122 | +``` |
| 123 | + |
| 124 | +### Implement Defensive Practices |
| 125 | + |
| 126 | +When creating temporary files, always: |
| 127 | + |
| 128 | +1. **Set Appropriate Permissions**: Use `os.umask()` to set restrictive permissions |
| 129 | +2. **Verify Directory Security**: Ensure the target directory is not world-writable |
| 130 | +3. **Use Absolute Paths**: Avoid relying on relative paths or environment variables |
| 131 | +4. **Clean Up**: Always delete temporary files after use, even in error cases |
| 132 | +5. **Limit Exposure**: Minimize the time temporary files exist in the filesystem |
| 133 | + |
| 134 | +### Use Secure Configuration |
| 135 | + |
| 136 | +```python |
| 137 | +import tempfile |
| 138 | +import os |
| 139 | +import stat |
| 140 | + |
| 141 | +def secure_temp_file(data, prefix='myapp_'): |
| 142 | + """ |
| 143 | + Create a secure temporary file with restrictive permissions. |
| 144 | + |
| 145 | + Args: |
| 146 | + data: Content to write to the file |
| 147 | + prefix: Prefix for the temporary filename |
| 148 | + |
| 149 | + Returns: |
| 150 | + The filename of the temporary file |
| 151 | + """ |
| 152 | + # Set restrictive umask temporarily |
| 153 | + old_umask = os.umask(0o177) |
| 154 | + |
| 155 | + try: |
| 156 | + # Create secure temporary file |
| 157 | + fd, filename = tempfile.mkstemp(prefix=prefix, text=True) |
| 158 | + |
| 159 | + # Set restrictive permissions (owner read/write only) |
| 160 | + os.fchmod(fd, stat.S_IRUSR | stat.S_IWUSR) |
| 161 | + |
| 162 | + # Write data |
| 163 | + with os.fdopen(fd, 'w') as f: |
| 164 | + f.write(data) |
| 165 | + |
| 166 | + return filename |
| 167 | + finally: |
| 168 | + # Restore original umask |
| 169 | + os.umask(old_umask) |
| 170 | +``` |
| 171 | + |
| 172 | + |
| 173 | +## Discussion |
| 174 | + |
| 175 | +**Historical Context** |
| 176 | + |
| 177 | +`tempfile.mktemp()` was deprecated in Python 2.3 (2003) after security researchers identified widespread vulnerabilities in applications using the function. Despite being deprecated for over two decades, the function occasionally appears in legacy codebases and beginner tutorials, leading to continued security risks. |
| 178 | + |
| 179 | +## More Information |
| 180 | + |
| 181 | +- [Python `tempfile` Documentation](https://docs.python.org/3/library/tempfile.html) |
| 182 | +- [CWE-367: Time-of-check Time-of-use (TOCTOU) Race Condition](https://cwe.mitre.org/data/definitions/367.html) |
| 183 | +- [CWE-377: Insecure Temporary File](https://cwe.mitre.org/data/definitions/377.html) |
| 184 | +- [CWE-379: Creation of Temporary File in Directory with Incorrect Permissions](https://cwe.mitre.org/data/definitions/379.html) |
0 commit comments