fix(security): escape the project name in the analytic modal title

LayoutHelper::analytic() prefixes the title with the raw project name, and
the AJAX branch of analytic/layout.php printed that title as is, so a
project name containing markup was injected into the analytic modals.

Escape it with $this->text->e() like the other layouts do. It does not
double-encode, so the ">" separator still renders as ">".
This commit is contained in:
dualfroz committed 2026-10-03 15:58:07 +02:00
1 parent 392b2d737b
commit bb891e182e
2 files changed
+24 -1

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
<?php if ($is_ajax): ?>
<div class="page-header">
<h2><?= $title ?></h2>
<h2><?= $this->text->e($title) ?></h2>
</div>
<?php else: ?>
<?= $this->projectHeader->render($project, 'TaskListController', 'show') ?>
+23
View File
@@ -3,6 +3,7 @@
namespace KanboardTests\units\Core;
use KanboardTests\units\Base;
use Kanboard\Core\Http\Request;
use Kanboard\Core\Security\Role;
use Kanboard\Core\Template;
@@ -82,4 +83,26 @@ class TemplateTest extends Base
$html
);
}
public function testAnalyticAjaxLayoutEscapesProjectNameInTitle()
{
$this->container['request'] = new Request($this->container, array(
'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest',
));
$html = $this->container['helper']->layout->analytic('analytic/task_distribution', array(
'project' => array('id' => 1, 'name' => '<img src=x onerror=alert(document.domain)>'),
'metrics' => array(),
'title' => 'Task distribution',
));
$this->assertStringNotContainsString(
'<img src=x onerror=alert(document.domain)>',
$html
);
$this->assertStringContainsString(
'<h2>&lt;img src=x onerror=alert(document.domain)&gt; &gt; Task distribution</h2>',
$html
);
}
}