Magento LTS's guest order "protect code" can be brute-forced too easily
Description
Magento LTS is the official OpenMage LTS codebase. Guest orders may be viewed without authentication using a "guest-view" cookie which contains the order's "protect_code". This code is 6 hexadecimal characters which is arguably not enough to prevent a brute-force attack. Exposing each order would require a separate brute force attack. This issue has been patched in versions 19.5.1 and 20.1.1.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Guest order protect code in OpenMage Magento LTS is only 6 hex characters, enabling brute-force attacks to view orders without authentication.
Vulnerability
Details
CVE-2023-41879 affects OpenMage Magento LTS, the official community-maintained codebase. Guest orders can be viewed without authentication by setting a "guest-view" cookie that contains the order's "protect_code". This protect code is only 6 hexadecimal characters, providing at most 24 bits of entropy, which is insufficient to prevent brute-force attacks [1][2][3].
Exploitation
An attacker can brute-force the protect code for a given order by iterating over the 16^6 possible values. Since order numbers are assigned incrementally, an attacker can narrow the search space by placing a guest order to determine the current order number range [3]. The attack requires no authentication and can be performed remotely. Each order requires a separate brute-force attempt, but the low entropy makes it feasible.
Impact
Successful brute-force allows an attacker to view sensitive order information, including billing address, shipping address, payment details, and other personal data [3]. This compromises customer privacy and could lead to further attacks.
Mitigation
The issue has been patched in versions 19.5.1 and 20.1.1 by introducing rate limiting on the guest order view route (sales/guest/view/) [1][2]. The patch adds a configurable rate limit that blocks excessive requests from the same IP address. As a workaround, administrators can implement strict rate limiting at the web server level, e.g., 1 request per minute per IP for the affected route [3].
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 |
|---|---|---|
openmage/magento-ltsPackagist | < 19.5.1 | 19.5.1 |
openmage/magento-ltsPackagist | >= 20.0.0, < 20.1.1 | 20.1.1 |
Affected products
2- OpenMage/magento-ltsv5Range: <= 19.5.0
Patches
231e74ac5d670Merge pull request from GHSA-9358-cpvx-c2qp
6 files changed · +73 −38
app/code/core/Mage/Core/etc/config.xml+4 −0 modified@@ -315,6 +315,10 @@ <csrf> <use_form_key>1</use_form_key> </csrf> + <rate_limit> + <active>1</active> + <timeframe>30</timeframe> + </rate_limit> <cache> <flush_cron_expr>30 2 * * *</flush_cron_expr> </cache>
app/code/core/Mage/Core/etc/system.xml+27 −36 modified@@ -50,6 +50,33 @@ </use_form_key> </fields> </csrf> + <rate_limit translate="label comment" module="core"> + <label>Rate limit</label> + <sort_order>10</sort_order> + <show_in_default>1</show_in_default> + <show_in_website>1</show_in_website> + <show_in_store>1</show_in_store> + <comment>This functionality limits the number of requests a user (identified by IP address) can perform within a specific time frame, preventing excessive resources usage and maintaining system performance, stability and security.</comment> + <fields> + <active translate="label"> + <label>Enabled</label> + <frontend_type>select</frontend_type> + <source_model>adminhtml/system_config_source_yesno</source_model> + <sort_order>10</sort_order> + <show_in_default>1</show_in_default> + <show_in_website>1</show_in_website> + <show_in_store>1</show_in_store> + </active> + <timeframe translate="label comment"> + <label>Timeframe</label> + <sort_order>20</sort_order> + <show_in_default>1</show_in_default> + <show_in_website>1</show_in_website> + <show_in_store>1</show_in_store> + <comment>Number of seconds between each allowed request.</comment> + </timeframe> + </fields> + </rate_limit> <cache translate="label" module="core"> <label>Advanced Cache Settings</label> <sort_order>1000</sort_order> @@ -69,13 +96,6 @@ </cache> </groups> </system> - <!--<web_track translate="label" module="core"> - <label>Web Tracking</label> - <sort_order>180</sort_order> - <show_in_default>1</show_in_default> - <show_in_website>1</show_in_website> - <show_in_store>1</show_in_store> - </web_track>--> <advanced translate="label" module="core"> <label>Advanced</label> <tab>advanced</tab> @@ -84,35 +104,6 @@ <show_in_website>1</show_in_website> <show_in_store>1</show_in_store> <groups> - <!--datashare translate="label"> - <label>Datasharing</label> - <sort_order>1</sort_order> - <show_in_default>1</show_in_default> - <show_in_website>1</show_in_website> - <show_in_store>0</show_in_store> - <fields> - <default translate="label"> - <label>Default</label> - <frontend_type>multiselect</frontend_type> - <backend_model>adminhtml/system_config_backend_datashare</backend_model> - <source_model>adminhtml/system_config_source_store</source_model> - <sort_order>1</sort_order> - <show_in_default>1</show_in_default> - <show_in_website>1</show_in_website> - <show_in_store>1</show_in_store> - </default> - <default translate="label"> - <label>Default</label> - <frontend_type>multiselect</frontend_type> - <backend_model>adminhtml/system_config_backend_datashare</backend_model> - <source_model>adminhtml/system_config_source_store</source_model> - <sort_order>1</sort_order> - <show_in_default>1</show_in_default> - <show_in_website>1</show_in_website> - <show_in_store>1</show_in_store> - </default> - </fields> - </datashare--> <modules_disable_output translate="label"> <label>Disable Modules Output</label> <frontend_model>adminhtml/system_config_form_fieldset_modules_disableOutput</frontend_model>
app/code/core/Mage/Core/Helper/Data.php+35 −0 modified@@ -999,4 +999,39 @@ public function unEscapeCSVData($data) } return $data; } + + /** + * @param bool $setErrorMessage Adds a predefined error message to the 'core/session' object + * @return bool + */ + public function isRateLimitExceeded($setErrorMessage = true, $recordRateLimitHit = true): bool + { + $active = Mage::getStoreConfigFlag('system/rate_limit/active'); + if ($active && $remoteAddr = Mage::helper('core/http')->getRemoteAddr()) { + $cacheTag = 'rate_limit_' . $remoteAddr; + if (Mage::app()->testCache($cacheTag)) { + $errorMessage = "Too Soon: You are trying to perform this operation too frequently. Please wait a few seconds and try again."; + Mage::getSingleton('core/session')->addError($this->__($errorMessage)); + return true; + } + + if ($recordRateLimitHit) { + $this->recordRateLimitHit(); + } + } + + return false; + } + + /** + * @return void + */ + public function recordRateLimitHit(): void + { + $active = Mage::getStoreConfigFlag('system/rate_limit/active'); + if ($active && $remoteAddr = Mage::helper('core/http')->getRemoteAddr()) { + $cacheTag = 'rate_limit_' . $remoteAddr; + Mage::app()->saveCache(1, $cacheTag, ['brute_force'], Mage::getStoreConfig('system/rate_limit/timeframe')); + } + } }
app/code/core/Mage/Sales/Helper/Guest.php+5 −1 modified@@ -106,6 +106,7 @@ public function loadValidOrder() $errors = true; } } else { + Mage::helper('core')->recordRateLimitHit(); $errors = true; } } @@ -115,7 +116,10 @@ public function loadValidOrder() return true; } - Mage::getSingleton('core/session')->addError($this->__($errorMessage)); + if (!Mage::helper('core')->isRateLimitExceeded(true, false)) { + Mage::getSingleton('core/session')->addError($this->__($errorMessage)); + } + Mage::app()->getResponse()->setRedirect(Mage::getUrl('sales/guest/form')); return false; }
app/code/core/Mage/Sales/Model/Order.php+1 −1 modified@@ -2346,7 +2346,7 @@ protected function _beforeSave() } if (!$this->getId()) { - $this->setData('protect_code', substr(md5(uniqid(mt_rand(), true) . ':' . microtime(true)), 5, 6)); + $this->setData('protect_code', Mage::helper('core')->getRandomString(16)); } if ($this->getStatus() !== $this->getOrigData('status')) {
app/locale/en_US/Mage_Core.csv+1 −0 modified@@ -384,6 +384,7 @@ "Timezone","Timezone" "Title Prefix","Title Prefix" "Title Suffix","Title Suffix" +"Too Soon: You are trying to perform this operation too frequently. Please wait a few seconds and try again.","Too Soon: You are trying to perform this operation too frequently. Please wait a few seconds and try again." "Transactional Emails","Transactional Emails" "Translate Inline","Translate Inline" "Translate, blocks and other output caches should be disabled for both frontend and admin inline translations.","Translate, blocks and other output caches should be disabled for both frontend and admin inline translations."
2a2a2fb50424Merge pull request from GHSA-9358-cpvx-c2qp
6 files changed · +73 −38
app/code/core/Mage/Core/etc/config.xml+4 −0 modified@@ -315,6 +315,10 @@ <csrf> <use_form_key>1</use_form_key> </csrf> + <rate_limit> + <active>1</active> + <timeframe>30</timeframe> + </rate_limit> <cache> <flush_cron_expr>30 2 * * *</flush_cron_expr> </cache>
app/code/core/Mage/Core/etc/system.xml+27 −36 modified@@ -50,6 +50,33 @@ </use_form_key> </fields> </csrf> + <rate_limit translate="label comment" module="core"> + <label>Rate limit</label> + <sort_order>10</sort_order> + <show_in_default>1</show_in_default> + <show_in_website>1</show_in_website> + <show_in_store>1</show_in_store> + <comment>This functionality limits the number of requests a user (identified by IP address) can perform within a specific time frame, preventing excessive resources usage and maintaining system performance, stability and security.</comment> + <fields> + <active translate="label"> + <label>Enabled</label> + <frontend_type>select</frontend_type> + <source_model>adminhtml/system_config_source_yesno</source_model> + <sort_order>10</sort_order> + <show_in_default>1</show_in_default> + <show_in_website>1</show_in_website> + <show_in_store>1</show_in_store> + </active> + <timeframe translate="label comment"> + <label>Timeframe</label> + <sort_order>20</sort_order> + <show_in_default>1</show_in_default> + <show_in_website>1</show_in_website> + <show_in_store>1</show_in_store> + <comment>Number of seconds between each allowed request.</comment> + </timeframe> + </fields> + </rate_limit> <cache translate="label" module="core"> <label>Advanced Cache Settings</label> <sort_order>1000</sort_order> @@ -69,13 +96,6 @@ </cache> </groups> </system> - <!--<web_track translate="label" module="core"> - <label>Web Tracking</label> - <sort_order>180</sort_order> - <show_in_default>1</show_in_default> - <show_in_website>1</show_in_website> - <show_in_store>1</show_in_store> - </web_track>--> <advanced translate="label" module="core"> <label>Advanced</label> <tab>advanced</tab> @@ -84,35 +104,6 @@ <show_in_website>1</show_in_website> <show_in_store>1</show_in_store> <groups> - <!--datashare translate="label"> - <label>Datasharing</label> - <sort_order>1</sort_order> - <show_in_default>1</show_in_default> - <show_in_website>1</show_in_website> - <show_in_store>0</show_in_store> - <fields> - <default translate="label"> - <label>Default</label> - <frontend_type>multiselect</frontend_type> - <backend_model>adminhtml/system_config_backend_datashare</backend_model> - <source_model>adminhtml/system_config_source_store</source_model> - <sort_order>1</sort_order> - <show_in_default>1</show_in_default> - <show_in_website>1</show_in_website> - <show_in_store>1</show_in_store> - </default> - <default translate="label"> - <label>Default</label> - <frontend_type>multiselect</frontend_type> - <backend_model>adminhtml/system_config_backend_datashare</backend_model> - <source_model>adminhtml/system_config_source_store</source_model> - <sort_order>1</sort_order> - <show_in_default>1</show_in_default> - <show_in_website>1</show_in_website> - <show_in_store>1</show_in_store> - </default> - </fields> - </datashare--> <modules_disable_output translate="label"> <label>Disable Modules Output</label> <frontend_model>adminhtml/system_config_form_fieldset_modules_disableOutput</frontend_model>
app/code/core/Mage/Core/Helper/Data.php+35 −0 modified@@ -1000,4 +1000,39 @@ public function unEscapeCSVData($data) } return $data; } + + /** + * @param bool $setErrorMessage Adds a predefined error message to the 'core/session' object + * @return bool + */ + public function isRateLimitExceeded($setErrorMessage = true, $recordRateLimitHit = true): bool + { + $active = Mage::getStoreConfigFlag('system/rate_limit/active'); + if ($active && $remoteAddr = Mage::helper('core/http')->getRemoteAddr()) { + $cacheTag = 'rate_limit_' . $remoteAddr; + if (Mage::app()->testCache($cacheTag)) { + $errorMessage = "Too Soon: You are trying to perform this operation too frequently. Please wait a few seconds and try again."; + Mage::getSingleton('core/session')->addError($this->__($errorMessage)); + return true; + } + + if ($recordRateLimitHit) { + $this->recordRateLimitHit(); + } + } + + return false; + } + + /** + * @return void + */ + public function recordRateLimitHit(): void + { + $active = Mage::getStoreConfigFlag('system/rate_limit/active'); + if ($active && $remoteAddr = Mage::helper('core/http')->getRemoteAddr()) { + $cacheTag = 'rate_limit_' . $remoteAddr; + Mage::app()->saveCache(1, $cacheTag, ['brute_force'], Mage::getStoreConfig('system/rate_limit/timeframe')); + } + } }
app/code/core/Mage/Sales/Helper/Guest.php+5 −1 modified@@ -105,6 +105,7 @@ public function loadValidOrder() $errors = true; } } else { + Mage::helper('core')->recordRateLimitHit(); $errors = true; } } @@ -114,7 +115,10 @@ public function loadValidOrder() return true; } - Mage::getSingleton('core/session')->addError($this->__($errorMessage)); + if (!Mage::helper('core')->isRateLimitExceeded(true, false)) { + Mage::getSingleton('core/session')->addError($this->__($errorMessage)); + } + Mage::app()->getResponse()->setRedirect(Mage::getUrl('sales/guest/form')); return false; }
app/code/core/Mage/Sales/Model/Order.php+1 −1 modified@@ -2372,7 +2372,7 @@ protected function _beforeSave() } if (!$this->getId()) { - $this->setData('protect_code', substr(md5(uniqid(mt_rand(), true) . ':' . microtime(true)), 5, 6)); + $this->setData('protect_code', Mage::helper('core')->getRandomString(16)); } if ($this->getStatus() !== $this->getOrigData('status')) {
app/locale/en_US/Mage_Core.csv+1 −0 modified@@ -384,6 +384,7 @@ "Timezone","Timezone" "Title Prefix","Title Prefix" "Title Suffix","Title Suffix" +"Too Soon: You are trying to perform this operation too frequently. Please wait a few seconds and try again.","Too Soon: You are trying to perform this operation too frequently. Please wait a few seconds and try again." "Transactional Emails","Transactional Emails" "Translate Inline","Translate Inline" "Translate, blocks and other output caches should be disabled for both frontend and admin inline translations.","Translate, blocks and other output caches should be disabled for both frontend and admin inline translations."
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-9358-cpvx-c2qpghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-41879ghsaADVISORY
- github.com/OpenMage/magento-lts/commit/2a2a2fb504247e8966f8ffc2e17d614be5d43128ghsax_refsource_MISCWEB
- github.com/OpenMage/magento-lts/commit/31e74ac5d670b10001f88f038046b62367f15877ghsax_refsource_MISCWEB
- github.com/OpenMage/magento-lts/releases/tag/v19.5.1ghsax_refsource_MISCWEB
- github.com/OpenMage/magento-lts/releases/tag/v20.1.1ghsax_refsource_MISCWEB
- github.com/OpenMage/magento-lts/security/advisories/GHSA-9358-cpvx-c2qpghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.