CVE-2023-33194 (JavaScript, published 2023-05-26T21:15Z)
Description: value: Craft is a CMS for creating custom digital experiences on the web.The platform does not filter input and encode output in Quick Post validation error message, which can deliver an XSS payload. Old CVE fixed the XSS in label HTML but didn’t fix it when clicking save. This issue was patched in version 4.4.6.
Severity: nan (CVSS v3 base score: 4.8)
Weakness: CWE-79 \u2014 Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Repository: https://github.com/craftcms/cms
Files changed:
CHANGELOG.md
src/web/assets/quickpost/dist/QuickPostWidget.js
src/web/assets/quickpost/dist/QuickPostWidget.js.map
src/web/assets/quickpost/src/QuickPostWidget.js
Commit message: Fixed an XSS vulnerability


Vulnerable code:
!function(){var t;t=jQuery,Craft.QuickPostWidget=Garnish.Base.extend({params:null,initFields:null,formHtml:null,$widget:null,$form:null,$spinner:null,$errorList:null,loading:!1,init:function(i,r,e,n){this.params=r,this.initFields=e,this.formHtml=n,this.$widget=t("#widget"+i),this.initForm(this.$widget.find("form:first"))},initForm:function(t){this.$form=t,this.$spinner=this.$form.find(".spinner"),this.initFields();var i=this.$form.find("> .buttons > .btngroup > .menubtn"),r=i.data("menubtn").menu.$container.find("> ul > li > a");i.menubtn(),this.addListener(this.$form,"submit","handleFormSubmit"),this.addListener(r,"click","saveAndContinueEditing")},handleFormSubmit:function(t){t.preventDefault(),this.save(this.onSave.bind(this))},saveAndContinueEditing:function(){this.save(this.gotoEntry.bind(this))},save:function(i){var r=this;if(!this.loading){this.loading=!0,this.$spinner.removeClass("hidden");var e=Garnish.getPostData(this.$form),n=t.extend({enabled:1},e,this.params);Craft.postActionRequest("entries/save-entry",n,(function(e,n){if(r.loading=!1,r.$spinner.addClass("hidden"),r.$errorList&&r.$errorList.children().remove(),"success"===n)if(e.success)Craft.cp.displayNotice(Craft.t("app","Entry saved.")),i(e);else if(Craft.cp.displayError(Craft.t("app","Couldn’t save entry.")),e.errors)for(var s in r.$errorList||(r.$errorList=t('<ul class="errors"/>').insertAfter(r.$form)),e.errors)if(e.errors.hasOwnProperty(s))for(var a=0;a<e.errors[s].length;a++){var o=e.errors[s][a];t("<li>"+o+"</li>").appendTo(r.$errorList)}}))}},onSave:function(i){var r=t(this.formHtml);if(this.$form.replaceWith(r),Craft.initUiElements(r),this.initForm(r),void 0!==Craft.RecentEntriesWidget)for(var e=0;e<Craft.RecentEntriesWidget.instances.length;e++){var n=Craft.RecentEntriesWidget.instances[e];n.params.sectionId&&n.params.sectionId!=this.params.sectionId||n.addEntry({url:i.cpEditUrl,title:i.title,dateCreated:i.dateCreated,username:i.authorUsername})}},gotoEntry:function(t){Craft.redirectTo(t.cpEditUrl)}})}();
{"version":3,"file":"QuickPostWidget.js","mappings":"YAAA,IAAWA,EAAAA,EAyIRC,OAtIDC,MAAMC,gBAAkBC,QAAQC,KAAKC,OAAO,CAC1CC,OAAQ,KACRC,WAAY,KACZC,SAAU,KACVC,QAAS,KACTC,MAAO,KACPC,SAAU,KACVC,WAAY,KACZC,SAAS,EAETC,KAAM,SAAUC,EAAUT,EAAQC,EAAYC,GAC5CQ,KAAKV,OAASA,EACdU,KAAKT,WAAaA,EAClBS,KAAKR,SAAWA,EAChBQ,KAAKP,QAAUV,EAAE,UAAYgB,GAE7BC,KAAKC,SAASD,KAAKP,QAAQS,KAAK,gBAGlCD,SAAU,SAAUP,GAClBM,KAAKN,MAAQA,EACbM,KAAKL,SAAWK,KAAKN,MAAMQ,KAAK,YAEhCF,KAAKT,aAEL,IAAIY,EAAWH,KAAKN,MAAMQ,KAAK,qCAC7BE,EAA6BD,EAC1BE,KAAK,WACLC,KAAKC,WAAWL,KAAK,iBAE1BC,EAASK,UAETR,KAAKS,YAAYT,KAAKN,MAAO,SAAU,oBACvCM,KAAKS,YACHL,EACA,QACA,2BAIJM,iBAAkB,SAAUC,GAC1BA,EAAMC,iBAENZ,KAAKa,KAAKb,KAAKc,OAAOC,KAAKf,QAG7BgB,uBAAwB,WACtBhB,KAAKa,KAAKb,KAAKiB,UAAUF,KAAKf,QAGhCa,KAAM,SAAUK,GAAU,WACxB,IAAIlB,KAAKH,QAAT,CAIAG,KAAKH,SAAU,EACfG,KAAKL,SAASwB,YAAY,UAE1B,IAAIC,EAAWjC,QAAQkC,YAAYrB,KAAKN,OACtCW,EAAOtB,EAAEM,OAAO,CAACiC,QAAS,GAAIF,EAAUpB,KAAKV,QAE/CL,MAAMsC,kBACJ,qBACAlB,GACA,SAACmB,EAAUC,GAQT,GAPA,EAAK5B,SAAU,EACf,EAAKF,SAAS+B,SAAS,UAEnB,EAAK9B,YACP,EAAKA,WAAW+B,WAAWC,SAGV,YAAfH,EACF,GAAID,EAASK,QACX5C,MAAM6C,GAAGC,cAAc9C,MAAM+C,EAAE,MAAO,iBACtCd,EAASM,QAIT,GAFAvC,MAAM6C,GAAGG,aAAahD,MAAM+C,EAAE,MAAO,yBAEjCR,EAASU,OAOX,IAAK,IAAIC,KANJ,EAAKvC,aACR,EAAKA,WAAab,EAAE,wBAAwBqD,YAC1C,EAAK1C,QAIa8B,EAASU,OAC7B,GAAKV,EAASU,OAAOG,eAAeF,GAIpC,IAAK,IAAIG,EAAI,EAAGA,EAAId,EAASU,OAAOC,GAAWI,OAAQD,IAAK,CAC1D,IAAIE,EAAQhB,EAASU,OAAOC,GAAWG,GACvCvD,EAAE,OAASyD,EAAQ,SAASC,SAAS,EAAK7C,kBAU1DkB,OAAQ,SAAUU,GAEhB,IAAIkB,EAAW3D,EAAEiB,KAAKR,UAMtB,GALAQ,KAAKN,MAAMiD,YAAYD,GACvBzD,MAAM2D,eAAeF,GACrB1C,KAAKC,SAASyC,QAG2B,IAA9BzD,MAAM4D,oBACf,IAAK,IAAIP,EAAI,EAAGA,EAAIrD,MAAM4D,oBAAoBC,UAAUP,OAAQD,IAAK,CACnE,IAAIS,EAAS9D,MAAM4D,oBAAoBC,UAAUR,GAE9CS,EAAOzD,OAAO0D,WACfD,EAAOzD,OAAO0D,WAAahD,KAAKV,OAAO0D,WAEvCD,EAAOE,SAAS,CACdC,IAAK1B,EAAS2B,UACdC,MAAO5B,EAAS4B,MAChBC,YAAa7B,EAAS6B,YACtBC,SAAU9B,EAAS+B,mBAO7BtC,UAAW,SAAUO,GAEnBvC,MAAMuE,WAAWhC,EAAS2B,c","sources":["webpack:///./QuickPostWidget.js"],"sourcesContent":["(function ($) {\n  /** global: Craft */\n  /** global: Garnish */\n  Craft.QuickPostWidget = Garnish.Base.extend({\n    params: null,\n    initFields: null,\n    formHtml: null,\n    $widget: null,\n    $form: null,\n    $spinner: null,\n    $errorList: null,\n    loading: false,\n\n    init: function (widgetId, params, initFields, formHtml) {\n      this.params = params;\n      this.initFields = initFields;\n      this.formHtml = formHtml;\n      this.$widget = $('#widget' + widgetId);\n\n      this.initForm(this.$widget.find('form:first'));\n    },\n\n    initForm: function ($form) {\n      this.$form = $form;\n      this.$spinner = this.$form.find('.spinner');\n\n      this.initFields();\n\n      var $menuBtn = this.$form.find('> .buttons > .btngroup > .menubtn'),\n        $saveAndContinueEditingBtn = $menuBtn\n          .data('menubtn')\n          .menu.$container.find('> ul > li > a');\n\n      $menuBtn.menubtn();\n\n      this.addListener(this.$form, 'submit', 'handleFormSubmit');\n      this.addListener(\n        $saveAndContinueEditingBtn,\n        'click',\n        'saveAndContinueEditing'\n      );\n    },\n\n    handleFormSubmit: function (event) {\n      event.preventDefault();\n\n      this.save(this.onSave.bind(this));\n    },\n\n    saveAndContinueEditing: function () {\n      this.save(this.gotoEntry.bind(this));\n    },\n\n    save: function (callback) {\n      if (this.loading) {\n        return;\n      }\n\n      this.loading = true;\n      this.$spinner.removeClass('hidden');\n\n      var formData = Garnish.getPostData(this.$form),\n        data = $.extend({enabled: 1}, formData, this.params);\n\n      Craft.postActionRequest(\n        'entries/save-entry',\n        data,\n        (response, textStatus) => {\n          this.loading = false;\n          this.$spinner.addClass('hidden');\n\n          if (this.$errorList) {\n            this.$errorList.children().remove();\n          }\n\n          if (textStatus === 'success') {\n            if (response.success) {\n              Craft.cp.displayNotice(Craft.t('app', 'Entry saved.'));\n              callback(response);\n            } else {\n              Craft.cp.displayError(Craft.t('app', 'Couldn’t save entry.'));\n\n              if (response.errors) {\n                if (!this.$errorList) {\n                  this.$errorList = $('<ul class=\"errors\"/>').insertAfter(\n                    this.$form\n                  );\n                }\n\n                for (var attribute in response.errors) {\n                  if (!response.errors.hasOwnProperty(attribute)) {\n                    continue;\n                  }\n\n                  for (var i = 0; i < response.errors[attribute].length; i++) {\n                    var error = response.errors[attribute][i];\n                    $('<li>' + error + '</li>').appendTo(this.$errorList);\n                  }\n                }\n              }\n            }\n          }\n        }\n      );\n    },\n\n    onSave: function (response) {\n      // Reset the widget\n      var $newForm = $(this.formHtml);\n      this.$form.replaceWith($newForm);\n      Craft.initUiElements($newForm);\n      this.initForm($newForm);\n\n      // Are there any Recent Entries widgets to notify?\n      if (typeof Craft.RecentEntriesWidget !== 'undefined') {\n        for (var i = 0; i < Craft.RecentEntriesWidget.instances.length; i++) {\n          var widget = Craft.RecentEntriesWidget.instances[i];\n          if (\n            !widget.params.sectionId ||\n            widget.params.sectionId == this.params.sectionId\n          ) {\n            widget.addEntry({\n              url: response.cpEditUrl,\n              title: response.title,\n              dateCreated: response.dateCreated,\n              username: response.authorUsername,\n            });\n          }\n        }\n      }\n    },\n\n    gotoEntry: function (response) {\n      // Redirect to the entry's edit URL\n      Craft.redirectTo(response.cpEditUrl);\n    },\n  });\n})(jQuery);\n"],"names":["$","jQuery","Craft","QuickPostWidget","Garnish","Base","extend","params","initFields","formHtml","$widget","$form","$spinner","$errorList","loading","init","widgetId","this","initForm","find","$menuBtn","$saveAndContinueEditingBtn","data","menu","$container","menubtn","addListener","handleFormSubmit","event","preventDefault","save","onSave","bind","saveAndContinueEditing","gotoEntry","callback","removeClass","formData","getPostData","enabled","postActionRequest","response","textStatus","addClass","children","remove","success","cp","displayNotice","t","displayError","errors","attribute","insertAfter","hasOwnProperty","i","length","error","appendTo","$newForm","replaceWith","initUiElements","RecentEntriesWidget","instances","widget","sectionId","addEntry","url","cpEditUrl","title","dateCreated","username","authorUsername","redirectTo"],"sourceRoot":""}
                    $('<li>' + error + '</li>').appendTo(this.$errorList);

