Steps to reproduce
Expected Result
In cases 1) and 2) the same censored link is shown in step 3) and 4)
In cases 3) and 4) the URL in shown as plaintext in step 3) and 4)
Actual Result
In case 1) the output differs between step 3) and 4)
In case 3) the output is invisibble in step 4)
In case 4) the output as a clickable link, effectively allowing the user to inject JavaScript.
Replacing method
- Add the following censored words with replacement
Word or phrase Replacement (optional) replaceword censorword replaceword https://javascript javascript - Add posts with the following BB code
[url unfurl="true"]https://censorword.does.not.exist[/url]
[url]https://censorword.does.not.exist[/url]
[url unfurl="true"]about://censorword.does.not.exist[/url]
https://javascript:alert('called!');
- View rendered HTML with unfurl enabled
- View rendered HTML with unfurl disabled
Expected Result
In cases 1) and 2) the same censored link is shown in step 3) and 4)
In cases 3) and 4) the URL in shown as plaintext in step 3) and 4)
Actual Result
In case 1) the output differs between step 3) and 4)
In case 3) the output is invisibble in step 4)
In case 4) the output as a clickable link, effectively allowing the user to inject JavaScript.
Replacing method
XF\BbCodeRenderer\Html::renderTagUrl
with smth. like the following code (+ additional changes to support new option noCensor
) seems to fix this for me:
PHP:
public function shouldUnfurl(string $url, $option, array $options): bool
{
if (
is_array($option)
&& isset($option['unfurl'])
&& $option['unfurl'] === 'true'
&& !empty($options['allowUnfurl'])
)
{
return true;
}
return false;
}
public function renderTagUrl(array $children, $option, array $tag, array $options)
{
$unfurl = false;
$options['noCensor'] = true;
$text = '';
if ($option !== null && !is_array($option))
{
$options['lightbox'] = false;
$url = $option;
$text = $this->renderSubTree($children, $options);
}
else
{
$unfurl = true;
$url = $this->renderSubTreePlain($children);
}
$url = $this->formatter->censorText($url);
if ($text === '')
{
$text = $this->prepareTextFromUrlExtended($url, $options);
}
$url = $this->getValidUrl($url);
if (!$url)
{
return $text;
}
if ($unfurl && $this->shouldUnfurl($url, $option, $options))
{
return $this->getRenderedUnfurl($url, $options, $text);
}
return $this->getRenderedLink($text, $url, $options);
}