Patching SUPEE-6788

Unlike many other Magento patches, SUPEE-6788 is not quite a case of fit and forget, it is a complex patch that requires several changes to be made to the store after application.

Where to download

Its best downloading the patch from the Magento.com download section - however, you can also use our Magento download mirror if you know the filename you need.

Breaking changes

After the patch is applied, several issues will need to be rectified. I'd recommend reading the detailed notes from Magento, which explain what is affected and how to rectify each. However, the salient points of what needs manual attention post-patch are,

  • APPSEC-1027: Form key addition 1 - The customer registration and password templates need to be modified to include a form key
  • APPSEC-1034: Securing admin area 1 - 3rd party modules/custom code that has an admin area need to be fixed
  • APPSEC-1057: Variable whitelisting 1 - It is no longer possible to use variables in emails/blocks without whitelisting first (eg. general/store_information/phone)
  • APPSEC-1057: Block whitelisting 1 - It is no longer possible to call custom blocks without whitelisting first (eg. core/template)
  • APPSEC-1063: Scope for SQL injection 1 - 3rd party modules/custom code that uses SQL statements in the addFieldToFilter method need to be fixed
  • APPSEC-1079: Custom option exploit - This change will affect any customization that uses product custom options to save

1 - Requires manual patching

Applying the patch

This step will address,

  • APPSEC-1079: Custom option exploit
  • APPSEC-1027: Form key addition (in base/default, default/iphone, default/modern and rwd/default)

Thankfully, applying the patch itself is no different to the normal Magento patch process. I'd recommend doing this in staging/development before attempting on live (if you don't have a dev. site follow this guide to create one).

  1. Download the patch file to your computer and upload to the document root of your store
  2. Execute the patch file,

     cd /microcloud/data/domains/example/domains/example.com/http
     bash supee-6788.sh

At this stage, the patch is now applied and the manual work of completing the five remaining steps above are required.

Introducing the SUPEE-6788 toolbox

This step will address,

  • APPSEC-1057: Variable whitelisting
  • APPSEC-1057: Block whitelisting

Thanks to a fantastic community effort, the SUPEE-6788 Toolbox provides an automated tool to largely find and fix the majority of the manual items outlined above.

I've forked the main project because the automated admin route fixing feature has proved to be unreliable and can cause more problems than it helps. By skipping this step, it does leave your store vulnerable to exposed admin URLs - however, this can be supplemented by protecting your admin 3rd party module admin URLs using MageStack functionality (I'll expand on this later).

  1. Download the tool,

     cd /microcloud/data/domains/example/domains/example.com/http
     wget --no-check-certificate https://raw.githubusercontent.com/sonassi/supee-6788-toolbox/master/fixSUPEE6788.php -O shell/fixSUPEE6788.php
  2. Then execute the tool using the dry-run functionality to identify the changes required.

     php shell/fixSUPEE6788.php -- analyze

    ! This method is safe to run and will not modify any files.

  3. Once you are confident that the above changes are ready to be rectified (in most cases, this will apply), you can go on to execute the script twice more, in fix mode and fixWhitelists mode.

     php shell/fixSUPEE6788.php -- fix
     php shell/fixSUPEE6788.php -- fixWhitelists

Protecting admin URLs

This step will address,

  • APPSEC-1034: Securing admin area

This step is not a fix, it is a workaround, to allow you to continue to use your store in a safe and secure manner, whilst buying you time to slowly roll out the proper fixes for the admin area of each module as necessary.

Referring to the technical documentation for a full fix is recommended, or by contacting the vendor of all your 3rd party/custom modules to see if there is an updated version compliant with SUPEE-6788. The list of incompatible modules would have been produced during the analyse phase of the SUPEE-6788 toolbox.

  1. Using the guide to identify admin paths

     cd /microcloud/domains/example/domains/example.com/http/app/code
     awk '/<admin>/,/<\/admin>/' $(find -name config.xml) | tr '\n' ' ' | sed -E "s#[ \t]+##g; s#</admin>#</admin>\n\n#g" | ack-grep "<use>admin</use>.+?<frontName>(.+)?</frontName>" --output='$1' | sort -u | tr '\n' '|' | sed 's/|$//g'
  2. Enable admin protection
  3. Then add the resulting regular expression to define a custom admin area on MageStack, in ___general/example.com.conf - replacing module_admin|other_module_admin as necessary.

     set $magestack_protect_admin true;
     if ($request_uri ~* ^/(index\.php/)?(module_admin|other_module_admin)/) {
       set $magestack_is_admin true;
     }
  4. Reload Nginx to reflect your change and verify by trying to access one of the URLs using a third-party test (eg. Pingdom FPT)

