Dangerous subinterpreters run_string() Usage

HIGH

subinterpreters.run_string() executes arbitrary Python code strings in sub-interpreters, enabling code injection when called with untrusted input.

Rule Information

Language
Python
Category
Python Core
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonsubinterpreterscode-executionsub-interpreterCWE-95OWASP-A03
CWE References

Interactive Playground

Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.

pathfinder scan --ruleset python/PYTHON-LANG-SEC-023 --project .
1
2
3
4
5
6
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

About This Rule

Understanding the vulnerability and how it is detected

Python's _xxsubinterpreters (also accessible as subinterpreters in some builds) module provides low-level access to CPython's sub-interpreter API, allowing multiple Python interpreters to run in the same process. The run_string() function executes a Python code string inside a specified sub-interpreter.

Despite running in a separate interpreter instance, sub-interpreters do not provide a security sandbox. Code running in a sub-interpreter can still access the filesystem, make network connections, import arbitrary modules, and interact with the host system. If the code string passed to run_string() is derived from untrusted input, an attacker achieves full code execution in the context of the Python process.

This module is experimental and its API has changed between Python versions. Its use in production code is rare and should be carefully audited.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Code Execution in Sub-interpreter

Code executing in a sub-interpreter has full access to the filesystem, network, and installed Python modules. It can spawn subprocesses, open sockets, read files, and import os or subprocess. The sub-interpreter boundary provides isolation from the parent interpreter's namespace but not from host system resources.

2

Inter-interpreter State Leakage

Sub-interpreters share the same process memory space. Through ctypes, cffi, or direct memory access, code in a sub-interpreter may be able to read or corrupt the parent interpreter's memory, bypassing the namespace separation.

3

Experimental API Instability

The subinterpreters API is experimental and has changed across Python versions. Code relying on it may break silently or exhibit unexpected security behaviors on version upgrades, making security properties difficult to reason about.

4

Resource Exhaustion

Injected code running in a sub-interpreter can create threads, allocate large amounts of memory, or perform CPU-intensive operations that consume process resources and cause denial of service for the parent interpreter.

How to Fix

Recommended remediation steps

  • 1Never pass user-controlled strings to subinterpreters.run_string(); there is no security isolation between sub-interpreters and the host filesystem.
  • 2For sandboxed execution of untrusted code, use process isolation with resource limits, seccomp filters, or container-level sandboxing rather than sub-interpreters.
  • 3Use ast.literal_eval() for safe expression evaluation of Python literals without code execution.
  • 4If dynamic computation is needed, use a purpose-built safe expression library that restricts available operations.
  • 5Audit all uses of the subinterpreters module since it is experimental and rarely needed in production application code.

Detection Scope

How Code Pathfinder analyzes your code for this vulnerability

This rule detects calls to _xxsubinterpreters.run_string() and subinterpreters.run_string() in Python source code. All call sites are flagged since this is an experimental low-level API that should not appear in production code and always requires review when found.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

CWE Top 25
CWE-95 - Eval Injection in the MITRE CWE Top 25 Most Dangerous Software Weaknesses
OWASP Top 10
A03:2021 - Injection
NIST SP 800-53
SI-10: Information Input Validation
PCI DSS v4.0
Requirement 6.2.4 - Protect web-facing applications against injection attacks

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about Dangerous subinterpreters run_string() Usage

Sub-interpreters provide namespace isolation — each interpreter has its own module namespace and global state. However, they do NOT provide filesystem isolation, network isolation, or memory isolation. Code in a sub-interpreter can still perform any OS operation, access any file, and potentially access the parent interpreter's memory via ctypes or direct pointer manipulation.
Sub-interpreters are intended for multi-tenancy in frameworks where multiple Python programs need to run in the same process with separate global state (e.g., Python embedded in a web server). They are designed for trusted code isolation (preventing global state pollution), not for security isolation of untrusted code.
run_string() is equally dangerous to eval() for security purposes. Both execute arbitrary Python code. run_string() adds the overhead of a sub-interpreter but provides no additional security boundary against malicious code accessing host resources.
True sandboxing requires process isolation combined with OS-level resource restrictions. Options include: subprocess with seccomp-bpf syscall filtering, Docker containers with read-only filesystems and no network, WebAssembly runtimes (Pyodide, WASM), and dedicated sandboxing services. No pure-Python or CPython-internal mechanism provides true sandboxing.
No. The _xxsubinterpreters module is explicitly experimental and marked as such in CPython source. Its API has changed multiple times between minor Python versions. Using it in production code creates both a security risk and a maintenance burden from API instability.
Low-level sub-interpreter support has existed in CPython's C API since Python 3.x, but the _xxsubinterpreters module exposing it to Python code was added as an experimental feature in Python 3.9. PEP 554 proposes making it a proper public API, but as of Python 3.12 it remains experimental.

New feature

Get these findings posted directly on your GitHub pull requests

The Dangerous subinterpreters run_string() Usage rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works