# Python vulnerability: reading arbitrary process memory

Python's _json scanstring accepted a negative index, letting raw_decode read out-of-bounds process memory and leak adjacent objects.

- Payout: hidden
- Severity: medium
- Program: Internet Bug Bounty
- Found by: guido
- Disclosed: 2014-06-20
- CVE: CVE-2014-4616
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/12297
- Library page: https://bugbountylibrary.com/r/h1%3A12297
- Tags: area:oss domain:oss impact:data-leak kind:bounty platform:hackerone sev:medium tech:python technique:source-review vuln:info-disclosure vuln:memory-corruption

**Target:** _json C module scanstring/raw_decode
**Root cause:** scanner_call parses idx as signed Py_ssize_t and scan_once_unicode only checks idx >= length, never idx < 0, so PyUnicode_READ indexes the buffer with a negative offset.
**Steps:**
1. Create two strings a and b, compute diff = id(a) - id(b).
2. Call `j.raw_decode(b, diff)` where diff is negative.
3. Observe the returned value is the contents of a, not b.
4. Harvest memory by looping `j.raw_decode(a, 0 - x)` over a range to scan for valid JSON in process memory.
**How found:** Code review of _json.c: noticed PyArg_ParseTupleAndKeywords uses 'n' (signed) for idx, then traced scan_once_unicode and saw only an upper-bound check `idx >= length`, making negative indices pass into PyUnicode_READ's unchecked array access.
**Exploitation:** Attacker who controls the string and index passed to raw_decode supplies a negative index; the array address plus negative index wraps to memory below the buffer, returning adjacent object contents (e.g. another string) as decoded JSON. Large negative values segfault; tuned offsets leak valid JSON arrays from process memory.
**Insight:** When auditing C extensions, check every signed index parsed via 'n'/'i' for a lower-bound check; a lone `idx >= length` guard is a classic OOB read/write primitive, and id() differences give a reliable offset oracle for turning it into a memory disclosure.

