CVE-2019-7169
Description
Stored self-XSS in Croogo v3.0.5 and earlier allows admin-level attackers to inject arbitrary HTML/JS via the Title field on menu editing pages.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Stored self-XSS in Croogo v3.0.5 and earlier allows admin-level attackers to inject arbitrary HTML/JS via the Title field on menu editing pages.
Vulnerability
A stored cross-site scripting (XSS) vulnerability exists in Croogo Content Management System through version 3.0.5 [1][2]. The Title field on the menu editing page at /admin/menus/menus/edit/3 does not properly sanitize user input before rendering, allowing the injection of arbitrary HTML or JavaScript code [1][2]. This affects the menus administration panel and requires an authenticated user with menu editing privileges to exploit.
Exploitation
An attacker with valid admin credentials can navigate to the menu edit page and input malicious code (e.g., `) into the Title` field [2]. When the menu is saved and subsequently viewed by another admin (or the same admin) on the same page, the injected script executes in the context of the victim's browser [1][2]. The attack is stored, meaning the payload persists across sessions.
Impact
Successful exploitation allows an attacker to execute arbitrary HTML and JavaScript in the browser of an authenticated Croogo administrator [1][2]. This can lead to session hijacking, defacement, or theft of sensitive data accessible through the admin interface. The attack impacts the confidentiality, integrity, and availability of the application from the admin user's perspective.
Mitigation
The vulnerability has been addressed in a commit (cafaaabe2cef3d1d83652370e30563e6ad7c4158) that applies proper escaping via the h() function to the vulnerable fields [4]. Users should upgrade to a version beyond 3.0.5 or apply the patch manually [4]. No official fixed release version has been announced, but the commit is available in the Croogo repository. There is no known inclusion in the CISA KEV catalog.
AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
croogo/croogoPackagist | < 3.0.7 | 3.0.7 |
Affected products
2Patches
123 files changed · +38 −41
Blocks/src/Template/Admin/Blocks/form.ctp+1 −1 modified@@ -7,7 +7,7 @@ $this->extend('Croogo/Core./Common/admin_edit'); $this->Breadcrumbs->add(__d('croogo', 'Blocks'), ['action' => 'index']); if ($this->request->params['action'] == 'edit') { - $this->Breadcrumbs->add($block->title, $this->request->getRequestTarget()); + $this->Breadcrumbs->add(h($block->title), $this->request->getRequestTarget()); } if ($this->request->params['action'] == 'add') { $this->Breadcrumbs->add(__d('croogo', 'Add'), $this->request->getRequestTarget());
Blocks/src/Template/Admin/Regions/form.ctp+1 −1 modified@@ -12,7 +12,7 @@ $this->Breadcrumbs->add(__d('croogo', 'Blocks'), [ ]); if ($this->request->params['action'] == 'edit') { - $this->Breadcrumbs->add($region->title, $this->request->getRequestTarget()); + $this->Breadcrumbs->add(h($region->title), $this->request->getRequestTarget()); } if ($this->request->params['action'] == 'add') {
Contacts/src/Template/Admin/Contacts/form.ctp+1 −1 modified@@ -5,7 +5,7 @@ $this->extend('Croogo/Core./Common/admin_edit'); $this->Breadcrumbs->add(__d('croogo', 'Contacts'), ['controller' => 'contacts', 'action' => 'index']); if ($this->request->params['action'] == 'edit') { - $this->Breadcrumbs->add($contact->title, $this->request->getRequestTarget()); + $this->Breadcrumbs->add(h($contact->title), $this->request->getRequestTarget()); } if ($this->request->params['action'] == 'add') {
Contacts/src/Template/Admin/Messages/form.ctp+1 −1 modified@@ -8,7 +8,7 @@ $this->Breadcrumbs->add(__d('croogo', 'Contacts'), ['plugin' => 'Croogo/Contacts', 'controller' => 'Messages', 'action' => 'index']); if ($this->request->params['action'] == 'edit') { - $this->Breadcrumbs->add($message->title, $this->request->getRequestTarget()); + $this->Breadcrumbs->add(h($message->title), $this->request->getRequestTarget()); } $this->append('form-start', $this->Form->create($message));
Contacts/src/Template/Admin/Messages/index.ctp+5 −5 modified@@ -83,14 +83,14 @@ foreach ($messages as $message) { 'class' => 'row-select', 'id' => 'Messages'. $message->id . 'Id', ]), - $message->contact->title, - $message->name, - $message->email, + h($message->contact->title), + h($message->name), + h($message->email), $commentIcon . ' ' . $this->Html->link($message->title, '#', [ 'class' => 'comment-view', 'data-target' => '#comment-modal', - 'data-title' => $message->title, - 'data-content' => $message->body, + 'data-title' => h($message->title), + 'data-content' => h($message->body), ]), $this->Time->i18nFormat($message->created), $actions,
Contacts/src/Template/Admin/Messages/view.ctp+1 −1 modified@@ -5,7 +5,7 @@ $this->extend('Croogo/Core./Common/admin_view'); $this->Breadcrumbs ->add(__d('croogo', 'Messages'), ['action' => 'index']); - $this->Breadcrumbs->add($message->title, $this->request->getRequestTarget()); + $this->Breadcrumbs->add(h($message->title), $this->request->getRequestTarget()); $this->append('action-buttons'); echo $this->Croogo->adminAction(__d('croogo', 'List Messages'), ['action' => 'index']);
Core/src/View/Helper/CroogoHelper.php+1 −1 modified@@ -168,7 +168,7 @@ public function adminMenus($menus, $options = [], $depth = 0) $menu['htmlAttributes'] += ['icon' => $menu['icon']]; } if ($sidebar) { - $title .= '<span>' . $menu['title'] . '</span>'; + $title .= '<span>' . h($menu['title']) . '</span>'; } else { $title .= $menu['title']; }
Core/src/View/Helper/CroogoHtmlHelper.php+1 −1 modified@@ -224,7 +224,7 @@ public function status($value, $url = []) */ public function link($title, $url = null, array $options = [], $confirmMessage = false) { - $defaults = ['escape' => false]; + $defaults = ['escape' => true]; $options = is_null($options) ? [] : $options; $options = array_merge($defaults, $options); $iconDefaults = $this->config('iconDefaults');
FileManager/src/Template/Admin/Attachments/browse.ctp+1 −1 modified@@ -22,7 +22,7 @@ $this->Html->script('Croogo/FileManager.attachments/browse', ['block' => true]); 'class' => 'text-muted', ]); - $cardHeader = $this->Html->div('card-header', $attachment->title); + $cardHeader = $this->Html->div('card-header', h($attachment->title)); $cardBlock = $this->Html->div('card-body', $thumbnail); $cardFooter = $this->Html->div('card-footer', $footerText); $card = $this->Html->div('card text-center selector',
FileManager/src/Template/Admin/Attachments/edit.ctp+2 −1 modified@@ -5,7 +5,7 @@ $this->extend('Croogo/Core./Common/admin_edit'); $this->Breadcrumbs->add(__d('croogo', 'Attachments'), ['plugin' => 'Croogo/FileManager', 'controller' => 'attachments', 'action' => 'index']) - ->add($attachment->title, $this->request->getRequestTarget()); + ->add(h($attachment->title), $this->request->getRequestTarget()); $this->append('form-start', $this->Form->create($attachment)); @@ -52,6 +52,7 @@ else: endif; $preview = $this->Html->link($imgUrl, $attachment->path, [ 'data-toggle' => 'lightbox', + 'escape' => false, ]); echo $this->Html->beginBox(__d('croogo', 'Preview')) . $preview; echo $this->Html->endBox();
FileManager/src/Template/Admin/Attachments/index.ctp+1 −1 modified@@ -78,7 +78,7 @@ foreach ($attachments as $attachment) { $this->Form->checkbox('Attachments.' . $attachment->id . '.id', ['class' => 'row-select']), $attachment->id, $thumbnail, - $this->Html->tag('div', $attachment->title, ['class' => 'ellipsis']), + $this->Html->tag('div', h($attachment->title), ['class' => 'ellipsis']), $this->Html->tag('div', $this->Html->link($this->Url->build($attachment->path, true), $attachment->path, ['target' => '_blank']), ['class' => 'ellipsis']),
Menus/src/Template/Admin/Links/form.ctp+2 −2 modified@@ -8,7 +8,7 @@ $this->Croogo->adminScript('Croogo/Menus.admin'); $this->Breadcrumbs->add(__d('croogo', 'Menus'), ['controller' => 'Menus', 'action' => 'index']); if ($this->request->params['action'] == 'add') { - $this->Breadcrumbs->add($menu->title, [ + $this->Breadcrumbs->add(h($menu->title), [ 'action' => 'index', '?' => ['menu_id' => $menu->id], ]) @@ -20,7 +20,7 @@ if ($this->request->params['action'] == 'add') { } if ($this->request->params['action'] == 'edit') { - $this->Breadcrumbs->add($menu->title, [ + $this->Breadcrumbs->add(h($menu->title), [ 'action' => 'index', '?' => ['menu_id' => $menu->id], ])
Menus/src/Template/Admin/Links/index.ctp+1 −1 modified@@ -8,7 +8,7 @@ $this->Croogo->adminscript('Croogo/Menus.admin'); $this->extend('Croogo/Core./Common/admin_index'); $this->Breadcrumbs->add(__d('croogo', 'Menus'), ['controller' => 'Menus', 'action' => 'index']) - ->add(__d('croogo', $menu->title), $this->request->getRequestTarget()); + ->add(h(__d('croogo', $menu->title)), $this->request->getRequestTarget()); $this->append('action-buttons'); echo $this->Croogo->adminAction(__d('croogo', 'New link'), ['action' => 'add', 'menu_id' => $menu->id], ['button' => 'success']);
Menus/src/Template/Admin/Menus/form.ctp+1 −1 modified@@ -7,7 +7,7 @@ $this->extend('Croogo/Core./Common/admin_edit'); $this->Breadcrumbs->add(__d('croogo', 'Menus'), ['action' => 'index']); if ($this->request->params['action'] == 'edit') { - $this->Breadcrumbs->add($menu->title, $this->request->getRequestTarget()); + $this->Breadcrumbs->add(h($menu->title), $this->request->getRequestTarget()); $this->assign('title', __d('croogo', 'Edit Menu')); }
Meta/src/Template/Admin/Meta/form.ctp+1 −1 modified@@ -8,7 +8,7 @@ $this->Breadcrumbs->add(__d('croogo', 'Settings'), ['plugin' => 'Croogo/Settings $this->Breadcrumbs->add(__d('croogo', 'Meta'), ['action' => 'index']); if ($this->request->params['action'] == 'edit') { - $this->Breadcrumbs->add($$viewVar->key, $this->request->getRequestTarget()); + $this->Breadcrumbs->add(h($$viewVar->key), $this->request->getRequestTarget()); $this->assign('title', __d('croogo', 'Edit Meta')); }
Nodes/src/Template/Admin/Nodes/form.ctp+7 −11 modified@@ -13,30 +13,26 @@ if ($this->request->params['action'] == 'add') { $this->assign('title', __d('croogo', 'Create content: %s', $type->title)); $this->Breadcrumbs->add(__d('croogo', 'Create'), ['action' => 'create']) - ->add($type->title, $this->request->getRequestTarget()); + ->add(h($type->title), $this->request->getRequestTarget()); } if ($this->request->params['action'] == 'edit') { - $this->Breadcrumbs->add($node->title, $this->request->getRequestTarget(), [ - 'innerAttrs' => [ - 'title' => $node->title, - ], - ]); + $this->Breadcrumbs->add(h($node->title), $this->request->getRequestTarget()); } $this->append('form-start', $this->Form->create($node, [ 'class' => 'protected-form', ])); $this->start('tab-heading'); - echo $this->Croogo->adminTab(__d('croogo', $type->title), '#node-main'); + echo $this->Croogo->adminTab(__d('croogo', h($type->title)), '#node-main'); $this->end(); $this->start('tab-content'); echo $this->Html->tabStart('node-main'); echo $this->Form->input('title', [ 'label' => false, - 'placeholder' => __d('croogo', '%s title', $type->title), + 'placeholder' => __d('croogo', '%s title', h($type->title)), 'data-slug' => '#slug', 'data-slug-editable' => true, 'data-slug-edit-class' => 'btn btn-secondary btn-sm', @@ -66,7 +62,7 @@ $this->start('panels'); $username = isset($node->user->username) ? $node->user->username : $this->request->session() ->read('Auth.User.username'); echo $this->Html->beginBox(__d('croogo', 'Publishing')); - echo $this->element('Croogo/Core.admin/buttons', ['type' => $type->title]); + echo $this->element('Croogo/Core.admin/buttons', ['type' => h($type->title)]); echo $this->element('Croogo/Core.admin/publishable'); echo $this->Form->input('promote', [ @@ -75,7 +71,7 @@ $this->start('panels'); ]); echo $this->Html->endBox(); - echo $this->Html->beginBox(__d('croogo', '%s attributes', $type->title)); + echo $this->Html->beginBox(__d('croogo', '%s attributes', h($type->title))); echo $this->Form->autocomplete('user_id', [ 'label' => __d('croogo', 'Author'), 'options' => $users, @@ -100,7 +96,7 @@ $this->start('panels'); 'options' => $parents, 'default' => $node->parent_id, 'autocomplete' => [ - 'default' => $node->parent ? $node->parent->title : null, + 'default' => $node->parent ? h($node->parent->title) : null, 'data-displayField' => 'title', 'data-queryField' => 'title', 'data-relatedElement' => '#parent-id',
Nodes/src/Template/Nodes/view.ctp+1 −1 modified@@ -5,7 +5,7 @@ $this->assign('title', $node->title); $this->Nodes->set($node); ?> <div id="node-<?= $this->Nodes->field('id') ?>" class="node node-type-<?= $this->Nodes->field('type') ?>"> - <h2><?= $this->Nodes->field('title') ?></h2> + <h2><?= h($this->Nodes->field('title')) ?></h2> <?php echo $this->Nodes->info(); echo $this->Nodes->body();
Settings/src/Template/Admin/Settings/form.ctp+1 −1 modified@@ -9,7 +9,7 @@ $this->Breadcrumbs ]); if ($this->request->param('action') == 'edit') { - $this->Breadcrumbs->add($setting->key, $this->request->getRequestTarget()); + $this->Breadcrumbs->add(h($setting->key), $this->request->getRequestTarget()); } if ($this->request->param('action') == 'add') {
Settings/src/Template/Admin/Settings/index.ctp+4 −4 modified@@ -9,9 +9,9 @@ $this->Breadcrumbs 'controller' => 'Settings', 'action' => 'index', )); -if (!empty($this->request->params['named']['p'])) { - $this->Breadcrumbs->add($this->request->params['named']['p']); -} +if ($this->request->getQuery('key')): + $this->Breadcrumbs->add(h($this->request->getQuery('key'))); +endif; $this->start('table-heading'); $tableHeaders = $this->Html->tableHeaders(array( $this->Paginator->sort('id', __d('croogo', 'Id')), @@ -57,7 +57,7 @@ $this->append('table-body'); $rows[] = array( $setting->id, $this->Html->link($keyPrefix, array('controller' => 'Settings', 'action' => 'index', '?' => array('key' => $keyPrefix))) . $keyTitle, - $this->Text->truncate($setting->value, 20), + $this->Text->truncate(h($setting->value), 20), $this->Html->status($setting->editable), $actions, );
Taxonomy/src/Template/Admin/Terms/index.ctp+1 −1 modified@@ -8,7 +8,7 @@ $this->Breadcrumbs->add(__d('croogo', 'Content'), ['plugin' => 'Croogo/Nodes', 'controller' => 'Nodes', 'action' => 'index']) ->add(__d('croogo', 'Vocabularies'), ['plugin' => 'Croogo/Taxonomy', 'controller' => 'Vocabularies', 'action' => 'index']) - ->add($vocabulary->title, $this->request->getRequestTarget()); + ->add(h($vocabulary->title), $this->request->getRequestTarget()); $this->append('action-buttons'); echo $this->Croogo->adminAction(__d('croogo', 'Create term'), [
Taxonomy/src/Template/Admin/Types/form.ctp+1 −1 modified@@ -9,7 +9,7 @@ $this->Breadcrumbs if ($this->request->params['action'] == 'edit') { $this->assign('title', __d('croogo', 'Edit Type')); - $this->Breadcrumbs->add($type->title, $this->request->getRequestTarget()); + $this->Breadcrumbs->add(h($type->title), $this->request->getRequestTarget()); } if ($this->request->params['action'] == 'add') {
Users/src/Template/Admin/Roles/form.ctp+1 −1 modified@@ -5,7 +5,7 @@ $this->Breadcrumbs ->add(__d('croogo', 'Roles'), ['plugin' => 'Croogo/Users', 'controller' => 'Roles', 'action' => 'index']); if ($this->request->param('action') == 'edit') { - $this->Breadcrumbs->add($role->title, $this->request->getRequestTarget()); + $this->Breadcrumbs->add(h($role->title), $this->request->getRequestTarget()); } if ($this->request->param('action') == 'add') {
Users/src/Template/Admin/Users/form.ctp+1 −1 modified@@ -9,7 +9,7 @@ $this->Breadcrumbs->add(__d('croogo', 'Users'), ['plugin' => 'Croogo/Users', 'controller' => 'Users', 'action' => 'index']); if ($this->request->param('action') == 'edit') { - $this->Breadcrumbs->add($user->name, $this->request->getRequestTarget()); + $this->Breadcrumbs->add(h($user->name), $this->request->getRequestTarget()); $this->assign('title', __d('croogo', 'Edit user %s', $user->username)); } else { $this->assign('title', __d('croogo', 'New user'));
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-wr5c-4f2h-28m6ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2019-7169ghsaADVISORY
- github.com/croogo/croogo/commit/cafaaabe2cef3d1d83652370e30563e6ad7c4158ghsaWEB
- github.com/croogo/croogo/issues/888ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.