CVE-2026-35201

CVE-2026-35201 is a medium-severity out-of-bounds read vulnerability in rdiscount (rubygems), affecting versions >= 1.3.1.1, < 2.2.7.4. It is fixed in 2.2.7.4.

Summary

A signed length truncation bug causes an out-of-bounds read in the default Markdown parse path. Inputs larger than INT_MAX are truncated to a signed int before entering the native parser, allowing the parser to read past the end of the supplied buffer and crash the process

Details

In both public entry points:

  • ext/rdiscount.c:97
  • ext/rdiscount.c:136

RSTRING_LEN(text) is passed directly into mkd_string():

MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);

mkd_string() accepts int len:

  • ext/mkdio.c:174
Document * mkd_string(const char *buf, int len, mkd_flag_t flags)
{
    struct string_stream about;

    about.data = buf;
    about.size = len;

    return populate((getc_func)__mkd_io_strget, &about, flags & INPUT_MASK);
}

The parser stores the remaining input length in a signed int:

  • ext/markdown.h:205
struct string_stream {
    const char *data;
    int   size;
};

The read loop stops only when size == 0:

  • ext/mkdio.c:161
int __mkd_io_strget(struct string_stream *in)
{
    if ( !in->size ) return EOF;

    --(in->size);

    return *(in->data)++;
}

If the Ruby string length exceeds INT_MAX, the value can truncate to a negative int. In that state, the parser continues incrementing data and reading past the end of the original Ruby string, causing an out-of-bounds read and native crash.

Affected APIs:

  • RDiscount.new(input).to_html
  • RDiscount.new(input).toc_content

PoC

Crash via to_html:

RUBYLIB=lib:ext ruby -e 'require "rdiscount"; n=2_200_000_000; s = "a" * n; warn "built=#{s.bytesize}"; RDiscount.new(s).to_html"'

result:

  • built=2200000000
  • Ruby terminates with [BUG] Segmentation fault
  • top control frame: CFUNC :to_html

same result with toc_content

Impact

This is an out-of-bounds read with the main issue being reliable denial-of-service. Impacted is limited to deployments parses attacker-controlled Markdown and permits multi-GB inputs.

A read operation accesses a memory location beyond the intended buffer boundary. Typical impact: sensitive data disclosure or crash.

CVE-2026-35201 has a CVSS score of 5.9 (Medium). The vector is network-reachable, no privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (2.2.7.4); upgrading removes the vulnerable code path.

Affected versions

rdiscount (>= 1.3.1.1, < 2.2.7.4)

Security releases

rdiscount → 2.2.7.4 (rubygems)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

See it in your environment

Remediation advice

just add a checked length guard before the mkd_string() call in both public entry points:

  • ext/rdiscount.c:97
  • ext/rdiscount.c:136
    ex:
VALUE text = rb_funcall(self, rb_intern("text"), 0);
long text_len = RSTRING_LEN(text);
VALUE buf = rb_str_buf_new(1024);
Check_Type(text, T_STRING);

if (text_len > INT_MAX) {
    rb_raise(rb_eArgError, "markdown input too large");
}

MMIOT *doc = mkd_string(RSTRING_PTR(text), (int)text_len, flags);

The same guard should be applied in rb_rdiscount_toc_content() before its mkd_string() call.

Frequently Asked Questions

  1. What is CVE-2026-35201? CVE-2026-35201 is a medium-severity out-of-bounds read vulnerability in rdiscount (rubygems), affecting versions >= 1.3.1.1, < 2.2.7.4. It is fixed in 2.2.7.4. A read operation accesses a memory location beyond the intended buffer boundary.
  2. How severe is CVE-2026-35201? CVE-2026-35201 has a CVSS score of 5.9 (Medium). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
  3. Which versions of rdiscount are affected by CVE-2026-35201? rdiscount (rubygems) versions >= 1.3.1.1, < 2.2.7.4 is affected.
  4. Is there a fix for CVE-2026-35201? Yes. CVE-2026-35201 is fixed in 2.2.7.4. Upgrade to this version or later.
  5. Is CVE-2026-35201 exploitable, and should I be worried? Whether CVE-2026-35201 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  6. What actually determines whether CVE-2026-35201 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  7. How do I fix CVE-2026-35201? Upgrade rdiscount to 2.2.7.4 or later.

Other vulnerabilities in rdiscount

Stop the waste.
Protect your environment with Kodem.