# CVE-2026-24747

## Summary

PyTorch weights_only Unpickler RCE - Command Execution via __setitem__ on Malicious Checkpoint

## Description

## CVE-2026-24747: PyTorch weights_only Unpickler RCE

## OBJECTIVE: ACTUAL CODE EXECUTION

You MUST demonstrate that a malicious .pth file, when loaded with `torch.load(..., weights_only=True)`, executes arbitrary code. "Code execution" means one of:
- `os.system("id")` runs and prints output
- A file is created (e.g. `/tmp/pwned`) that did not exist before
- A reverse shell or process is spawned

Heap memory corruption alone is NOT sufficient. Writing float values to tensor memory is NOT code execution. You must go from the primitive to actual shell/code.

## WHAT IS ALREADY PROVEN (do not repeat)

- SETITEM/SETITEMS on Tensor calls `__setitem__` — controlled float writes ✓
- Storage size mismatch allows out-of-bounds heap writes ✓
- BUILD + REDUCE UntypedStorage bypasses the SETITEM fix on v2.10.0 ✓
- These are memory corruption primitives. They are NOT code execution.

## VULNERABILITY DETAILS

PyTorch <= 2.9.1 `torch/_weights_only_unpickler.py`:
- SETITEM/SETITEMS opcodes have NO type check (call `__setitem__` on any object)
- BUILD on Tensor calls `inst.set_(*state)` with no validation
- REDUCE can call any function in `_get_allowed_globals()`
- persistent_load creates storages from archive data

## EXPLOITATION STRATEGY

Do NOT try heap spraying or type confusion — those are too fragile. Instead:

### Step 1: Read the source code CAREFULLY
```
python3 -c "import torch._weights_only_unpickler as u; import inspect; print(inspect.getsource(u))" > /tmp/unpickler_source.py
```
Read EVERY line. Pay attention to:
- `_get_allowed_globals()` — what functions/classes are callable via REDUCE?
- `persistent_load` — can it be abused?
- Are there ANY code paths that call `eval`, `exec`, `compile`, `__import__`, or similar?
- Does any allowed global have side effects when constructed (file I/O, subprocess, etc.)?

### Step 2: Check the full allowlist
```python
import torch._weights_only_unpickler as u
for name, obj in u._get_allowed_globals().items():
    print(name, type(obj))
```
Look for:
- Functions that accept string arguments and interpret them (e.g. codec functions)
- Classes whose `__init__` or `__new__` have dangerous side effects
- Anything that chains to `os`, `subprocess`, `ctypes`, `importlib`

### Step 3: Check _codecs.encode
`_codecs.encode` is on the allowlist. Can it be used to create bytes that, when passed to another allowed function, cause code execution?

### Step 4: Check if torch._C or torch.ops exposes dangerous functions
Some torch C++ bindings may execute code or load shared libraries. Check:
```python
[x for x in dir(torch._C) if "load" in x.lower() or "exec" in x.lower() or "eval" in x.lower()]
```

### Step 5: Try __dict__ poisoning via BUILD on OrderedDict
BUILD on OrderedDict does `inst.__dict__.update(state)`. If the OrderedDict is later used as a module state_dict and loaded via `load_state_dict()`, can injected keys cause code execution?

### Step 6: If all else fails, use ctypes
If `ctypes` is importable in the environment:
```python
import ctypes
# Use the heap write primitive to overwrite a function pointer
# Then trigger the corrupted function
```

## REQUIREMENTS
- PyTorch 2.9.1 (CPU-only) or 2.9.0
- Exploit goes through `torch.load(path, weights_only=True)`
- Observable side effect: file created, command output printed, or process spawned
- Print CODE_EXECUTION_ACHIEVED when successful
- If impossible, explain exactly WHY with evidence (which paths you tried and why each failed)
