ColdFusion Hash() Defaults Changed — Here’s How to Fix It With Regex

Starting with ColdFusion 2021 Update 14 and ColdFusion 2023 Update 8, the default hashing algorithm changed from CFMX_COMPAT to SHA-256.

Any code relying on Hash(value) without explicitly specifying the algorithm can:

  • Behave differently after an upgrade
  • Break verification logic
  • Trigger security scanner findings (Fixinator)

Fixinator provides the following warning:

Use of a weak hashing algorithm such as MD5 (the algorithm used by CFMX_COMPAT). This can also be a compatibility issue (after CF2023 update 8 and CF2021 update 14) if the hash algorithm is not specified. The default has changed from CFMX_COMPAT to SHA-256 in those releases.
In CFML, Hash() can appear in two contexts:
  1. Output expressions: #Hash(value)#
  2. Script/logic: Hash(value)

Any global refactor must account for both forms. It took me a few iterations to get what I needed.

This article demonstrates how to perform a global search and replace using REGEX in VS Code.

Note(s):

  • In the VS Code search panel REGEX is enabled with the .* icon to the right of the search input.
  • The ColdFusion app I was working with used only Hash() and not hash().
  • You could use a case insensitive search with the REGEX from Iteration 3 with “Preserve Case” for the replace input to account for Hash() vs hash() if necessary.
  • Your mileage may vary on this solution.

WARNING

PLEASE PREVIEW THE RESULTS OF YOUR SEARCHES BEFORE DOING THE REPLACE.


Iteration 1

This was my first attempt.

Search: #Hash\(\s*([^)]*?)\s*\)#
Replace: #Hash($1, "SHA-256", "UTF-8")#
Bad Match: <a href="edit.cfm?newsID=#qData.newsID#&verifyID=#Hash(qData.newsID, ">Edit</a>
Bad Result: <a href="edit.cfm?newsID=#qData.newsID#&verifyID=#Hash(qData.newsID, ">Edit</a>
Why it’s bad: Caused incorrect code if the algorithm argument already existed.

Iteration 2

Based on the failure of the first attempt I made the following second attempt.

Search: #Hash\(\s*([^,\)]+)\s*\)#
Replace: #Hash($1, "SHA-256", "UTF-8")#
Missed Match:

<cfif Hash(URL.newsID) EQ URL.newsID>
...
</cfif>

Why it’s bad: No match when there were no pound signs (ie Script/logic not output)

Iteration 3

Third time is a charm!

Search: \bHash\(\s*([^,\)\r\n]+?)\s*\)
Replace: Hash($1, "SHA-256", "UTF-8")

cfhash search and replace regex
cfhash search and replace with regex vscode screenshot

Conclusion

YAY! This result yielded 206 corrections throughout the app that would have taken a long time to correct without a REGEX search and replace. This legacy app is 20+ years old so the first goal was compatibility. In a follow up article I’ll look at improving security with HMAC.

Note

This post was amended from “the default hashing algorithm changed from MD5 to SHA-256” to “the default hashing algorithm changed from CFMX_COMPAT to SHA-256”. Even though they do the same thing the default was technically CFMX_COMPAT.