CVE-2019-7170
Description
Croogo v3.0.5 and earlier contains a stored self-XSS vulnerability in the Title field of the vocabulary admin page.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Croogo v3.0.5 and earlier contains a stored self-XSS vulnerability in the Title field of the vocabulary admin page.
Vulnerability
A stored self-XSS vulnerability exists in Croogo through version 3.0.5. The bug resides in the Title field when creating or editing vocabularies at /admin/taxonomy/vocabularies. The application fails to sanitize the Title input before storing and later rendering it, allowing an attacker to inject arbitrary HTML or JavaScript. Affected versions include all releases up to and including v3.0.5 [1][2].
Exploitation
An attacker must have an account with permissions to create or edit vocabularies (typically admin-level). The attacker crafts a malicious payload in the Title field. When the vocabulary page is viewed by any user (including the attacker or other administrators), the payload executes in the victim's browser. The XSS is self-stored, meaning the attacker must be authenticated to submit the malicious title, but it can affect other users who subsequently view the vocabulary list [2].
Impact
Successful exploitation allows the attacker to execute arbitrary JavaScript in the context of the victim's session. This can lead to session hijacking, defacement, or theft of sensitive data. The impact is limited to users with access to the vocabulary management interface, but because the payload is stored, it can persist and affect multiple users over time [1][2].
Mitigation
The fix was committed in commit cafaaabe2cef3d1d83652370e30563e6ad7c4158, which applies h() (HTML escaping) to the title and other fields in the messages view [3]. Users should upgrade to a version that includes this fix. As of the CVE publication date (2019-01-29), no official patched release was announced; the fix exists in the commit but may not be part of a tagged release. Administrators should apply the patch manually or update to the latest available version. No workaround is documented [2][3].
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-36pq-cjh9-fv46ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2019-7170ghsaADVISORY
- github.com/croogo/croogo/commit/cafaaabe2cef3d1d83652370e30563e6ad7c4158ghsaWEB
- github.com/croogo/croogo/issues/890ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.