Skip to content

XSS via quote injection in renderEmail() (email autolink) #192

Description

@rahulramesh96

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 (shared LinkTrait)
  • 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions