Skip to content

Commit a048f9d

Browse files
flavorjonesRubySec CI
authored andcommitted
Updated advisory posts against rubysec/ruby-advisory-db@3b738da
1 parent c396493 commit a048f9d

1 file changed

Lines changed: 132 additions & 0 deletions

File tree

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
---
2+
layout: advisory
3+
title: 'CVE-2026-35201 (rdiscount): rdiscount has an Out-of-bounds Read'
4+
comments: false
5+
categories:
6+
- rdiscount
7+
advisory:
8+
gem: rdiscount
9+
cve: 2026-35201
10+
ghsa: 6r34-94wq-jhrc
11+
url: https://github.com/davidfstr/rdiscount/security/advisories/GHSA-6r34-94wq-jhrc
12+
title: rdiscount has an Out-of-bounds Read
13+
date: 2026-04-06
14+
description: |-
15+
### Summary
16+
17+
A signed length truncation bug causes an out-of-bounds read in the
18+
default Markdown parse path. Inputs larger than `INT_MAX` are truncated
19+
to a signed `int` before entering the native parser, allowing the
20+
parser to read past the end of the supplied buffer and crash the process.
21+
22+
### Details
23+
24+
In both public entry points:
25+
26+
- `ext/rdiscount.c:97`
27+
- `ext/rdiscount.c:136`
28+
29+
`RSTRING_LEN(text)` is passed directly into `mkd_string()`:
30+
31+
```c
32+
MMIOT *doc = mkd_string(RSTRING_PTR(text),
33+
RSTRING_LEN(text), flags);
34+
```
35+
36+
`mkd_string()` accepts `int len`:
37+
38+
- `ext/mkdio.c:174`
39+
40+
```c
41+
Document
42+
* mkd_string(const char *buf, int len, mkd_flag_t flags)
43+
{
44+
struct string_stream about;
45+
46+
about.data = buf;
47+
about.size = len;
48+
49+
return populate((getc_func)__mkd_io_strget, &about, flags & INPUT_MASK);
50+
}
51+
```
52+
53+
The parser stores the remaining input length in a signed `int`:
54+
55+
- `ext/markdown.h:205`
56+
57+
```c
58+
struct string_stream {
59+
const
60+
char *data;
61+
int size;
62+
};
63+
```
64+
65+
The read loop stops only when `size == 0`:
66+
67+
- `ext/mkdio.c:161`
68+
69+
```c
70+
int __mkd_io_strget(struct string_stream *in)
71+
{
72+
if ( !in->size ) return EOF;
73+
74+
--(in->size);
75+
76+
return *(in->data)++;
77+
}
78+
```
79+
80+
If the Ruby string length exceeds `INT_MAX`, the value can truncate
81+
to a negative `int`. In that state, the parser continues incrementing
82+
`data` and reading past the end of the original Ruby string, causing
83+
an out-of-bounds read and native crash.
84+
85+
Affected APIs:
86+
87+
- `RDiscount.new(input).to_html`
88+
- `RDiscount.new(input).toc_content`
89+
90+
### Impact
91+
92+
This is an out-of-bounds read with the main issue being reliable
93+
denial-of-service. Impacted is limited to deployments parses
94+
attacker-controlled Markdown and permits multi-GB inputs.
95+
96+
### Fix
97+
98+
just add a checked length guard before the `mkd_string()`
99+
call in both public entry points:
100+
101+
- `ext/rdiscount.c:97`
102+
- `ext/rdiscount.c:136`
103+
ex:
104+
105+
```c
106+
VALUE text = rb_funcall(self, rb_intern(\"text\"), 0);
107+
long text_len = RSTRING_LEN(text);
108+
VALUE buf = rb_str_buf_new(1024);
109+
Check_Type(text, T_STRING);
110+
111+
if (text_len > INT_MAX) {
112+
rb_raise(rb_eArgError, \"markdown input too large\");
113+
}
114+
115+
MMIOT *doc = mkd_string(RSTRING_PTR(text), (int)text_len, flags);
116+
```
117+
118+
The same guard should be applied in `rb_rdiscount_toc_content()`
119+
before its `mkd_string()` call.
120+
cvss_v3: 5.9
121+
unaffected_versions:
122+
- "< 1.3.1.1"
123+
patched_versions:
124+
- ">= 2.2.7.4"
125+
related:
126+
url:
127+
- https://nvd.nist.gov/vuln/detail/CVE-2026-35201
128+
- https://github.com/davidfstr/rdiscount/security/advisories/GHSA-6r34-94wq-jhrc
129+
- http://github.com/davidfstr/rdiscount/releases/tag/2.2.7.4
130+
- https://github.com/davidfstr/rdiscount/commit/b1a16445e92e0d12c07594dedcdc56f80b317761
131+
- https://github.com/advisories/GHSA-6r34-94wq-jhrc
132+
---

0 commit comments

Comments
 (0)