CVE-2018-20756
Description
MODX Revolution through v2.7.0-pl allows XSS via a document resource (such as pagetitle), which is mishandled during an Update action, a Quick Edit action, or the viewing of manager logs.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
MODX Revolution through v2.7.0-pl contains a stored XSS vulnerability where document resource fields like pagetitle are not properly sanitized, allowing malicious scripts to execute in the manager interface.
Vulnerability
CVE-2018-20756 is a stored cross-site scripting (XSS) vulnerability in MODX Revolution up to and including version v2.7.0-pl [1]. It affects document resource fields such as pagetitle during Update and Quick Edit actions, as well as when these fields are rendered in manager logs [1][4]. The vulnerability exists because user-supplied input is not properly sanitized before being stored and later displayed in the MODX manager interface [4].
Exploitation
An attacker with at least a manager-level user account (sufficient privileges to create or edit document resources) can inject malicious JavaScript or HTML into a resource field like pagetitle [4]. The payload is stored in the database and will execute when a manager user views the resource in an Update form, uses Quick Edit, or when the manager logs display the resource [1][4]. No additional user interaction beyond viewing the affected page is required for the payload to execute.
Impact
Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of a victim manager user's session. This could lead to sensitive information disclosure (e.g., session tokens, manager actions), page content manipulation, or further compromise of the MODX instance [4]. The attack is limited to the manager interface and does not directly affect public-facing site visitors.
Mitigation
MODX Revolution fixed this issue in commit 71f894ee55dc4eed10538979761d6c94e8cd1078, which was included in a subsequent release after v2.7.0-pl [2][4]. Users should upgrade to a patched version (v2.7.1 or later) [2]. There is no evidence that this CVE is listed in CISA's Known Exploited Vulnerabilities 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 |
|---|---|---|
modx/revolutionPackagist | < 2.7.1-pl | 2.7.1-pl |
Affected products
2- Range: v2.0.1-pl, v2.0.3-pl, v2.0.4-pl, …
Patches
171f894ee55dcFixes bunch of various XSS issues in the manager #14335
9 files changed · +33 −31
core/docs/changelog.txt+1 −0 modified@@ -4,6 +4,7 @@ development release, and is only shown to give an idea of what's currently in th MODX Revolution 2.7.1-pl (TBD) ==================================== +- Fixes bunch of various XSS issues in the manager [#14335] - Fix issue with resource list preventing parents from working correctly [#14329] - Fixed issues with tab width and very long strings in the vertical tabs [#14317] - Refactored tag input renderer to fix rendering with empty options list [#14319]
core/model/modx/moduser.class.php+2 −2 modified@@ -904,10 +904,10 @@ public function getProfilePhoto($width = 128, $height = 128) { $source = modMediaSource::getDefaultSource($this->xpdo, $this->xpdo->getOption('photo_profile_source')); $source->initialize(); - $path = $source->getBasePath($this->Profile->photo) . $this->Profile->photo; + $path = $source->prepareSrcForThumb($this->Profile->photo); return $this->xpdo->getOption('connectors_url', null, MODX_CONNECTORS_URL) - . "system/phpthumb.php?zc=1&h={$height}&w={$width}&src={$path}"; + . "system/phpthumb.php?" . http_build_query(array("zc" => 1, "h" => $height, "w" => $width, "src" => $path)); } /**
manager/assets/modext/modx.jsgrps-min.js+1 −1 modifiedmanager/assets/modext/util/utilities.js+22 −22 modified@@ -1,7 +1,7 @@ Ext.namespace('MODx.util.Progress'); /** * A JSON Reader specific to MODExt - * + * * @class MODx.util.JSONReader * @extends Ext.util.JSONReader * @param {Object} config An object of configuration properties @@ -20,7 +20,7 @@ Ext.extend(MODx.util.JSONReader,Ext.data.JsonReader); Ext.reg('modx-json-reader',MODx.util.JSONReader); /** - * @class MODx.util.Progress + * @class MODx.util.Progress */ MODx.util.Progress = { id: 0 @@ -66,7 +66,7 @@ Ext.override(Ext.form.BasicForm,{ nodeToRecurse = nodeToRecurse || this; nodeToRecurse.items.each(function(f){ if (!f.getValue) return; - + if(f.items){ this.clearDirty(f); } else if(f.originalValue != f.getValue()){ @@ -77,7 +77,7 @@ Ext.override(Ext.form.BasicForm,{ }); -/** +/** * Static Textfield */ MODx.StaticTextField = Ext.extend(Ext.form.TextField, { @@ -91,7 +91,7 @@ MODx.StaticTextField = Ext.extend(Ext.form.TextField, { }); Ext.reg('statictextfield',MODx.StaticTextField); -/** +/** * Static Boolean */ MODx.StaticBoolean = Ext.extend(Ext.form.TextField, { @@ -103,7 +103,7 @@ MODx.StaticBoolean = Ext.extend(Ext.form.TextField, { MODx.StaticBoolean.superclass.onRender.apply(this, arguments); this.on('change',this.onChange,this); } - + ,setValue: function(v) { if (v === 1) { this.addClass('green'); @@ -147,13 +147,13 @@ Ext.form.setCheckboxValues = function(form,id,mask) { while ((f = form.findField(id+n)) !== null) { f.setValue((mask & (1<<n))?'true':'false'); n=n+1; - } + } }; Ext.form.getCheckboxMask = function(cbgroup) { var mask=''; if (typeof(cbgroup) !== 'undefined') { - if ((typeof(cbgroup)==='string')) { + if ((typeof(cbgroup)==='string')) { mask = cbgroup+''; } else { for(var i=0,len=cbgroup.length;i<len;i=i+1) { @@ -218,7 +218,7 @@ Ext.form.HourField = function(id,name,v){ ,editable: false ,value: v || 1 ,transform: id - }); + }); }; @@ -229,7 +229,7 @@ Ext.override(Ext.tree.TreeNodeUI,{ return className && (' '+el.dom.className+' ').indexOf(' '+className+' ') !== -1; } ,renderElements : function(n, a, targetNode, bulkRender){ - + this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : ''; var cb = Ext.isBoolean(a.checked), @@ -247,7 +247,7 @@ Ext.override(Ext.tree.TreeNodeUI,{ iconMarkup, cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : '/>')) : '', '<a hidefocus="on" class="x-tree-node-anchor" href="',href,'" tabIndex="1" ', - a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '><span unselectable="on">',n.text,"</span></a></div>", + a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '><span unselectable="on">',Ext.util.Format.htmlEncode(n.text),"</span></a></div>", '<ul class="x-tree-node-ct" style="display:none;"></ul>', "</li>"].join(''); @@ -266,7 +266,7 @@ Ext.override(Ext.tree.TreeNodeUI,{ var index = 3; if(cb){ this.checkbox = cs[3]; - + this.checkbox.defaultChecked = this.checkbox.checked; index++; } @@ -295,8 +295,8 @@ Ext.override(Ext.tree.TreeNodeUI,{ /* allows for messages in JSON responses */ -Ext.override(Ext.form.Action.Submit,{ - handleResponse : function(response){ +Ext.override(Ext.form.Action.Submit,{ + handleResponse : function(response){ var m = Ext.decode(response.responseText); /* shaun 7/11/07 */ if (this.form.errorReader) { var rs = this.form.errorReader.read(response); @@ -320,7 +320,7 @@ Ext.override(Ext.form.Action.Submit,{ }); /* QTips to form fields */ -Ext.form.Field.prototype.afterRender = Ext.form.Field.prototype.afterRender.createSequence(function() { +Ext.form.Field.prototype.afterRender = Ext.form.Field.prototype.afterRender.createSequence(function() { if (this.description) { Ext.QuickTips.register({ target: this.getEl() @@ -350,7 +350,7 @@ Ext.applyIf(Ext.form.Field,{ } wrapDiv = field.getEl().up('div.x-form-item'); if(wrapDiv) { - label = wrapDiv.child('label'); + label = wrapDiv.child('label'); } if(label){ return label; @@ -365,7 +365,7 @@ MODx.util.Clipboard = function() { text = encodeURIComponent(text); return text.replace(/%0A/g, "%0D%0A"); } - + ,copy: function(text){ if (Ext.isIE) { window.clipboardData.setData("Text", text); @@ -375,10 +375,10 @@ MODx.util.Clipboard = function() { var divholder = document.createElement('div'); divholder.id = flashcopier; document.body.appendChild(divholder); - } - document.getElementById(flashcopier).innerHTML = ''; + } + document.getElementById(flashcopier).innerHTML = ''; var divinfo = '<embed src="' + MODx.config.manager_url - + 'assets/modext/_clipboard.swf" FlashVars="clipboard=' + + 'assets/modext/_clipboard.swf" FlashVars="clipboard=' + MODx.util.Clipboard.escape(text) + '" width="0" height="0" type="application/x-shockwave-flash"></embed>'; document.getElementById(flashcopier).innerHTML = divinfo; @@ -408,7 +408,7 @@ Ext.ns('Ext.ux.grid');if('function'!==typeof RegExp.escape){RegExp.escape=functi * Ext JS Library 0.30 * Copyright(c) 2006-2009, Ext JS, LLC. * licensing@extjs.com - * + * * http://extjs.com/license */ Ext.SwitchButton = Ext.extend(Ext.Component, { @@ -489,7 +489,7 @@ Ext.SwitchButton = Ext.extend(Ext.Component, { } return item; }, - + onClick : function(e){ var target = e.getTarget('td', 2); if(!this.disabled && target){
manager/assets/modext/widgets/core/modx.grid.settings.js+2 −2 modified@@ -2,7 +2,7 @@ MODx.grid.SettingsGrid = function(config) { config = config || {}; this.exp = new Ext.grid.RowExpander({ tpl : new Ext.Template( - '<p class="desc">{description_trans}</p>' + '<p class="desc">{description_trans:htmlEncode}</p>' ) }); @@ -646,4 +646,4 @@ MODx.window.UpdateSetting = function(config) { MODx.window.UpdateSetting.superclass.constructor.call(this,config); }; Ext.extend(MODx.window.UpdateSetting,MODx.Window); -Ext.reg('modx-window-setting-update',MODx.window.UpdateSetting); \ No newline at end of file +Ext.reg('modx-window-setting-update',MODx.window.UpdateSetting);
manager/assets/modext/widgets/resource/modx.tree.resource.js+1 −1 modified@@ -493,7 +493,7 @@ Ext.extend(MODx.tree.Resource,MODx.tree.Tree,{ ,'hide':{fn:function() {this.destroy();}} } }); - w.title += ': <span dir="ltr">' + w.record.pagetitle + ' ('+ w.record.id + ')</span>'; + w.title += ': <span dir="ltr">' + Ext.util.Format.htmlEncode(w.record.pagetitle) + ' ('+ w.record.id + ')</span>'; w.setValues(r.object); w.show(e.target,function() { Ext.isSafari ? w.setPosition(null,30) : w.center();
manager/assets/modext/widgets/system/modx.grid.manager.log.js+1 −0 modified@@ -39,6 +39,7 @@ MODx.grid.ManagerLog = function(config) { header: _('object') ,dataIndex: 'name' ,width: 300 + ,renderer: Ext.util.Format.htmlEncode }] ,tbar: [{ xtype: 'button'
manager/controllers/default/security/user/update.class.php+2 −2 modified@@ -133,7 +133,7 @@ private function _parseCustomData(array $remoteData = array(),$path = '') { ); if (is_array($value)) { $field['iconCls'] = 'icon-folder'; - $field['text'] = $key; + $field['text'] = htmlentities($key,ENT_QUOTES,$encoding); $field['leaf'] = false; $field['children'] = $this->_parseCustomData($value,$key); } else { @@ -147,7 +147,7 @@ private function _parseCustomData(array $remoteData = array(),$path = '') { $v = substr($v,0,30).'...'; } $field['iconCls'] = 'icon-terminal'; - $field['text'] = $key.' - <i>'.htmlentities($v,ENT_QUOTES,$encoding).'</i>'; + $field['text'] = htmlentities($key,ENT_QUOTES,$encoding).' - <i>'.htmlentities($v,ENT_QUOTES,$encoding).'</i>'; $field['leaf'] = true; $field['value'] = $value; }
manager/templates/default/header.tpl+1 −1 modified@@ -1,7 +1,7 @@ <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" dir="{$_config.manager_direction}" lang="{$_config.manager_lang_attribute}" xml:lang="{$_config.manager_lang_attribute}"> <head> -<title>{if $_pagetitle}{$_pagetitle} | {/if}{$_config.site_name|strip_tags|escape}</title> +<title>{if $_pagetitle}{$_pagetitle|escape} | {/if}{$_config.site_name|strip_tags|escape}</title> <meta http-equiv="Content-Type" content="text/html; charset={$_config.modx_charset}" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-fpxg-5x79-43rmghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2018-20756ghsaADVISORY
- github.com/modxcms/revolution/commit/71f894ee55dc4eed10538979761d6c94e8cd1078ghsaWEB
- github.com/modxcms/revolution/issues/14105ghsax_refsource_MISCWEB
- github.com/modxcms/revolution/pull/14335ghsaWEB
News mentions
0No linked articles in our index yet.