Fixed code:
- Fixed an XSS vulnerability.
!function(){var t;t=jQuery,Craft.QuickPostWidget=Garnish.Base.extend({params:null,initFields:null,formHtml:null,$widget:null,$form:null,$spinner:null,$errorList:null,loading:!1,init:function(i,r,e,n){this.params=r,this.initFields=e,this.formHtml=n,this.$widget=t("#widget"+i),this.initForm(this.$widget.find("form:first"))},initForm:function(t){this.$form=t,this.$spinner=this.$form.find(".spinner"),this.initFields();var i=this.$form.find("> .buttons > .btngroup > .menubtn"),r=i.data("menubtn").menu.$container.find("> ul > li > a");i.menubtn(),this.addListener(this.$form,"submit","handleFormSubmit"),this.addListener(r,"click","saveAndContinueEditing")},handleFormSubmit:function(t){t.preventDefault(),this.save(this.onSave.bind(this))},saveAndContinueEditing:function(){this.save(this.gotoEntry.bind(this))},save:function(i){var r=this;if(!this.loading){this.loading=!0,this.$spinner.removeClass("hidden");var e=Garnish.getPostData(this.$form),n=t.extend({enabled:1},e,this.params);Craft.postActionRequest("entries/save-entry",n,(function(e,n){if(r.loading=!1,r.$spinner.addClass("hidden"),r.$errorList&&r.$errorList.children().remove(),"success"===n)if(e.success)Craft.cp.displayNotice(Craft.t("app","Entry saved.")),i(e);else if(Craft.cp.displayError(Craft.t("app","Couldn’t save entry.")),e.errors)for(var s in r.$errorList||(r.$errorList=t('<ul class="errors"/>').insertAfter(r.$form)),e.errors)if(e.errors.hasOwnProperty(s))for(var a=0;a<e.errors[s].length;a++){var o=e.errors[s][a];t("<li/>",{text:o}).appendTo(r.$errorList)}}))}},onSave:function(i){var r=t(this.formHtml);if(this.$form.replaceWith(r),Craft.initUiElements(r),this.initForm(r),void 0!==Craft.RecentEntriesWidget)for(var e=0;e<Craft.RecentEntriesWidget.instances.length;e++){var n=Craft.RecentEntriesWidget.instances[e];n.params.sectionId&&n.params.sectionId!=this.params.sectionId||n.addEntry({url:i.cpEditUrl,title:i.title,dateCreated:i.dateCreated,username:i.authorUsername})}},gotoEntry:function(t){Craft.redirectTo(t.cpEditUrl)}})}();
{"version":3,"file":"QuickPostWidget.js","mappings":"YAAA,IAAWA,EAAAA,EA2IRC,OAxIDC,MAAMC,gBAAkBC,QAAQC,KAAKC,OAAO,CAC1CC,OAAQ,KACRC,WAAY,KACZC,SAAU,KACVC,QAAS,KACTC,MAAO,KACPC,SAAU,KACVC,WAAY,KACZC,SAAS,EAETC,KAAM,SAAUC,EAAUT,EAAQC,EAAYC,GAC5CQ,KAAKV,OAASA,EACdU,KAAKT,WAAaA,EAClBS,KAAKR,SAAWA,EAChBQ,KAAKP,QAAUV,EAAE,UAAYgB,GAE7BC,KAAKC,SAASD,KAAKP,QAAQS,KAAK,gBAGlCD,SAAU,SAAUP,GAClBM,KAAKN,MAAQA,EACbM,KAAKL,SAAWK,KAAKN,MAAMQ,KAAK,YAEhCF,KAAKT,aAEL,IAAIY,EAAWH,KAAKN,MAAMQ,KAAK,qCAC7BE,EAA6BD,EAC1BE,KAAK,WACLC,KAAKC,WAAWL,KAAK,iBAE1BC,EAASK,UAETR,KAAKS,YAAYT,KAAKN,MAAO,SAAU,oBACvCM,KAAKS,YACHL,EACA,QACA,2BAIJM,iBAAkB,SAAUC,GAC1BA,EAAMC,iBAENZ,KAAKa,KAAKb,KAAKc,OAAOC,KAAKf,QAG7BgB,uBAAwB,WACtBhB,KAAKa,KAAKb,KAAKiB,UAAUF,KAAKf,QAGhCa,KAAM,SAAUK,GAAU,WACxB,IAAIlB,KAAKH,QAAT,CAIAG,KAAKH,SAAU,EACfG,KAAKL,SAASwB,YAAY,UAE1B,IAAIC,EAAWjC,QAAQkC,YAAYrB,KAAKN,OACtCW,EAAOtB,EAAEM,OAAO,CAACiC,QAAS,GAAIF,EAAUpB,KAAKV,QAE/CL,MAAMsC,kBACJ,qBACAlB,GACA,SAACmB,EAAUC,GAQT,GAPA,EAAK5B,SAAU,EACf,EAAKF,SAAS+B,SAAS,UAEnB,EAAK9B,YACP,EAAKA,WAAW+B,WAAWC,SAGV,YAAfH,EACF,GAAID,EAASK,QACX5C,MAAM6C,GAAGC,cAAc9C,MAAM+C,EAAE,MAAO,iBACtCd,EAASM,QAIT,GAFAvC,MAAM6C,GAAGG,aAAahD,MAAM+C,EAAE,MAAO,yBAEjCR,EAASU,OAOX,IAAK,IAAIC,KANJ,EAAKvC,aACR,EAAKA,WAAab,EAAE,wBAAwBqD,YAC1C,EAAK1C,QAIa8B,EAASU,OAC7B,GAAKV,EAASU,OAAOG,eAAeF,GAIpC,IAAK,IAAIG,EAAI,EAAGA,EAAId,EAASU,OAAOC,GAAWI,OAAQD,IAAK,CAC1D,IAAIE,EAAQhB,EAASU,OAAOC,GAAWG,GACvCvD,EAAE,QAAS,CACT0D,KAAMD,IACLE,SAAS,EAAK9C,kBAUjCkB,OAAQ,SAAUU,GAEhB,IAAImB,EAAW5D,EAAEiB,KAAKR,UAMtB,GALAQ,KAAKN,MAAMkD,YAAYD,GACvB1D,MAAM4D,eAAeF,GACrB3C,KAAKC,SAAS0C,QAG2B,IAA9B1D,MAAM6D,oBACf,IAAK,IAAIR,EAAI,EAAGA,EAAIrD,MAAM6D,oBAAoBC,UAAUR,OAAQD,IAAK,CACnE,IAAIU,EAAS/D,MAAM6D,oBAAoBC,UAAUT,GAE9CU,EAAO1D,OAAO2D,WACfD,EAAO1D,OAAO2D,WAAajD,KAAKV,OAAO2D,WAEvCD,EAAOE,SAAS,CACdC,IAAK3B,EAAS4B,UACdC,MAAO7B,EAAS6B,MAChBC,YAAa9B,EAAS8B,YACtBC,SAAU/B,EAASgC,mBAO7BvC,UAAW,SAAUO,GAEnBvC,MAAMwE,WAAWjC,EAAS4B,c","sources":["webpack:///./QuickPostWidget.js"],"sourcesContent":["(function ($) {\n  /** global: Craft */\n  /** global: Garnish */\n  Craft.QuickPostWidget = Garnish.Base.extend({\n    params: null,\n    initFields: null,\n    formHtml: null,\n    $widget: null,\n    $form: null,\n    $spinner: null,\n    $errorList: null,\n    loading: false,\n\n    init: function (widgetId, params, initFields, formHtml) {\n      this.params = params;\n      this.initFields = initFields;\n      this.formHtml = formHtml;\n      this.$widget = $('#widget' + widgetId);\n\n      this.initForm(this.$widget.find('form:first'));\n    },\n\n    initForm: function ($form) {\n      this.$form = $form;\n      this.$spinner = this.$form.find('.spinner');\n\n      this.initFields();\n\n      var $menuBtn = this.$form.find('> .buttons > .btngroup > .menubtn'),\n        $saveAndContinueEditingBtn = $menuBtn\n          .data('menubtn')\n          .menu.$container.find('> ul > li > a');\n\n      $menuBtn.menubtn();\n\n      this.addListener(this.$form, 'submit', 'handleFormSubmit');\n      this.addListener(\n        $saveAndContinueEditingBtn,\n        'click',\n        'saveAndContinueEditing'\n      );\n    },\n\n    handleFormSubmit: function (event) {\n      event.preventDefault();\n\n      this.save(this.onSave.bind(this));\n    },\n\n    saveAndContinueEditing: function () {\n      this.save(this.gotoEntry.bind(this));\n    },\n\n    save: function (callback) {\n      if (this.loading) {\n        return;\n      }\n\n      this.loading = true;\n      this.$spinner.removeClass('hidden');\n\n      var formData = Garnish.getPostData(this.$form),\n        data = $.extend({enabled: 1}, formData, this.params);\n\n      Craft.postActionRequest(\n        'entries/save-entry',\n        data,\n        (response, textStatus) => {\n          this.loading = false;\n          this.$spinner.addClass('hidden');\n\n          if (this.$errorList) {\n            this.$errorList.children().remove();\n          }\n\n          if (textStatus === 'success') {\n            if (response.success) {\n              Craft.cp.displayNotice(Craft.t('app', 'Entry saved.'));\n              callback(response);\n            } else {\n              Craft.cp.displayError(Craft.t('app', 'Couldn’t save entry.'));\n\n              if (response.errors) {\n                if (!this.$errorList) {\n                  this.$errorList = $('<ul class=\"errors\"/>').insertAfter(\n                    this.$form\n                  );\n                }\n\n                for (var attribute in response.errors) {\n                  if (!response.errors.hasOwnProperty(attribute)) {\n                    continue;\n                  }\n\n                  for (var i = 0; i < response.errors[attribute].length; i++) {\n                    var error = response.errors[attribute][i];\n                    $('<li/>', {\n                      text: error,\n                    }).appendTo(this.$errorList);\n                  }\n                }\n              }\n            }\n          }\n        }\n      );\n    },\n\n    onSave: function (response) {\n      // Reset the widget\n      var $newForm = $(this.formHtml);\n      this.$form.replaceWith($newForm);\n      Craft.initUiElements($newForm);\n      this.initForm($newForm);\n\n      // Are there any Recent Entries widgets to notify?\n      if (typeof Craft.RecentEntriesWidget !== 'undefined') {\n        for (var i = 0; i < Craft.RecentEntriesWidget.instances.length; i++) {\n          var widget = Craft.RecentEntriesWidget.instances[i];\n          if (\n            !widget.params.sectionId ||\n            widget.params.sectionId == this.params.sectionId\n          ) {\n            widget.addEntry({\n              url: response.cpEditUrl,\n              title: response.title,\n              dateCreated: response.dateCreated,\n              username: response.authorUsername,\n            });\n          }\n        }\n      }\n    },\n\n    gotoEntry: function (response) {\n      // Redirect to the entry's edit URL\n      Craft.redirectTo(response.cpEditUrl);\n    },\n  });\n})(jQuery);\n"],"names":["$","jQuery","Craft","QuickPostWidget","Garnish","Base","extend","params","initFields","formHtml","$widget","$form","$spinner","$errorList","loading","init","widgetId","this","initForm","find","$menuBtn","$saveAndContinueEditingBtn","data","menu","$container","menubtn","addListener","handleFormSubmit","event","preventDefault","save","onSave","bind","saveAndContinueEditing","gotoEntry","callback","removeClass","formData","getPostData","enabled","postActionRequest","response","textStatus","addClass","children","remove","success","cp","displayNotice","t","displayError","errors","attribute","insertAfter","hasOwnProperty","i","length","error","text","appendTo","$newForm","replaceWith","initUiElements","RecentEntriesWidget","instances","widget","sectionId","addEntry","url","cpEditUrl","title","dateCreated","username","authorUsername","redirectTo"],"sourceRoot":""}
                    $('<li/>', {
                      text: error,
                    }).appendTo(this.$errorList);