Concrete CMS version 9 below 9.3.3 and below 8.5.18 are vulnerable to Stored XSS in RSS Displayer
Description
Concrete CMS versions 9.0.0 to 9.3.2 and below 8.5.18 are vulnerable to Stored XSS in RSS Displayer when user input is stored and later embedded into responses. A rogue administrator could inject malicious code into fields due to insufficient input validation. The Concrete CMS security team gave this vulnerability a CVSS v4 score of 5.1 with vector https://www.first.org/cvss/calculator/4.0#CVSS:4.0/AV:N/AC:H/AT:N/PR:H/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N Thanks, m3dium for reporting. (CNA updated this risk rank on 17 Jan 2025 by lowering the AC based on CVSS 4.0 documentation that access privileges should not be considered for AC)
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Concrete CMS versions 9.0.0–9.3.2 and ≤8.5.17 contain a stored XSS in the RSS Displayer block, exploitable by an administrator with elevated privileges.
Vulnerability: Stored XSS in RSS Displayer
CVE-2024-4350 is a stored cross-site scripting (XSS) vulnerability in Concrete CMS that affects versions 9.0.0 through 9.3.2 and all versions prior to 8.5.18. The flaw resides in the RSS Displayer block, where user-supplied input is stored without sufficient validation and later embedded into HTTP responses. This allows a rogue administrator—someone who already holds administrative credentials—to inject arbitrary JavaScript or HTML into the block's fields [1][2].
Attack
Vector and Prerequisites
To exploit this vulnerability, an attacker must have administrator-level access to the Concrete CMS instance. The attack surface is the RSS Displayer block's configuration interface, where the administrator can store malicious payloads in fields that are later rendered to other users. No additional authentication bypass is required because the attacker already possesses admin privileges. The CVSS v4 score assigned by the CNA is 5.1 (medium severity), with an attack vector of network (AV:N) and low attack complexity (AC:L) after a revision in January 2025 [1].
Impact
A successful exploit allows the rogue administrator to inject malicious scripts that execute in the browsers of other users who view pages containing the affected RSS Displayer block. The impact is limited to confidentiality (data theft, session hijacking) within the web application context; the CVSS vector indicates low impact to confidentiality (VC:L) and no impact to integrity or availability [1].
Mitigation
Concrete CMS has released fixed versions: 9.3.3 (for the 9.x branch) and 8.5.18 (for the 8.5.x branch). The fix was implemented via commit 12166 for version 9 and commit c08d9671cec4e7afdabb547339c4bc0bed8eab06 for version 8 [2][3][4]. Administrators are strongly advised to upgrade to these patched versions immediately. No workarounds are documented, and the vulnerability is not currently listed in CISA’s Known Exploited Vulnerabilities catalog.
AI Insight generated on May 20, 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 |
|---|---|---|
concrete5/concrete5Packagist | < 8.5.18 | 8.5.18 |
concrete5/concrete5Packagist | >= 9.0.0RC1, < 9.3.3 | 9.3.3 |
Affected products
2- Concrete CMS/Concrete CMSv5Range: 9.0.0
Patches
255e485e06b0bMerge pull request #12166 from aembler/misc-fixes-080124
24 files changed · +114 −35
build/package.json+1 −1 modified@@ -13,7 +13,7 @@ "production": "mix --production" }, "devDependencies": { - "@concretecms/bedrock": "1.5.0", + "@concretecms/bedrock": "^1.5.1", "cross-env": "^5.1.1", "download": "~8.0.0", "grunt": "^1.5.3",
build/package-lock.json+4 −4 modified@@ -12,7 +12,7 @@ "tui-image-editor": "^3.10.0" }, "devDependencies": { - "@concretecms/bedrock": "1.5.0", + "@concretecms/bedrock": "^1.5.1", "cross-env": "^5.1.1", "download": "~8.0.0", "grunt": "^1.5.3", @@ -1751,9 +1751,9 @@ } }, "node_modules/@concretecms/bedrock": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@concretecms/bedrock/-/bedrock-1.5.0.tgz", - "integrity": "sha512-7p1vTRX+mc+4feJwPejETqGG+dnMSpSbTqgHXyd/q9Cbd3l+liO9GXpzZK7K8sgqshgFWNUaShlQschs686iUQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@concretecms/bedrock/-/bedrock-1.5.1.tgz", + "integrity": "sha512-oXzwA8U1Eus2TNc1ak8gVficKEfSMnO0pRFAjfzZQKwGp6u3cCzDw/fonOa5uRyOSaY9QL8NF0h3zLpbgYeLkg==", "dev": true, "dependencies": { "@fortawesome/fontawesome-free": "^5.15.1",
composer.lock+11 −8 modified@@ -11389,20 +11389,19 @@ }, { "name": "zircote/swagger-php", - "version": "4.5.2", + "version": "4.9.2", "source": { "type": "git", "url": "https://github.com/zircote/swagger-php.git", - "reference": "8b55d616213cd0b05de84e0fabc34de74a4c6d1d" + "reference": "256d42cb07ba1c2206d66bc7516ee3d3e3e9f0b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zircote/swagger-php/zipball/8b55d616213cd0b05de84e0fabc34de74a4c6d1d", - "reference": "8b55d616213cd0b05de84e0fabc34de74a4c6d1d", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/256d42cb07ba1c2206d66bc7516ee3d3e3e9f0b2", + "reference": "256d42cb07ba1c2206d66bc7516ee3d3e3e9f0b2", "shasum": "" }, "require": { - "doctrine/annotations": "^1.7", "ext-json": "*", "php": ">=7.2", "psr/log": "^1.1 || ^2.0 || ^3.0", @@ -11412,11 +11411,15 @@ }, "require-dev": { "composer/package-versions-deprecated": "^1.11", - "friendsofphp/php-cs-fixer": "^2.17 || ^3.0", + "doctrine/annotations": "^1.7 || ^2.0", + "friendsofphp/php-cs-fixer": "^2.17 || ^3.47.1", "phpstan/phpstan": "^1.6", "phpunit/phpunit": ">=8", "vimeo/psalm": "^4.23" }, + "suggest": { + "doctrine/annotations": "^1.7 || ^2.0" + }, "bin": [ "bin/openapi" ], @@ -11461,9 +11464,9 @@ ], "support": { "issues": "https://github.com/zircote/swagger-php/issues", - "source": "https://github.com/zircote/swagger-php/tree/4.5.2" + "source": "https://github.com/zircote/swagger-php/tree/4.9.2" }, - "time": "2022-12-19T00:41:18+00:00" + "time": "2024-05-02T21:36:00+00:00" } ], "packages-dev": [
concrete/bedrock/assets/@concretecms/bedrock/assets/cms/scss/_hud.scss+5 −0 modified@@ -131,6 +131,11 @@ div#ccm-popup-alert-message { right: 30px; width: 380px; z-index: $index-level-page-alert; + @media only screen and (max-width: 768px) { + left: 0; + right: 0; + width: 100vw; + } } .ccm-notifications-box-header {
concrete/bedrock/assets/@concretecms/bedrock/assets/cms/scss/jquery-ui/_overrides.scss+7 −2 modified@@ -9,9 +9,15 @@ html.ccm-toolbar-visible { .ui-dialog { box-shadow: $modal-content-box-shadow-sm-up; + max-width: 100vw; padding: 0; - z-index: $index-level-dialog; + @media only screen and (max-width: 768px) { + display: flex; + flex-direction: column; + max-height: 100vh; + } + /* hide section titles for panels when those panels are shown in dialogs */ section { header { @@ -144,6 +150,5 @@ html.ccm-toolbar-visible { button { margin: $modal-footer-margin-between / 2; } - } }
concrete/bedrock/assets/@concretecms/bedrock/assets/cms/scss/panels/pages/_attributes.scss+11 −0 modified@@ -99,6 +99,10 @@ display: block; float: left; width: 100%; + @media only screen and (max-width: 768px) { + display: flex; + flex-direction: column-reverse; + } } #ccm-dialog-attributes-menu { @@ -107,6 +111,9 @@ margin: 0; padding: 0; width: 30%; + @media only screen and (max-width: 768px) { + width: auto; + } } #ccm-dialog-attributes-detail { @@ -115,6 +122,10 @@ margin: 0 0 0 65px; padding: 0; width: calc(70% - 65px); + @media only screen and (max-width: 768px) { + margin: 0; + width: auto; + } } /**
concrete/bedrock/assets/@concretecms/bedrock/assets/cms/scss/_toolbar.scss+19 −0 modified@@ -7,6 +7,9 @@ div#ccm-toolbar { position: fixed; top: 0; width: 100%; + @media only screen and (max-width: 768px) { + width: 100vw; + } z-index: $index-level-main-bar; /* over the top of the highlighter, which is 1000 */ .ccm-toolbar-accessibility-title { @@ -373,6 +376,22 @@ ul.ccm-mobile-menu { } } +.ccm-toolbar-mobile-add-pages-button { + border-left: 1px solid $gray-200; + cursor: pointer; + height: 47px; + padding: 14px 18px; + + svg { + fill: $gray-600; + height: 16px; + margin: 0 auto; + transition: fill 0.25s ease-in-out; + vertical-align: baseline; + width: 16px; + } +} + .ccm-mobile-toolbar-menu { display: none;
concrete/blocks/rss_displayer/controller.php+1 −1 modified@@ -201,7 +201,7 @@ public function view() ++$i; } } catch (\Exception $e) { - $this->set('errorMsg', $e->getMessage()); + $this->set('errorMsg', t('Unable to load RSS posts.')); } if (empty($this->titleFormat)) {
concrete/blocks/rss_displayer/view.php+1 −1 modified@@ -7,7 +7,7 @@ <?php if (strlen($title) > 0) { ?> <div class="ccm-block-rss-displayer-header"> - <<?php echo $titleFormat; ?>><?=$title?></<?php echo $titleFormat; ?>> + <<?php echo $titleFormat; ?>><?=h($title)?></<?php echo $titleFormat; ?>> </div> <?php } ?>
concrete/blocks/share_this_page/view.php+1 −1 modified@@ -4,7 +4,7 @@ <ul class="list-inline"> <?php foreach ($selected as $service) { ?> <li> - <a href="<?php echo h($service->getServiceLink()) ?>" target="_blank" rel="noopener noreferrer" aria-label="<?php echo h($service->getDisplayName()) ?>"><?php echo $service->getServiceIconHTML()?></a> + <a href="<?php echo h($service->getServiceLink()) ?>" target="<?=$service->getServiceLinkTarget()?>" rel="noopener noreferrer" aria-label="<?php echo h($service->getDisplayName()) ?>"><?php echo $service->getServiceIconHTML()?></a> </li> <?php } ?> </ul>
concrete/composer.json+1 −1 modified@@ -120,7 +120,7 @@ "laminas/laminas-cache-storage-adapter-memory": "^2.0", "tubalmartin/cssmin": "^4.1", "ssddanbrown/htmldiff": "^1.0", - "zircote/swagger-php": "^4.4", + "zircote/swagger-php": "4.9.2", "concretecms/dependency-patches": "^1.7.2" }, "replace": {
concrete/config/concrete.php+3 −3 modified@@ -6,9 +6,9 @@ * * @var string */ - 'version' => '9.3.2', - 'version_installed' => '9.3.2', - 'version_db' => '20240618202000', // the key of the latest database migration + 'version' => '9.3.3', + 'version_installed' => '9.3.3', + 'version_db' => '20240711000000', // the key of the latest database migration /* * Installation status
concrete/css/cms.css+1 −1 modifiedconcrete/elements/attribute/key/list.php+1 −1 modified@@ -3,7 +3,7 @@ foreach ($sortable_sets as $set) { ?> - <h4><?=$set->getAttributeSetName()?></h4> + <h4><?=$set->getAttributeSetDisplayName()?></h4> <ul class="item-select-list ccm-attribute-list-wrapper" data-sortable-attribute-set="<?=$set->getAttributeSetID()?>"> <?php foreach ($set->getAttributeKeys() as $key) {
concrete/js/cms.js+1 −1 modifiedconcrete/single_pages/dashboard/system/attributes/sets.php+1 −1 modified@@ -44,7 +44,7 @@ <div class="form-group"> <?php echo $form->label('asName', t('Name'))?> - <?php echo $form->text('asName', $set->getAttributeSetName())?> + <?php echo $form->text('asName', $set->getAttributeSetDisplayName())?> </div> <div class="form-group">
concrete/src/Entity/Board/Designer/CustomElement.php+1 −1 modified@@ -33,7 +33,7 @@ abstract public function createBlock() : Block; /** * @ORM\ManyToOne(targetEntity="\Concrete\Core\Entity\User\User") - * @ORM\JoinColumn(name="uID", referencedColumnName="uID") + * @ORM\JoinColumn(name="uID", referencedColumnName="uID", onDelete="SET NULL") */ protected $author;
concrete/src/Entity/Board/InstanceSlotRule.php+1 −1 modified@@ -68,7 +68,7 @@ class InstanceSlotRule implements \JsonSerializable, ObjectInterface /** * @ORM\ManyToOne(targetEntity="\Concrete\Core\Entity\User\User") - * @ORM\JoinColumn(name="uID", referencedColumnName="uID") + * @ORM\JoinColumn(name="uID", referencedColumnName="uID", onDelete="SET NULL") */ protected $user;
concrete/src/Sharing/ShareThisPage/Service.php+12 −3 modified@@ -18,15 +18,24 @@ public static function getByHandle($ssHandle) } } + public function getServiceLinkTarget(): string + { + // @TODO - perhaps make this more modular and defined within each service's config. + if (in_array($this->getHandle(), ['email', 'print'])) { + return ''; + } else { + return '_blank'; + } + } + public function getServiceLink(Page $c = null) { if (!is_object($c)) { $req = Request::getInstance(); $c = $req->getCurrentPage(); - if($c){ + if($c) { $url = urlencode(URL::to($c)); - } - else{ + } else { $url = urlencode($req->getUri()); } } elseif (!$c->isError()) {
concrete/src/Updater/Migrations/Migrations/Version20240711000000.php+27 −0 added@@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +namespace Concrete\Core\Updater\Migrations\Migrations; + +use Concrete\Core\Entity\Board\Designer\CustomElement; +use Concrete\Core\Entity\Board\Designer\ItemSelectorCustomElement; +use Concrete\Core\Entity\Board\InstanceSlotRule; +use Concrete\Core\Entity\User\User; +use Concrete\Core\Updater\Migrations\AbstractMigration; +use Concrete\Core\Updater\Migrations\RepeatableMigrationInterface; + +final class Version20240711000000 extends AbstractMigration implements RepeatableMigrationInterface +{ + + public function upgradeDatabase() + { + $this->refreshEntities([ + InstanceSlotRule::class, + CustomElement::class, + ItemSelectorCustomElement::class, + User::class + ]); + } + +}
concrete/themes/atomik/blocks/share_this_page/view.php+1 −1 modified@@ -4,7 +4,7 @@ <h4><?=t('Share This Article')?></h4> <?php foreach ($selected as $service) { ?> - <a href="<?php echo h($service->getServiceLink()) ?>" target="_blank" rel="noopener noreferrer" aria-label="<?php echo h($service->getDisplayName()) ?>"><?php echo $service->getServiceIconHTML()?></a> + <a href="<?php echo h($service->getServiceLink()) ?>" target="<?=$service->getServiceLinkTarget()?>" rel="noopener noreferrer" aria-label="<?php echo h($service->getDisplayName()) ?>"><?php echo $service->getServiceIconHTML()?></a> <?php } ?> </div>
concrete/themes/concrete/main.css+1 −1 modifiedconcrete/themes/dashboard/main.css+1 −1 modifiedconcrete/themes/dashboard/main.js+1 −1 modified
c08d9671cec4Cherry-pick two commits from 9
3 files changed · +4 −4
concrete/blocks/rss_displayer/controller.php+1 −1 modified@@ -157,7 +157,7 @@ public function view() ++$i; } } catch (\Exception $e) { - $this->set('errorMsg', $e->getMessage()); + $this->set('errorMsg', t('Unable to load RSS posts.')); } $this->set('posts', $posts);
concrete/blocks/rss_displayer/view.php+1 −1 modified@@ -7,7 +7,7 @@ <?php if (strlen($title) > 0) { ?> <div class="ccm-block-rss-displayer-header"> - <h5><?=$title?></h5> + <h5><?=h($title)?></h5> </div> <?php } ?>
concrete/config/concrete.php+2 −2 modified@@ -6,8 +6,8 @@ * * @var string */ - 'version' => '8.5.17', - 'version_installed' => '8.5.17', + 'version' => '8.5.18', + 'version_installed' => '8.5.18', 'version_db' => '20220319043123', // the key of the latest database migration /*
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-q5wx-m95r-4cgcghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-4350ghsaADVISORY
- documentation.concretecms.org/9-x/developers/introduction/version-history/933-release-notesghsaWEB
- documentation.concretecms.org/developers/introduction/version-history/8518-release-notesghsaWEB
- github.com/concretecms/concretecms/commit/55e485e06b0b3342613a55af6a7c61d939d2ccb5ghsaWEB
- github.com/concretecms/concretecms/commit/c08d9671cec4e7afdabb547339c4bc0bed8eab06ghsaWEB
- github.com/concretecms/concretecms/pull/12166ghsaWEB
News mentions
0No linked articles in our index yet.