Affected component: Shaarli 0.16.3, setting general.header_link (ConfigureController::save, application/front/controller/admin/ConfigureController.php:78), rendered as the site title link in tpl/default/page.header.html via PageBuilder::initialize (application/render/PageBuilder.php:138).
CWE: CWE-79 (Improper Neutralization of Input During Web Page Generation).
Required privileges: Administrator.
Summary
The "Home link" configuration value (general.header_link) is rendered into the href of the Shaarli title/logo link that appears in the header of every page. The value is stored with HTML escaping but without any URL protocol filtering, so an administrator can store a javascript: URI. Any visitor who clicks the title link then executes attacker-controlled JavaScript.
Bookmark URLs, which are rendered in the same kind of href, are protocol-filtered through whitelist_protocols. The header link is not, so it is the one title-bar destination that still accepts a script URI.
Details
The value is stored with escape() only:
// application/front/controller/admin/ConfigureController.php
78: $this->container->conf->set('general.header_link', escape($request->getParam('titleLink')));
escape() is htmlspecialchars(..., ENT_COMPAT), which encodes <, >, &, and " but leaves javascript:alert(document.domain) unchanged (it contains none of those characters). No whitelist_protocols is applied.
It is then assigned untouched and emitted directly into the href:
// application/render/PageBuilder.php
137: if ($this->conf->exists('general.header_link')) {
138: $this->tpl->assign('titleLink', $this->conf->get('general.header_link'));
<!-- tpl/default/page.header.html (lines 5 and 17) -->
<a href="{$titleLink}" class="pure-menu-link shaarli-title" id="shaarli-title-mobile">
<a href="{$titleLink}" class="pure-menu-link shaarli-title" id="shaarli-title-desktop">
PoC
- Sign in as the administrator and open the configuration page (Tools, then "Configure your Shaarli").
- In the "Home link" field, enter
javascript:alert(document.domain) and save.
- Open any page of the instance.
- Click the Shaarli title or logo in the top-left. The browser runs the stored script in the Shaarli origin.
Impact
The payload is stored and rendered on every page, so it reaches every visitor of the instance, authenticated or not. A visitor who clicks the title link runs the script in the Shaarli origin.
Remediation
Apply the existing protocol filter to the header link, the same control already used for bookmark URLs:
// application/front/controller/admin/ConfigureController.php
$this->container->conf->set(
'general.header_link',
escape(whitelist_protocols($request->getParam('titleLink'), $this->container->conf->get('security.allowed_protocols', [])))
);
whitelist_protocols rewrites any non-allowed scheme (including javascript:) to http://, so the stored value can no longer be a script URI. Relative values such as the default / are preserved (they are returned unchanged by whitelist_protocols).
Affected component: Shaarli 0.16.3, setting
general.header_link(ConfigureController::save,application/front/controller/admin/ConfigureController.php:78), rendered as the site title link intpl/default/page.header.htmlviaPageBuilder::initialize(application/render/PageBuilder.php:138).CWE: CWE-79 (Improper Neutralization of Input During Web Page Generation).
Required privileges: Administrator.
Summary
The "Home link" configuration value (
general.header_link) is rendered into thehrefof the Shaarli title/logo link that appears in the header of every page. The value is stored with HTML escaping but without any URL protocol filtering, so an administrator can store ajavascript:URI. Any visitor who clicks the title link then executes attacker-controlled JavaScript.Bookmark URLs, which are rendered in the same kind of
href, are protocol-filtered throughwhitelist_protocols. The header link is not, so it is the one title-bar destination that still accepts a script URI.Details
The value is stored with
escape()only:escape()ishtmlspecialchars(..., ENT_COMPAT), which encodes<,>,&, and"but leavesjavascript:alert(document.domain)unchanged (it contains none of those characters). Nowhitelist_protocolsis applied.It is then assigned untouched and emitted directly into the
href:PoC
javascript:alert(document.domain)and save.Impact
The payload is stored and rendered on every page, so it reaches every visitor of the instance, authenticated or not. A visitor who clicks the title link runs the script in the Shaarli origin.
Remediation
Apply the existing protocol filter to the header link, the same control already used for bookmark URLs:
whitelist_protocolsrewrites any non-allowed scheme (includingjavascript:) tohttp://, so the stored value can no longer be a script URI. Relative values such as the default/are preserved (they are returned unchanged bywhitelist_protocols).