Fixing templates

This step will address,

  • APPSEC-1027: Form key addition

I've outlined the changes required for 1.9.2.1 to give you an idea of the scope of changes, for other versions, you'll need to open the patch file itself and search for app/design/frontend to see what the individual changes are that need to be applied to your custom template files.

Go through each patch entry as required, replacing base/default with your own package/design as necessary.

app/design/frontend/base/default/layout/customer.xml

-    <customer_account_resetpassword translate="label">
+    <customer_account_changeforgotten translate="label">
         <label>Reset a Password</label>
         <reference name="content">
-            <block type="customer/account_resetpassword" name="resetPassword" template="customer/form/resetforgottenpassword.phtml"/>
+            <block type="customer/account_changeforgotten" name="changeForgottenPassword" template="customer/form/resetforgottenpassword.phtml"/>
         </reference>
-    </customer_account_resetpassword>
+    </customer_account_changeforgotten>

This can be done in a single command like so,

ack-grep "customer_account_resetpassword" app/design/frontend --xml -l | xargs sed -i 's#customer_account_resetpassword#customer_account_changeforgotten#g'

app/design/frontend/base/default/template/customer/form/register.phtml

             <input type="hidden" name="error_url" value="<?php echo $this->getErrorUrl() ?>" />
+            <input type="hidden" name="form_key" value="<?php echo Mage::getSingleton('core/session')->getFormKey() ?>" />
             <h2 class="legend"><?php echo $this->__('Personal Information') ?></h2>

This can be done in a single command like so,

find app/design/frontend -path "*/template/customer/form/register.phtml" | xargs sed -i 's#</form>#<input type="hidden" name="form_key" value="<?php echo Mage::getSingleton('core/session')->getFormKey() ?>" /></form>#g'

app/design/frontend/base/default/template/customer/form/resetforgottenpassword.phtml

             <?php echo $this->getMessagesBlock()->toHtml(); ?>
-            <form action="<?php echo $this->getUrl('*/*/resetpasswordpost', array('_query' => array('id' => $this->getCustomerId(), 'token' => $this->getResetPasswordLinkToken()))); ?>" method="post" id="form-validate">
+            <form action="<?php echo $this->getUrl('*/*/resetpasswordpost'); ?>" method="post" id="form-validate">
             <div class="fieldset" style="margin-top: 70px;">

This can be done in a single command like so,

find app/design/frontend -path "*customer/form/resetforgottenpassword.phtml" -exec grep -l -E "resetpasswordpost.+_query" "{}" \; | xargs sed -i 's#, array(\'_query\' => array(\'id\' => $this->getCustomerId(), \'token\' => $this->getResetPasswordLinkToken()))##g'

app/design/frontend/base/default/template/persistent/customer/form/register.phtml

             <input type="hidden" name="error_url" value="<?php echo $this->getErrorUrl() ?>" />
+            <input type="hidden" name="form_key" value="<?php echo Mage::getSingleton('core/session')->getFormKey() ?>" />
             <h2 class="legend"><?php echo $this->__('Personal Information') ?></h2>

This can be done in a single command like so,

find app/design/frontend -path "*persistent/customer/form/register.phtml" | xargs sed -i 's#</form>#<input type="hidden" name="form_key" value="<?php echo Mage::getSingleton('core/session')->getFormKey() ?>" /></form>#g'

Fixing SQL injection

This step will address,

  • APPSEC-1063: Scope for SQL injection

Unfortunately, the scope for fixing potential SQL injection targets is far beyond this article.

Referring to the technical documentation for a full fix is recommended, or by contacting the vendor of all your 3rd party/custom modules to see if there is an updated version compliant with SUPEE-6788. The list of incompatible modules would have been produced during the analyse phase of the SUPEE-6788 toolbox.

Known issues

Missing htaccess.sample

If you have cleaned up your Magento installation to remove the *.sample files, the patch will fail to apply if .htaccess.sample is missing (or if any other file is missing). If your patch failed to apply, you need to replace the missing files as necessary and re-execute the patch.

If the patch fails to apply, it will not make any changes to your files. This is because it first runs in "dry run" mode.