Problem Framing
Python's widespread adoption across various domains, from web development and data science to AI/ML and system administration, makes it a prime target for attackers. Its interpreted nature, dynamic typing, and rich ecosystem of third-party packages introduce a broad attack surface. Understanding the common vulnerabilities and exploitation vectors within the Python landscape is crucial for application security professionals. This guide aims to provide a practitioner-focused overview of Python's security posture, highlighting key risks and mitigation strategies relevant to experienced security professionals.
Core Mechanics
Python's execution model, while offering flexibility, also presents inherent security challenges. The ability to dynamically execute code, load modules from arbitrary locations, and interact with the underlying operating system are powerful features that, if misused or improperly secured, can lead to severe vulnerabilities.
One fundamental mechanism is the use of built-in functions like eval() and exec(). These functions can execute arbitrary Python code passed as strings. While useful for legitimate purposes like dynamic configuration or scripting, they are a direct conduit for code injection if the input is not rigorously validated and sanitized. For instance, an attacker could supply malicious code to eval() that deletes files or executes shell commands. A safer alternative for evaluating simple literals is ast.literal_eval(), which restricts evaluation to Python literals like strings, numbers, tuples, lists, dicts, booleans, and None [1].
Another critical area is deserialization, particularly with the pickle module. pickle is designed to serialize and deserialize arbitrary Python object structures. This process can be exploited because the __reduce__ method of pickled objects can be manipulated to execute arbitrary code during deserialization [2][3]. An attacker can craft a malicious pickle payload that, when deserialized, triggers RCE. Tools like pickletools can be used to disassemble pickle byte streams, aiding in the analysis of suspicious data [S-internal-tooling]. Beyond pickle, other serialization formats like PyYAML, JSON (via libraries like jsonpickle), and marshal also present deserialization risks if used with untrusted data without proper safeguards [4].
Python's package management system, primarily pip, and its ecosystem are frequent targets for supply chain attacks. Malicious packages can be introduced to PyPI through various means, including typosquatting, compromised maintainer accounts, or CI/CD pipeline manipulation [5][6]. These poisoned packages might execute malicious code upon installation, either directly or by leveraging Python's startup hooks, such as .pth files, to achieve persistence or steal credentials [5][6]. The uv and pipx tools are modern alternatives for package management that can improve dependency management and isolation [S-internal-tooling]. Pinning dependencies with cryptographic hashes using uv lock or uv pip compile --generate-hashes is a vital defense mechanism [S-internal-tooling].
Python's standard library also contains modules that, when used incorrectly, can lead to vulnerabilities. For example, the os.system() function and the subprocess module can be used to execute shell commands. If user-supplied input is passed directly to these functions without proper sanitization, command injection becomes a significant risk [S-internal-tooling]. Similarly, network-related modules can be vulnerable if input is not validated, leading to issues like HTTP Response Splitting via CRLF injection in libraries like aiohttp [S-internal-tooling].
Notable Techniques
Several specific techniques are commonly employed by attackers targeting Python applications. Understanding these provides actionable intelligence for defense.
Insecure Deserialization: This remains a pervasive threat. Exploiting pickle is a classic example, where an attacker crafts a pickle payload that executes arbitrary code upon deserialization [2][3]. Libraries like PyYAML can be vulnerable if yaml.load() is used instead of yaml.safe_load() [4]. jsonpickle also presents similar risks [4]. Even specialized libraries like LangChain and Azure Core have seen vulnerabilities related to insecure deserialization, leading to secret extraction or RCE [7][S-aggregate-summaries]. The shelve module, which uses pickle internally, is also susceptible [4].
Code Injection: Beyond eval() and exec(), code injection can occur through various channels. This includes server-side template injection (SSTI), particularly in templating engines like Jinja2, where malformed inputs can lead to arbitrary code execution [8]. AI-generated code in LLM frameworks like Langflow and CrewAI has also been identified as a vector for code injection due to insufficient validation [S-aggregate-summaries].
Supply Chain Attacks: This category is broad and constantly evolving.
- Package Poisoning: Malicious packages are uploaded to repositories like PyPI. This can be through typosquatting (e.g.,
coloramavs.colourama), name confusion, or by compromising legitimate packages. The Ultralytics package was poisoned via GitHub Actions to deliver a cryptominer [S-aggregate-summaries]. The LiteLLM package compromise by TeamPCP serves as a prime example, where a compromised CI/CD pipeline was used to inject malicious code [5][6]. .pthHook Exploitation: Python.pth(path) files can be used to inject code into the Python path at startup. Malicious packages can install these hooks to achieve persistence and credential theft [5][6].- CI/CD Manipulation: Attackers compromise CI/CD pipelines (e.g., GitHub Actions) to inject malicious code into build processes or deploy poisoned packages [5]. The Shai-Hulud worm campaign notably targeted PyPI via compromised npm accounts, demonstrating cross-ecosystem attacks [S-aggregate-summaries].
Credential Theft: Attackers are adept at harvesting credentials from various sources. This includes API keys stored insecurely in code or environment variables, cloud provider credentials, and even secrets embedded in malware or exfiltrated through custom backdoors. The LiteLLM compromise included credential theft mechanisms [5][6].
Directory Traversal: Vulnerabilities like directory traversal can occur in web applications when user-supplied input is used in file path operations without proper sanitization. The startswith() method's limitations were exploited in Flask-Admin to achieve this [9].
Denial of Service (DoS): Excessive resource consumption can lead to DoS. The python-Pillow library has had vulnerabilities causing DoS via memory exhaustion [S-aggregate-summaries]. The Starlette framework has also seen DoS vulnerabilities related to multipart form data handling and ReDoS [S-aggregate-summaries].
Vulnerability Exploitation via Malformed HTTP Headers: The "BadHost" vulnerability in Starlette (affecting frameworks like FastAPI, vLLM, and LiteLLM) allows access control bypass by manipulating the Host header [10]. This impacts AI agents by potentially rerouting requests or altering their intended targets.
Remote Code Execution (RCE): This is a common outcome of many of the above techniques. Insecure deserialization, code injection via SSTI, and exploiting vulnerable dependencies can all lead to RCE. Notable examples include CVE-2026-45829 in ChromaDB via embedded model execution [11], CVE-2026-5760 in SGLang via GGUF files and Jinja2 SSTI [8], and CVE-2026-39987 in Marimo via unauthenticated WebSocket endpoints [S-aggregate-summaries].
Privilege Escalation: In specific environments, vulnerabilities in Python or the underlying OS can lead to privilege escalation. CVE-2026-31431 (Copy Fail) in the Linux Kernel allows privilege escalation with a small Python script [12].
AI/ML Model Security: The growing use of AI/ML models in Python applications introduces new attack vectors. Malicious GGUF files can exploit vulnerabilities in model loaders, leading to RCE [13][8]. Insecure deserialization can also impact ML frameworks [11].
Detection & Prevention
A multi-layered approach is necessary to detect and prevent Python-related vulnerabilities.
Static Analysis (SAST): SAST tools are invaluable for identifying potential vulnerabilities in source code without executing it.
- Bandit: A well-established SAST tool specifically designed for Python, it checks for common security issues [S-internal-tooling].
- Semgrep: A powerful semantic code analysis tool that supports custom rule writing, making it adaptable to emerging threats and organization-specific coding standards [14]. Semgrep Guardian is also relevant for AI-generated code [14].
- Pylint/Flake8/Pyflakes: General linters that can be configured with security-focused rules [S-internal-tooling].
- Mypy: While primarily for type checking, static type information can indirectly help in identifying potential runtime errors that might lead to vulnerabilities [S-internal-tooling].
- Commercial SAST Tools: Tools like Checkmarx SAST, Veracode, and GitHub Advanced Security (CodeQL) offer comprehensive SAST capabilities for Python [S-internal-tooling].
Dynamic Analysis (DAST): DAST tools test running applications for vulnerabilities. While less Python-specific, they are crucial for web applications. Tools like Wapiti can be used for web vulnerability scanning [S-internal-tooling].
Dependency Scanning: Identifying known vulnerabilities in third-party packages is critical.
- Snyk: A popular tool for dependency scanning and vulnerability detection in Python projects [S-internal-tooling].
- pip-audit: A tool to check for known CVEs in installed dependencies [S-internal-tooling].
- Safety: Another dependency vulnerability scanning tool [S-internal-tooling].
- Software Bill of Materials (SBOMs): Generating SBOMs (e.g., using CycloneDX) helps track dependencies and their associated vulnerabilities [S-internal-tooling].
Secure Coding Practices:
- Input Validation and Sanitization: Always validate and sanitize all user-supplied input, especially when it's used in file operations, database queries, or command execution.
- Avoiding Insecure Functions: Minimize the use of
eval()andexec(). If dynamic code execution is necessary, consider safer alternatives or robust sandboxing. - Secure Deserialization: Avoid deserializing untrusted data. If it's unavoidable, use safe deserialization formats or libraries and consider tools like
Picklescan(though its bypasses need careful consideration) [15]. - Dependency Management: Pin dependencies with precise versions and cryptographic hashes to prevent unexpected updates introducing vulnerabilities. Regularly audit and update dependencies. Use tools like
pip-auditorSnykto identify vulnerable packages [S-internal-tooling]. - Secrets Management: Never hardcode secrets (API keys, passwords). Use secure secret management solutions, environment variables, or dedicated secrets management tools like
keyring[16]. - Principle of Least Privilege: Ensure that processes and applications run with the minimum necessary permissions.
- Secure Configuration: Follow security best practices for web frameworks (e.g., Django, Flask) regarding HTTPS, session management, and input validation [S-internal-tooling].
Runtime Security:
- Sandboxing: For running untrusted code, employ sandboxing techniques. Linux's
seccompand resource modules can help limit the capabilities of processes [17]. - Dynamic Instrumentation: Tools like Frida can be used for dynamic analysis and security testing of running Python applications.
Supply Chain Security:
- Trusted Publishing: Implement secure package publishing workflows, potentially using OIDC and Sigstore for signing and attestation [S-internal-tooling].
- CI/CD Security: Secure CI/CD pipelines against compromise. Isolate build environments and restrict access to sensitive credentials. Monitor CI/CD logs for suspicious activity.
Tooling
A robust set of tools is available for securing Python applications.
Static Analysis:
- Semgrep: For flexible, semantic code analysis and custom rule creation [14].
- Bandit: Python-specific SAST for common vulnerabilities [S-internal-tooling].
- Mypy: Static type checking [S-internal-tooling].
- Pylint, Flake8, Pyflakes: Code linters that can be configured for security checks [S-internal-tooling].
Dependency Management & Scanning:
- pipx/uv: Modern package managers for isolated environments and secure dependency management [S-internal-tooling].
- pip-audit: CVE scanning for dependencies [S-internal-tooling].
- Snyk: Comprehensive dependency scanning and vulnerability detection [S-internal-tooling].
- Safety: Dependency vulnerability scanning [S-internal-tooling].
- CycloneDX: For generating SBOMs [S-internal-tooling].
Security Testing & Analysis:
pickletools: Disassembles pickle byte streams [S-internal-tooling].Picklescan: Scans pickle files for malicious content, though bypasses exist [15].- Wapiti: Web vulnerability scanner [S-internal-tooling].
httpdbg: Debugging HTTP(S) client requests [18].- ProxyHunter: GUI proxy for intercepting and modifying HTTP requests [19].
- JWTAuditor: JWT security analysis and exploitation platform [20].
ctypes: For C interop and interacting with low-level APIs [21].cryptographylibrary: For secure cryptographic operations [22][S-internal-tooling].os.system,subprocess: For system command execution (use with extreme caution) [S-internal-tooling].ast.literal_eval(): Safer alternative toeval()for literals [1].
Runtime & System Tools:
seccomp&resourcemodule: For sandboxing untrusted code on Linux [17].- Frida: Dynamic instrumentation toolkit [S-internal-tooling].
- Manhole: Provides an interactive prompt into running Python processes for debugging [23].
Network Analysis:
- Scapy: Powerful packet manipulation, crafting, and analysis library [24].
- Nmap: Network scanning [S-internal-tooling].
- Impacket: Collection of Python classes for low-level network protocol interaction, particularly SMB and MSRPC [25].
Secure Development Frameworks:
- Drawbridge: Drop-in SSRF protection for
requestsorhttpx[26].
Recent Developments
The Python security landscape is dynamic, with new vulnerabilities and attack vectors emerging regularly.
AI/LLM Security: The rapid integration of Large Language Models (LLMs) into Python applications has introduced new attack surfaces. Vulnerabilities in libraries handling AI models, such as ChromaDB's RCE via embedded models [11] and SGLang's RCE via malicious GGUF files [8], highlight the risks. Code injection via AI-generated code in frameworks like Langflow and CrewAI is also a growing concern [S-aggregate-summaries].
Sophisticated Supply Chain Attacks: Attackers are becoming more sophisticated in their supply chain attacks. The compromise of the LiteLLM package via a poisoned security scanner's CI/CD pipeline is a stark reminder of how attackers can pivot through development workflows to achieve their goals [5][6]. The TeamPCP campaign, involving multiple compromised Python packages like DurableTask and LiteLLM, demonstrates sustained and targeted efforts [27][28]. The Shai-Hulud worm campaign's reach across package repositories underscores the interconnectedness of the software ecosystem [S-aggregate-summaries].
PickleScan Bypasses: Despite the existence of tools like Picklescan for detecting malicious pickle files, attackers have found multiple ways to bypass it. This includes using specific file extensions, manipulating ZIP archive flags, and subclassing dangerous imports [15]. This emphasizes that Picklescan should not be the sole defense against deserialization attacks.
Exploiting Undocumented Parameters: The discovery of RCE in PLY (Python Lex-Yacc) via an undocumented picklefile parameter illustrates how attackers can leverage obscure or internal features of libraries for exploitation [29].
Infrastructure-as-Code (IaC) and CI/CD Security: As organizations increasingly rely on IaC and automated CI/CD pipelines, these systems become prime targets. Compromises like the one affecting the Trivy CI/CD pipeline, which then led to the LiteLLM backdoor, demonstrate the cascading impact of a single compromised infrastructure component [6].
Emerging Deserialization Vulnerabilities: New deserialization vulnerabilities continue to be found in various libraries, including LangChain Core [7] and Azure Core [S-aggregate-summaries].
Where to Go Deeper
For practitioners seeking to deepen their understanding of Python security, several avenues are available:
- Official Documentation: The Python standard library documentation is an essential resource, especially for understanding the behavior and potential pitfalls of built-in modules.
- Security-Focused Blogs and Write-ups: Regularly follow security research blogs and platforms that detail Python vulnerabilities. Sites like Snyk's blog [1][5][6], InfosecWriteups [9][30], and Eval.blog [31] often provide in-depth analyses of specific exploits and techniques.
- Vulnerability Databases: Utilize CVE databases (e.g., NVD, MITRE) and security advisories to stay informed about newly discovered vulnerabilities in Python packages.
- OWASP Resources: The OWASP Top Ten list provides a foundational understanding of common web application security risks, many of which are directly applicable to Python web applications [S-internal-tooling]. OWASP Pygoat is a learning platform for secure coding [32].
- Tooling Documentation: Thoroughly explore the documentation of security tools like Semgrep [14], Bandit, Snyk, and Scapy [24]. Understanding their capabilities and limitations is key to effective application security.
- CTF Challenges: Participating in Capture The Flag (CTF) competitions, especially those with web exploitation or reverse engineering categories, can provide hands-on experience with Python-related vulnerabilities.
- Source Code Review: Regularly perform manual source code reviews of critical Python applications and dependencies. Tools like
git guardiancan help scan for secrets. - Academic Research and Security Conferences: Keep an eye on research presented at security conferences and in academic papers, as these often detail novel attack vectors and defense mechanisms.
- Practical Guides and Tutorials: Resources like "Python for Researchers" [21] and guides on building specific security tools (e.g., vulnerability scanners [33], reverse shells [34]) offer practical insights.
- Dependency Analysis Tools: Actively use and understand the output of dependency scanning tools like
pip-auditandSnyk[S-internal-tooling]. - Secure Coding Best Practices: Refer to comprehensive guides on secure Python development, such as those that cover managing secrets [16] and secure serialization practices [4].
- Understanding Python Internals: Deeper knowledge of Python's internals, including its object model, memory management, and execution flow, can significantly aid in identifying and exploiting vulnerabilities. Resources on
picklemanipulation [2][3] and bytecode analysis [35][36] are valuable.