Skip to main content
Sonar.tv
Back
5 Lesser Known Python Security PitfallsNow Playing

5 Lesser Known Python Security Pitfalls

Code SecurityMarch 13th 20248:34Part of SCSE

A focused look at five security vulnerabilities that Python developers frequently overlook, with demonstrations of how SonarQube's security rules detect these pitfalls before they reach a deployed application.

Python's widespread adoption in web applications and systems programming makes understanding its security vulnerabilities critical for developers. While many are familiar with common threats like SQL injection and cross-site scripting, several subtle security pitfalls in Python can compromise code integrity when overlooked. This article explores five lesser-known vulnerabilities that developers should be aware of to build more secure applications.

Python Optimized Mode and Assertion Removal

One of the most dangerous pitfalls occurs when running Python with the -O flag, which enables optimized mode. When activated, this flag removes all assertion statements from the code entirely rather than simply skipping their evaluation. This creates a catastrophic security issue when assertions are used as security checks. A Flask application that relies on assertions to validate critical operations will fail silently in optimized mode, allowing unsafe code to execute without triggering errors. While optimized mode is rarely used in production due to minimal memory savings, developers who distribute Python to multiple machines or attempt to optimize resource usage should avoid this practice entirely or refactor security checks to use explicit conditional statements instead of assertions.

Path Joining Vulnerabilities

The behavior of path joining functions in Python presents unintuitive security risks that developers frequently encounter. Both os.path.join() and pathlib.Path exhibit the same problematic behavior: when joining paths where the second path begins with a forward slash (or backslash on Windows), the function discards the first path entirely and returns only the second path. This occurs because both functions treat absolute paths specially, assuming that an absolute path should replace any previous path components. This vulnerability manifested in a real-world CVE affecting Ajaxterm, a web-based terminal emulator, in 2020. Developers must ensure that user-provided path components are stripped of leading slashes before joining, preventing attackers from bypassing intended directory restrictions through path manipulation.

Zip Slip and Archive Extraction Attacks

The zip slip vulnerability represents a critical threat when extracting archived files without proper validation. This attack occurs when a malicious zip file contains entries with path traversal sequences (such as ../../../) that reference directories outside the intended extraction location. A naive implementation using zipfile.ZipFile() with manual file extraction can inadvertently create files in parent directories or system locations. The secure approach is to use the extract() or extractall() methods provided by the zipfile module, which implement protections against zip slip attacks by validating that extracted files remain within the target directory. Developers must never manually reconstruct file paths from zip entries without comprehensive validation.

Temporary File Path Traversal

Python's tempfile module, while useful for creating temporary files, contains a subtle vulnerability in its prefix parameter. This parameter is susceptible to path traversal attacks when it accepts user input without sanitization. An attacker can inject path sequences into the prefix argument to create temporary files in directories outside the intended temporary directory, potentially accessing or modifying sensitive locations if permission controls are insufficient. Although most systems implement permission restrictions to prevent access to sensitive areas, this vulnerability still represents an attack vector that malicious users can exploit. All input destined for the prefix parameter must be carefully sanitized and validated before use.

IP Address Normalization Bypass

IP address validation represents another area where Python's behavior can be unexpectedly permissive. The ipaddress library normalizes IP addresses in non-standard formats, which can bypass security checks. A user might submit a localhost address in an unusual format (such as using multiple zeros or alternative representations), which the application's validation logic fails to recognize as a local address. However, the ipaddress library normalizes this to 127.0.0.1, causing the application to inadvertently make internal requests to its own services. This vulnerability was particularly acute in Python versions before 3.8, where IP normalization was less strict. Developers using Python versions earlier than 3.8 should validate IP addresses after normalization or upgrade to newer Python versions that implement stricter normalization rules.

Key Takeaways

  • Avoid running Python applications in optimized mode (-O flag), as it removes all assertions and can disable critical security checks
  • Always strip leading path separators from user-supplied path components before joining paths to prevent directory traversal
  • Use the extract() and extractall() methods from zipfile instead of manually extracting archive contents to prevent zip slip attacks
  • Sanitize and validate all user input before passing it to the prefix parameter of temporary file creation functions
  • Upgrade to Python 3.8 or later and validate IP addresses after normalization to prevent attackers from bypassing security checks with malformed addresses