CVE-2026-54901: Oj: Use-After-Free in Oj::Parser array_class/hash_class GC Marking
Summary
Oj::Parser in usual mode does not mark arrayclass and hashclass references during garbage collection. If GC runs after the class is assigned but before a parse, the class object is reclaimed, leaving the parser holding a dangling VALUE. The subsequent parse call dereferences the freed object, producing a segfault.
Version
- Software: oj gem - Affected: all versions with ext/oj/usual.c / ext/oj/parser.c - Latest tested: 3.17.1 (confirmed present)
Details
The parsermark function in ext/oj/parser.c is registered as the GC mark callback for the parser's TypedData. If arrayclass (stored as d->arrayclass in the Usual struct) is not passed to rbgcmark, the GC does not know it is referenced and may collect it.
When closearrayclass (usual.c:405) later calls rbfuncallv on the collected class VALUE, it accesses freed memory, crashing at RIP: 0x7f... / 0x0000000000000000.
Crash output: arrayclass finalized about to parse [BUG] Segmentation fault at 0x0000000000000000 closearrayclass+0x194 /ext/oj/usual.c:405 parse+0x17b3 /ext/oj/parser.c:715 parserparse+0x10b /ext/oj/parser.c:1408 RIP: 0x7fd1b46d68b7 RBP: 0x0000000000000000
Reproduce
ruby require 'oj' p = Oj::Parser.new(:usual, arrayclass: (ac = Class.new { def <<(x); end })) ObjectSpace.definefinalizer(ac, proc { warn 'arrayclass finalized' }) ac = nil GC.start(fullmark: true, immediatesweep: true) # collect the class p.parse('[1]') # segfault
Other sources
Oj (Optimized JSON) is a JSON parser and Object marshaller packaged as a Ruby gem. In versions prior to 3.17.2, Oj::Parser in usual mode does not mark arrayclass and hashclass references during garbage collection, leading to Use-After-Free. If GC runs after the class is assigned but before a parse, the class object is reclaimed, leaving the parser holding a dangling VALUE. The subsequent parse call dereferences the freed object, producing a segfault. This issue has been fixed in version 3.17.2.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
rubygems/ojto a version that resolves this vulnerability.Fixed in 3.17.3 - Upgrade
Upgrade
oj gemto a version that resolves this vulnerability.Fixed in 3.17.2 - Operational
After upgrading to Oj 3.17.2, re-run the workload/parse operation to confirm the previous segfault condition is resolved (the prior parse may have exercised freed VALUEs).
Event History
Frequently Asked Questions
What is the severity of CVE-2026-54901?
CVE-2026-54901 has a risk score of 52, indicating a medium severity vulnerability.
How do I fix CVE-2026-54901?
To fix CVE-2026-54901, update the `oj` gem to the latest version where this issue has been addressed.
What software is affected by CVE-2026-54901?
CVE-2026-54901 affects the `rubygems/oj` library.
What kind of vulnerability is CVE-2026-54901 classified as?
CVE-2026-54901 is classified as a Use After Free vulnerability.
When was CVE-2026-54901 published?
CVE-2026-54901 was published on June 19, 2026.