Headline
CVE-2023-28626: Merge pull request from GHSA-8hqf-xjwp-p67v · kivikakk/comrak@ce795b7
comrak is a CommonMark + GFM compatible Markdown parser and renderer written in rust. A range of quadratic parsing issues are present in Comrak. These can be used to craft denial-of-service attacks on services that use Comrak to parse Markdown. This issue has been addressed in version 0.17.0. Users are advised to upgrade. There are no known workarounds for this vulnerability. This issue is also tracked as GHSL-2023-047
@@ -2,7 +2,6 @@ use crate::ctype::isspace; use crate::nodes::{AstNode, ListType, NodeCode, NodeValue, TableAlignment}; use crate::parser::{ComrakOptions, ComrakPlugins}; use crate::scanners; use crate::strings::build_opening_tag; use once_cell::sync::Lazy; use regex::Regex; use std::borrow::Cow; @@ -243,6 +242,40 @@ fn dangerous_url(input: &[u8]) -> bool { scanners::dangerous_url(input).is_some() }
fn escape(output: &mut dyn Write, buffer: &[u8]) -> io::Result<()> { let mut offset = 0; for (i, &byte) in buffer.iter().enumerate() { if NEEDS_ESCAPED[byte as usize] { let esc: &[u8] = match byte { b’"’ => b""", b’&’ => b"&", b’<’ => b"<", b’>’ => b">", _ => unreachable!(), }; output.write_all(&buffer[offset…i])?; output.write_all(esc)?; offset = i + 1; } } output.write_all(&buffer[offset…])?; Ok(()) }
pub fn build_opening_tag(tag: &str, attributes: &HashMap<String, String>) -> String { let mut out = Vec::with_capacity(80); write!(out, "<{}", tag).unwrap();
for (attr, val) in attributes { write!(out, " {}=\"", attr).unwrap(); escape(&mut out, val.as_bytes()).unwrap(); write!(out, “\"”).unwrap() }
write!(out, “>”).unwrap(); unsafe { String::from_utf8_unchecked(out) } }
impl<’o> HtmlFormatter<’o> { fn new( options: &’o ComrakOptions, @@ -267,23 +300,7 @@ impl<’o> HtmlFormatter<’o> { }
fn escape(&mut self, buffer: &[u8]) -> io::Result<()> { let mut offset = 0; for (i, &byte) in buffer.iter().enumerate() { if NEEDS_ESCAPED[byte as usize] { let esc: &[u8] = match byte { b’"’ => b""", b’&’ => b"&", b’<’ => b"<", b’>’ => b">", _ => unreachable!(), }; self.output.write_all(&buffer[offset…i])?; self.output.write_all(esc)?; offset = i + 1; } } self.output.write_all(&buffer[offset…])?; Ok(()) escape(&mut self.output, buffer) }
fn escape_href(&mut self, buffer: &[u8]) -> io::Result<()> {
Related news
### Impact A range of quadratic parsing issues from `cmark`/`cmark-gfm` are also present in Comrak. These can be used to craft denial-of-service attacks on services that use Comrak to parse Markdown. ### Patches 0.17.0 contains fixes to known quadratic parsing issues. ### Workarounds n/a ### References * https://github.com/commonmark/cmark/issues/255 * https://github.com/commonmark/cmark/issues/389 * https://github.com/commonmark/cmark/issues/373 * https://github.com/commonmark/cmark/issues/299 * https://github.com/commonmark/cmark/issues/388 * https://github.com/commonmark/cmark/issues/284 * https://github.com/commonmark/cmark/issues/218 * https://github.com/commonmark/cmark/pull/232 * https://github.com/github/cmark-gfm/blob/c32ef78bae851cb83b7ad52d0fbff880acdcd44a/test/pathological_tests.py#L63-L65 * https://github.com/github/cmark-gfm/blob/c32ef78bae851cb83b7ad52d0fbff880acdcd44a/test/pathological_tests.py#L87-L89