PT-2026-51087 · Rubygems · Oj

Published

2026-06-19

·

Updated

2026-06-19

·

CVE-2026-54901

CVSS v4.0

8.7

High

VectorAV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

Summary

Oj::Parser in usual mode does not mark array class and hash class 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 parser mark function in ext/oj/parser.c is registered as the GC mark callback for the parser's TypedData. If array class (stored as d->array class in the Usual struct) is not passed to rb gc mark, the GC does not know it is referenced and may collect it.
When close array class (usual.c:405) later calls rb funcallv on the collected class VALUE, it accesses freed memory, crashing at RIP: 0x7f... / 0x0000000000000000.
Crash output:
array class finalized
about to parse
[BUG] Segmentation fault at 0x0000000000000000
  close array class+0x194 /ext/oj/usual.c:405
  parse+0x17b3       /ext/oj/parser.c:715
  parser parse+0x10b    /ext/oj/parser.c:1408
RIP: 0x7fd1b46d68b7 RBP: 0x0000000000000000

Reproduce

ruby
require 'oj'
p = Oj::Parser.new(:usual,
 array class: (ac = Class.new { def <<( x); end }))
ObjectSpace.define finalizer(ac, proc { warn 'array class finalized' })
ac = nil
GC.start(full mark: true, immediate sweep: true) # collect the class
p.parse('[1]') # segfault

Fix

Use After Free

Found an issue in the description? Have something to add? Feel free to write us 👾

Weakness Enumeration

Related Identifiers

CVE-2026-54901
GHSA-VWM4-62GF-X745

Affected Products

Oj