YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
joblib CWE-789: Uncontrolled Memory Allocation via NumpyArrayWrapper.shape
Status: CONFIRMED β READY TO SUBMIT β
Severity: High (P2) β Denial of Service
Target
- Repo: joblib/joblib
- Platform: huntr.com
- Format: joblib
.pkl(numpy pickle)
Root Cause
NumpyArrayWrapper.read_array() computes an allocation size from
self.shape β deserialized from the pickle stream, fully attacker-controlled β
and passes it to np.empty() with no upper-bound check:
# joblib/numpy_pickle.py
shape_int64 = [unpickler.np.int64(x) for x in self.shape] # line 170
count = unpickler.np.multiply.reduce(shape_int64) # line 171
array = unpickler.np.empty(count, dtype=self.dtype) # line 193 β OOM
The int64 cast added in issue #859 prevents integer overflow in the product
but does not cap the resulting value. A large-but-valid product (no overflow)
still triggers an unbounded allocation β the same pattern as TFLite's
MultiplyAndCheckOverflow fix that guards overflow without an allocation ceiling.
Trigger Path
joblib.load('malicious.pkl')
β _unpickle(fobj) [numpy_pickle.py:626]
β NumpyUnpickler.load()
β load_build() [numpy_pickle.py:457]
β NumpyArrayWrapper.read() [numpy_pickle.py:284]
β NumpyArrayWrapper.read_array() [numpy_pickle.py:193]
β np.empty(1_000_000_000_000, dtype=float64)
β MemoryError: Unable to allocate 7.28 TiB
Vulnerable Files
| File | Lines | Issue |
|---|---|---|
joblib/numpy_pickle.py |
170β171 | self.shape from pickle used without bounds check |
joblib/numpy_pickle.py |
193 | np.empty(count, dtype) β uncapped allocation |
PoC Files
poc_joblib_cwe789.pyβ crafts the 229-byte malicious.pkland triggers the crashpoc-evidence.htmlβ self-contained HTML evidence page
Reproduction
pip install joblib numpy
python3 poc_joblib_cwe789.py
Expected output:
joblib 1.5.2 | numpy 2.3.5 | Python 3.13.12
[+] File: /tmp/poc_joblib_cwe789.pkl (229 bytes), shape=(1, 1000000000000)
[*] Calling joblib.load() ...
[!] CWE-789 CONFIRMED: Unable to allocate 7.28 TiB for an array with shape (1000000000000,) and data type float64
Fix
Add an upper-bound check before np.empty() in read_array():
MAX_SAFE_ALLOC_BYTES = 2 * 1024**3 # 2 GiB
alloc_bytes = int(count) * self.dtype.itemsize
if count < 0 or alloc_bytes > MAX_SAFE_ALLOC_BYTES:
raise ValueError(
f"Refusing to allocate {alloc_bytes / 2**30:.1f} GiB for shape "
f"{self.shape}. Possible malicious input."
)
References
- joblib issue #859 (overflow fix, not allocation cap): https://github.com/joblib/joblib/issues/859
- CWE-789: https://cwe.mitre.org/data/definitions/789.html
Inference Providers NEW
This model isn't deployed by any Inference Provider. π Ask for provider support