XSS via quote injection in renderEmail() (email autolink)
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
Research direction
Start in inline/LinkTrait.php at renderEmail() and trace how parseLt() sends email autolinks there. Reproduce the quoted local-part input from the issue, then add coverage for the generated HTML. Done means quotes in an autolink cannot become HTML attribute syntax or an event handler, while ordinary email autolinks still render correctly.
Written by the indexing model from the issue text.
Description
renderEmail() in inline/LinkTrait.php (lines 194-198, unchanged since 2014-10-10) escapes the parsed email address with htmlspecialchars(..., ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8'), which does not escape double-quote characters, and then interpolates it into a double-quoted HTML href attribute:
protected function renderEmail($block)
{
$email = htmlspecialchars($block[1], ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8');
return "<a href=\"mailto:$email\">$email</a>";
}
The email autolink regex in parseLt() (/^<([^\s>]*?@[^\s]*?\.\w+?)>/) allows " in the local part. Input <"onmouseover=alert(1)//@x.y> is parsed as an email autolink and rendered as:
<p><a href="mailto:"onmouseover=alert(1)//@x.y">"onmouseover=alert(1)//@x.y</a></p>
Verified with html5lib (faithful HTML5 tokenizer): the browser parses this as <a href="mailto:" onmouseover='alert(1)//@x.y"'> — a live onmouseover event handler. On hover, alert(1) executes.
Why this is distinct from CVE-2018-1000874
That CVE (DISPUTED) was about fenced-code-block raw HTML passthrough. This bug is not raw HTML passthrough: parseLt() routes <...@x.y> to renderEmail() before the raw-HTML fallback (parseInlineHtml). The broken HTML is generated by the library from a markdown-syntax autolink, not passed through from user HTML. I acknowledge the maintainer's documented position that output should be filtered with HTML Purifier; this is offered as an escaping defect the library itself introduces.
Affected
Markdown,MarkdownExtra,GithubMarkdown(sharedLinkTrait)- Versions: ≥1.1.2 through 1.2.1 and master (
2b2461b) - No fix exists.
CVSS v3.1
5.8 Medium — CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Constraint: the injected portion cannot contain whitespace (regex excludes \s), so the practical payload is interaction-required (onmouseover); no no-interaction payload found.
Suggested fix
protected function renderEmail($block)
{
$email = htmlspecialchars($block[1], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
return "<a href=\"mailto:$email\">$email</a>";
}
Reproduction
<?php
spl_autoload_register(function ($c) {
$f = '/path/to/cebe/markdown/' . str_replace('\\', '/', substr($c, 14)) . '.php';
if (is_file($f)) require $f;
});
$p = new cebe\markdown\Markdown();
echo $p->parse('<"onmouseover=alert(1)//@x.y>'), PHP_EOL;
Output:
<p><a href="mailto:"onmouseover=alert(1)//@x.y">"onmouseover=alert(1)//@x.y</a></p>
Independent discovery during a security audit. Verified novel: OSV empty, GitHub Advisory DB empty, no prior issue/comment mentions renderEmail/mailto/ENT_NOQUOTES.
- Dominant language
- HTML
- Stars
- 1k
- Forks
- 137
- PR merge metrics
- No merged PRs in 30d
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from cebe/markdown
-
Difficulty 5/5 Over a week Newbie friendliness 25/100
-
Maintenance status? Open
Difficulty 5/5 Over a week Newbie friendliness 15/100
-
Difficulty 3/5 1-2 days Newbie friendliness 38/100
-
Difficulty 3/5 1-2 days Newbie friendliness 42/100
-
Difficulty 4/5 3-5 days Newbie friendliness 20/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
AXERA-TECH/ax-llm#75 ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
gitbutlerapp/gitbutler#15998 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
sympozium-ai/sympozium#627 ·
-
clawsweeper:needs-product-decision clawsweeper:no-new-fix-pr clawsweeper:source-repro impact:security impact:ux-friction issue-rating: 🦞 diamond lobster P2
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
TheManticoreProject/Manticore#1383 ·