CVE-2019-7173
Description
Stored self-XSS in Croogo CMS through v3.0.5 allows arbitrary HTML/JS injection in the Title field of attachments.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Stored self-XSS in Croogo CMS through v3.0.5 allows arbitrary HTML/JS injection in the Title field of attachments.
Vulnerability
A stored self-XSS vulnerability exists in Croogo CMS versions through v3.0.5 [1]. The vulnerability is located in the Title field when editing an attachment at /admin/file-manager/attachments/edit/4. User input is not properly sanitized before being stored and later rendered, allowing an attacker to inject arbitrary HTML or JavaScript code.
Exploitation
An attacker must have authenticated access to the Croogo admin panel [2]. To exploit, the attacker edits an attachment and sets the Title field to a malicious payload. The payload is stored and executed when the same or another admin views the attachment edit page. The attacker needs privileges to edit attachments.
Impact
Successful exploitation allows the attacker to execute arbitrary JavaScript in the context of the admin session, potentially leading to session hijacking, defacement, or other client-side attacks. The attack is self-XSS because it requires the attacker to be authenticated, but can affect other admins if they view the compromised title.
Mitigation
The fix was applied in commit cafaaab on Croogo's GitHub repository [4]. The fix uses CakePHP's h() function to escape output. Administrators should update to a version that includes this commit or apply the patch manually. No official patched release is mentioned; as of the publication date, the issue exists in versions through v3.0.5. Workaround is to avoid trusting input and manually escape output.
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-q5fg-v5p7-r424ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2019-7173ghsaADVISORY
- github.com/croogo/croogo/commit/cafaaabe2cef3d1d83652370e30563e6ad7c4158ghsaWEB
- github.com/croogo/croogo/issues/889ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.