Skip to content

GHSA-2cw7-v8ff-p88r CVE-2026-54899

Oj: Use-After-Free in Oj::Parser Symbol Key Cache Toggle

High RubyGems
Severity
0.0 / 10
High · CVSS 4.0
Exploit chance (EPSS)
0.41%
Chance of exploitation in the next 30 days. Higher than 34.98% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-416 Use After Free
Fix
3.17.2
Upgrade oj to this version or later

Description

Summary

Disabling symbol_keys on a reused Oj::Parser instance triggers a heap use-after-free. When symbol_keys is toggled from true to false, opt_symbol_keys_set frees the internal key cache (cache_free) but does not clear the pointer. The next parse call reads from the freed cache via cache_intern, producing a use-after-free.

Version

  • Software: oj gem
  • Affected: all versions with ext/oj/usual.c
  • Latest tested: 3.17.1 (confirmed present)

Details

ext/oj/usual.c, opt_symbol_keys_set:

// usual.c:1043–1051
if (symbol_keys) {
    d->key_cache = cache_create(...);   // allocate
} else {
    cache_free(d->key_cache);           // free — but d->key_cache pointer not NULLed
}

On the next parse call, cache_key → cache_intern reads from d->key_cache which now points to freed memory.

ASAN report:

==145265==ERROR: AddressSanitizer: heap-use-after-free on address 0x50b00001a318
READ of size 8 at 0x50b00001a318 thread T0
    #0 cache_intern            /ext/oj/cache.c:328
    #1 cache_key               /ext/oj/usual.c:161
    #2 close_object            /ext/oj/usual.c:285
    #3 parse                   /ext/oj/parser.c:693
    #4 parser_parse            /ext/oj/parser.c:1408
freed by thread T0 here:
    #0 free
    #1 cache_free              /ext/oj/cache.c:277
    #2 opt_symbol_keys_set     /ext/oj/usual.c:1051
    #3 option                  /ext/oj/usual.c:1111
    #4 parser_missing          /ext/oj/parser.c:1362
0x50b00001a318 is 40 bytes inside freed 112-byte region [fd]fd fd fd fd fd fd fd

Reproduce

require 'oj'
p = Oj::Parser.new(:usual, symbol_keys: true)
p.symbol_keys = false     # frees cache without nulling pointer
p.parse('{"attacker":1}') # UAF: reads freed cache

Affected versions

RubyGems

PackageVulnerableFixed in
oj
< 3.17.2
3.17.2

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

oj RubyGems → 3.17.2

bundler
bundle update oj # Gemfile: gem "oj", ">= 3.17.2"

Severity breakdown

CVSS 4.0 0.0

CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

Attack vector
Network
Attack complexity
Low
Attack requirements
None
Privileges required
None
User interaction
None
Confidentiality (vulnerable system)
None
Integrity (vulnerable system)
None
Availability (vulnerable system)
High
Confidentiality (subsequent systems)
None
Integrity (subsequent systems)
None
Availability (subsequent systems)
None

Weakness

CWE-416: Use After Free

The product reuses or references memory after it has been freed. At some point afterward, the memory may be allocated again and saved in another pointer, while the original pointer references a location somewhere within the new allocation. Any operations using the original pointer are no longer valid because the memory "belongs" to the code that operates on the new pointer.

How to prevent it
  • Architecture and Design: Choose a language that provides automatic memory management.
  • Implementation: When freeing pointers, be sure to set them to NULL once they are freed. However, the utilization of multiple or complex data structures may lower the usefulness of this strategy.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-475m-ph3x-64gp
Oj: Integer Overflow in Oj.load 2GB String Handling
High Also affects oj
GHSA-m578-w5vf-rfcm
Oj: Use-After-Free in Oj::Parser SAJ Long Key Callback
High Also affects oj
GHSA-vwm4-62gf-x745
Oj: Use-After-Free in Oj::Parser array_class/hash_class GC Marking
High Also affects oj
GHSA-9cv6-qcjw-4grx
Oj: Negative-Size memcpy in Oj::Parser create_id Attribute Handling
High Also affects oj
GHSA-q2gm-54r6-8fwm
Oj: Use-After-Free in Oj::Parser SAJ Callback via Input Mutation
High Also affects oj
GHSA-9ppp-w3g4-fh4q
Oj: Use-After-Free in Oj::Doc Iterators via Reentrant Close
High Also affects oj
GHSA-35w3-pjm6-wj95
Oj: Heap Buffer Overflow in Oj.dump Exception Serialization via Large Indent
High Also affects oj
GHSA-3m6q-jj5j-38c9
Oj: Stack Buffer Overflow in Oj::Doc#each_child via Deeply Nested Input
High Also affects oj
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor