{"id":"CVE-2026-35201","aliases":["AZL-82902","DEBIAN-CVE-2026-35201","EUVD-2026-19474","GHSA-6r34-94wq-jhrc","UBUNTU-CVE-2026-35201"],"status":"published","title":"Discount has an Out-of-bounds Read in rdiscount","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.","severity":{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-10","score":0.00285,"percentile":0.21236,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-125"],"published":"2026-04-06T17:53:59Z","modified":"2026-10-28T02:31:09Z","fixes":[{"ecosystem":"RubyGems","package":"rdiscount","fixed_in":["2.2.7.4"],"sources":["ghsa","osv"]},{"ecosystem":"Azure Linux:3","package":"rubygem-rdiscount","fixed_in":["2.2.7.4-1"],"sources":["osv"]}],"affected":[{"source":"ghsa","ecosystem":"RubyGems","package":"rdiscount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.3.1.1"},{"fixed":"2.2.7.4"}]}]},{"source":"osv","ecosystem":"Azure Linux:3","package":"rubygem-rdiscount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.2.7.4-1"}]}]},{"source":"osv","ecosystem":"Debian:12","package":"discount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.2.7-2","2.2.7-2.1"]},{"source":"osv","ecosystem":"Debian:13","package":"discount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.2.7-2.1"]},{"source":"osv","ecosystem":"Debian:14","package":"discount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.2.7-2.1"]},{"source":"osv","ecosystem":"RubyGems","package":"rdiscount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.3.1.1"},{"fixed":"2.2.7.4"}]}],"versions":["1.3.1.1","1.3.4","1.3.5","1.5.5","1.5.8","1.5.8.1","1.6.3","1.6.3.1","1.6.3.2","1.6.5","1.6.8","2.0.7","2.0.7.1","2.0.7.2","2.0.7.3","2.1.6","2.1.7","2.1.7.1","2.1.8","2.2.0","2.2.0.1","2.2.0.2","2.2.7","2.2.7.1","2.2.7.2","2.2.7.3"]},{"source":"osv","ecosystem":"Ubuntu:16.04:LTS","package":"discount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.1.8-2"]},{"source":"osv","ecosystem":"Ubuntu:18.04:LTS","package":"discount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.1.8-2","2.2.3b8-2"]},{"source":"osv","ecosystem":"Ubuntu:20.04:LTS","package":"discount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.2.6-1"]},{"source":"osv","ecosystem":"Ubuntu:22.04:LTS","package":"discount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.2.6-1ubuntu2","2.2.7-2"]},{"source":"osv","ecosystem":"Ubuntu:24.04:LTS","package":"discount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.2.7-2","2.2.7-2build1"]},{"source":"osv","ecosystem":"Ubuntu:25.10","package":"discount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.2.7-2.1"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"discount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.2.7-2.1build1"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"discount","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.2.7-2.1","2.2.7-2.1build1"]}],"products":[{"vendor":"dafoster","product":"rdiscount"},{"vendor":"davidfstr","product":"rdiscount"}],"references":[{"url":"https://github.com/davidfstr/rdiscount/security/advisories/GHSA-6r34-94wq-jhrc","tags":["x_refsource_CONFIRM","Exploit","Vendor Advisory","advisory","web","report"]},{"url":"https://github.com/davidfstr/rdiscount/commit/b1a16445e92e0d12c07594dedcdc56f80b317761","tags":["web"]},{"url":"http://github.com/davidfstr/rdiscount/releases/tag/2.2.7.4","tags":["web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-35201","tags":["web","advisory"]},{"url":"https://github.com/rubysec/ruby-advisory-db/blob/master/gems/rdiscount/CVE-2026-35201.yml","tags":["web"]},{"url":"https://github.com/advisories/GHSA-6r34-94wq-jhrc"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/35xxx/CVE-2026-35201.json","tags":["advisory"]},{"url":"https://security-tracker.debian.org/tracker/CVE-2026-35201","tags":["advisory"]},{"url":"https://github.com/davidfstr/rdiscount","tags":["package"]},{"url":"https://ubuntu.com/security/CVE-2026-35201","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-35201","tags":["report"]}],"sources":{"cve":[{"id":"CVE-2026-35201","title":"Discount has an Out-of-bounds Read in rdiscount","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.","status":"published","published":"2026-04-06T19:49:48.806Z","modified":"2026-04-07T16:21:14.803Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium","assessor":"cna"}],"cwes":["CWE-125"],"updated_at":"2026-11-02T14:20:05.505362Z"}],"euvd":[{"id":"EUVD-2026-19474","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.","status":"published","published":"2026-04-06T19:49:48Z","modified":"2026-04-07T16:21:14Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium"}],"updated_at":"2026-11-02T19:25:12.431163Z"}],"ghsa":[{"id":"GHSA-6r34-94wq-jhrc","title":"rdiscount has an Out-of-bounds Read","description":"### Summary\n\nA 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\n\n### Details\n\nIn both public entry points:\n\n- `ext/rdiscount.c:97`\n- `ext/rdiscount.c:136`\n\n`RSTRING_LEN(text)` is passed directly into `mkd_string()`:\n\n```c\nMMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);\n```\n\n`mkd_string()` accepts `int len`:\n\n- `ext/mkdio.c:174`\n\n```c\nDocument * mkd_string(const char *buf, int len, mkd_flag_t flags)\n{\n    struct string_stream about;\n\n    about.data = buf;\n    about.size = len;\n\n    return populate((getc_func)__mkd_io_strget, \u0026about, flags \u0026 INPUT_MASK);\n}\n```\n\nThe parser stores the remaining input length in a signed `int`:\n\n- `ext/markdown.h:205`\n\n```c\nstruct string_stream {\n    const char *data;\n    int   size;\n};\n```\n\nThe read loop stops only when `size == 0`:\n\n- `ext/mkdio.c:161`\n\n```c\nint __mkd_io_strget(struct string_stream *in)\n{\n    if ( !in-\u003esize ) return EOF;\n\n    --(in-\u003esize);\n\n    return *(in-\u003edata)++;\n}\n```\n\nIf 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.\n\nAffected APIs:\n\n- `RDiscount.new(input).to_html`\n- `RDiscount.new(input).toc_content`\n\n### PoC\n\nCrash via `to_html`:\n\n```sh\nRUBYLIB=lib:ext ruby -e 'require \"rdiscount\"; n=2_200_000_000; s = \"a\" * n; warn \"built=#{s.bytesize}\"; RDiscount.new(s).to_html\"'\n```\nresult:\n\n- `built=2200000000`\n- Ruby terminates with `[BUG] Segmentation fault`\n- top control frame: `CFUNC :to_html`\n\nsame result with `toc_content`\n\n### Impact\n\nThis 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.\n\n### Fix\n\njust add a checked length guard before the `mkd_string()` call in both public entry points:\n\n- `ext/rdiscount.c:97`\n- `ext/rdiscount.c:136`\nex: \n```c\nVALUE text = rb_funcall(self, rb_intern(\"text\"), 0);\nlong text_len = RSTRING_LEN(text);\nVALUE buf = rb_str_buf_new(1024);\nCheck_Type(text, T_STRING);\n\nif (text_len \u003e INT_MAX) {\n    rb_raise(rb_eArgError, \"markdown input too large\");\n}\n\nMMIOT *doc = mkd_string(RSTRING_PTR(text), (int)text_len, flags);\n```\n\nThe same guard should be applied in `rb_rdiscount_toc_content()` before its `mkd_string()` call.","status":"published","published":"2026-04-06T17:53:59Z","modified":"2026-05-13T16:20:39Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium"}],"cwes":["CWE-125"],"updated_at":"2026-11-02T14:40:08.003212Z"}],"nvd":[{"id":"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.","status":"published","published":"2026-04-06T20:16:27.893Z","modified":"2026-07-24T21:10:00.143Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium","assessor":"secondary"}],"cwes":["CWE-125"],"updated_at":"2026-11-02T14:12:13.1424Z"}],"osv":[{"id":"CVE-2026-35201","title":"Discount has an Out-of-bounds Read in rdiscount","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.","status":"published","published":"2026-04-06T19:49:48.806Z","modified":"2026-10-28T02:31:09.468629118Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium"}],"cwes":["CWE-125"],"updated_at":"2026-11-02T15:45:02.673625Z"},{"id":"DEBIAN-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.","status":"published","published":"2026-04-06T20:16:27.893Z","modified":"2026-10-01T03:02:38.690740787Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium"}],"updated_at":"2026-11-02T15:45:54.587575Z"},{"id":"GHSA-6r34-94wq-jhrc","title":"rdiscount has an Out-of-bounds Read","description":"### Summary\n\nA 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\n\n### Details\n\nIn both public entry points:\n\n- `ext/rdiscount.c:97`\n- `ext/rdiscount.c:136`\n\n`RSTRING_LEN(text)` is passed directly into `mkd_string()`:\n\n```c\nMMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);\n```\n\n`mkd_string()` accepts `int len`:\n\n- `ext/mkdio.c:174`\n\n```c\nDocument * mkd_string(const char *buf, int len, mkd_flag_t flags)\n{\n    struct string_stream about;\n\n    about.data = buf;\n    about.size = len;\n\n    return populate((getc_func)__mkd_io_strget, \u0026about, flags \u0026 INPUT_MASK);\n}\n```\n\nThe parser stores the remaining input length in a signed `int`:\n\n- `ext/markdown.h:205`\n\n```c\nstruct string_stream {\n    const char *data;\n    int   size;\n};\n```\n\nThe read loop stops only when `size == 0`:\n\n- `ext/mkdio.c:161`\n\n```c\nint __mkd_io_strget(struct string_stream *in)\n{\n    if ( !in-\u003esize ) return EOF;\n\n    --(in-\u003esize);\n\n    return *(in-\u003edata)++;\n}\n```\n\nIf 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.\n\nAffected APIs:\n\n- `RDiscount.new(input).to_html`\n- `RDiscount.new(input).toc_content`\n\n### PoC\n\nCrash via `to_html`:\n\n```sh\nRUBYLIB=lib:ext ruby -e 'require \"rdiscount\"; n=2_200_000_000; s = \"a\" * n; warn \"built=#{s.bytesize}\"; RDiscount.new(s).to_html\"'\n```\nresult:\n\n- `built=2200000000`\n- Ruby terminates with `[BUG] Segmentation fault`\n- top control frame: `CFUNC :to_html`\n\nsame result with `toc_content`\n\n### Impact\n\nThis 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.\n\n### Fix\n\njust add a checked length guard before the `mkd_string()` call in both public entry points:\n\n- `ext/rdiscount.c:97`\n- `ext/rdiscount.c:136`\nex: \n```c\nVALUE text = rb_funcall(self, rb_intern(\"text\"), 0);\nlong text_len = RSTRING_LEN(text);\nVALUE buf = rb_str_buf_new(1024);\nCheck_Type(text, T_STRING);\n\nif (text_len \u003e INT_MAX) {\n    rb_raise(rb_eArgError, \"markdown input too large\");\n}\n\nMMIOT *doc = mkd_string(RSTRING_PTR(text), (int)text_len, flags);\n```\n\nThe same guard should be applied in `rb_rdiscount_toc_content()` before its `mkd_string()` call.","status":"published","published":"2026-04-06T17:53:59Z","modified":"2026-05-13T16:35:44.190293Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium"}],"cwes":["CWE-125"],"updated_at":"2026-11-02T15:46:39.965326Z"},{"id":"UBUNTU-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.","status":"published","published":"2026-04-06T20:16:00Z","modified":"2026-10-17T12:58:12.698462755Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium"}],"updated_at":"2026-11-02T16:56:16.686388Z"},{"id":"AZL-82902","title":"CVE-2026-35201 affecting package rubygem-rdiscount for versions less than 2.2.7.4-1","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.","status":"published","published":"2026-04-06T20:16:27Z","modified":"2026-08-28T17:56:35.503414Z","updated_at":"2026-11-02T15:28:10.335477Z"}]}}
