GHSA-2CW7-V8FF-P88R

Vulnerability from github – Published: 2026-06-19 19:34 – Updated: 2026-06-19 19:34
VLAI
Summary
Oj: Use-After-Free in Oj::Parser Symbol Key Cache Toggle
Details

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
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c 3.17.2"
      },
      "package": {
        "ecosystem": "RubyGems",
        "name": "oj"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.17.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-54899"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-416"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-19T19:34:30Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "### Summary\n\nDisabling `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.\n\n### Version\n\n- **Software**: oj gem\n- **Affected**: all versions with `ext/oj/usual.c`\n- **Latest tested**: 3.17.1 (confirmed present)\n\n### Details\n\n`ext/oj/usual.c`, `opt_symbol_keys_set`:\n\n```c\n// usual.c:1043\u20131051\nif (symbol_keys) {\n    d-\u003ekey_cache = cache_create(...);   // allocate\n} else {\n    cache_free(d-\u003ekey_cache);           // free \u2014 but d-\u003ekey_cache pointer not NULLed\n}\n```\n\nOn the next parse call, `cache_key` \u2192 `cache_intern` reads from `d-\u003ekey_cache` which now points to freed memory.\n\nASAN report:\n```\n==145265==ERROR: AddressSanitizer: heap-use-after-free on address 0x50b00001a318\nREAD of size 8 at 0x50b00001a318 thread T0\n    #0 cache_intern            /ext/oj/cache.c:328\n    #1 cache_key               /ext/oj/usual.c:161\n    #2 close_object            /ext/oj/usual.c:285\n    #3 parse                   /ext/oj/parser.c:693\n    #4 parser_parse            /ext/oj/parser.c:1408\nfreed by thread T0 here:\n    #0 free\n    #1 cache_free              /ext/oj/cache.c:277\n    #2 opt_symbol_keys_set     /ext/oj/usual.c:1051\n    #3 option                  /ext/oj/usual.c:1111\n    #4 parser_missing          /ext/oj/parser.c:1362\n0x50b00001a318 is 40 bytes inside freed 112-byte region [fd]fd fd fd fd fd fd fd\n```\n\n### Reproduce\n\n```ruby\nrequire \u0027oj\u0027\np = Oj::Parser.new(:usual, symbol_keys: true)\np.symbol_keys = false     # frees cache without nulling pointer\np.parse(\u0027{\"attacker\":1}\u0027) # UAF: reads freed cache\n```",
  "id": "GHSA-2cw7-v8ff-p88r",
  "modified": "2026-06-19T19:34:30Z",
  "published": "2026-06-19T19:34:30Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/ohler55/oj/security/advisories/GHSA-2cw7-v8ff-p88r"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/ohler55/oj"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "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",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Oj: Use-After-Free in Oj::Parser Symbol Key Cache Toggle"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…