Skip to content

Commit 10ea911

Browse files
committed
GHSA/SYNC: 1 brand new advisory
1 parent b1e3c15 commit 10ea911

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

gems/rdiscount/CVE-2026-35201.yml

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

0 commit comments

Comments
 (0)