VYPR
Medium severity5.9NVD Advisory· Published Apr 6, 2026· Updated Apr 16, 2026

CVE-2026-35201

CVE-2026-35201

Description

Discount is an implementation of John Gruber's Markdown markup language in C. From 1.3.1.1 to before 2.2.7.4, 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. This vulnerability is fixed in 2.2.7.4.

Affected products

1
  • cpe:2.3:a:dafoster:rdiscount:*:*:*:*:*:ruby:*:*
    Range: >=1.3.1.1,<2.2.7.4

Patches

1
b1a16445e92e

Guard against oversized markdown input before calling mkd_string

2 files changed · +38 3
  • ext/rdiscount.c+19 3 modified
    @@ -1,4 +1,5 @@
     #include <stdio.h>
    +#include <limits.h>
     #include <locale.h>
     #include "ruby.h"
     #include "mkdio.h"
    @@ -43,6 +44,18 @@ static AccessorFlagPair ACCESSOR_2_FLAG[] = {
     
     static VALUE rb_cRDiscount;
     
    +static int
    +rb_rdiscount__text_len(VALUE text)
    +{
    +    long text_len = RSTRING_LEN(text);
    +
    +    if (text_len > INT_MAX) {
    +        rb_raise(rb_eArgError, "markdown input too large");
    +    }
    +
    +    return (int)text_len;
    +}
    +
     int rb_rdiscount__get_flags(VALUE ruby_obj)
     {
         AccessorFlagPair *entry;
    @@ -78,8 +91,10 @@ rb_rdiscount_to_html(int argc, VALUE *argv, VALUE self)
         int szres;
         VALUE encoding;
         VALUE text = rb_funcall(self, rb_intern("text"), 0);
    -    VALUE buf = rb_str_buf_new(1024);
         Check_Type(text, T_STRING);
    +    int text_len = rb_rdiscount__text_len(text);  // may rb_raise
    +    
    +    VALUE buf = rb_str_buf_new(1024);
     
         int flags = rb_rdiscount__get_flags(self);
         
    @@ -94,7 +109,7 @@ rb_rdiscount_to_html(int argc, VALUE *argv, VALUE self)
         char *old_locale = strdup(setlocale(LC_CTYPE, NULL));
         setlocale(LC_CTYPE, "C");   /* ASCII (and passthru characters > 127) */
     
    -    MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);
    +    MMIOT *doc = mkd_string(RSTRING_PTR(text), text_len, flags);
     
         if ( mkd_compile(doc, flags) ) {
             szres = mkd_document(doc, &res);
    @@ -129,11 +144,12 @@ rb_rdiscount_toc_content(int argc, VALUE *argv, VALUE self)
         /* grab char pointer to markdown input text */
         VALUE text = rb_funcall(self, rb_intern("text"), 0);
         Check_Type(text, T_STRING);
    +    int text_len = rb_rdiscount__text_len(text);  // may rb_raise
     
         /* allocate a ruby string buffer and wrap it in a stream */
         VALUE buf = rb_str_buf_new(4096);
     
    -    MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);
    +    MMIOT *doc = mkd_string(RSTRING_PTR(text), text_len, flags);
     
         if ( mkd_compile(doc, flags) ) {
             szres = mkd_toc(doc, &res);
    
  • test/rdiscount_test.rb+19 0 modified
    @@ -21,6 +21,25 @@ def test_that_discount_does_not_blow_up_with_weird_formatting_case
         RDiscount.new(text).to_html
       end
     
    +  def test_that_oversized_input_raises_argument_error
    +    # mkd_string() takes an int length, so inputs > INT_MAX (2 147 483 647 bytes)
    +    # must be rejected before reaching C to avoid integer truncation / overflow.
    +    int_max = 2_147_483_647  # INT_MAX in C
    +    begin
    +      oversized_text = 'a' * (int_max + 1)
    +    # ArgumentError on TruffleRuby; RangeError on Windows
    +    rescue NoMemoryError, ArgumentError, RangeError
    +      # `omit` is Test::Unit's native skip; `skip` is Minitest's. Support both.
    +      respond_to?(:omit, true) ?
    +        omit("Insufficient memory to create oversized input for this test") :
    +        skip("Insufficient memory to create oversized input for this test")
    +    end
    +
    +    assert_raise(ArgumentError) do
    +      RDiscount.new(oversized_text).to_html
    +    end
    +  end
    +
       def test_that_smart_converts_double_quotes_to_curly_quotes
         rd = RDiscount.new(%("Quoted text"), :smart)
         assert_equal %(<p>&ldquo;Quoted text&rdquo;</p>\n), rd.to_html
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.