Earlier lessons each reached for one specific encoding function without covering the full picture: URLEncodedFormat for a link, a filename-encoding detail on cfheader. This lesson covers CFML's encoding functions properly, the modern EncodeForX family built for XSS prevention, the legacy functions they replaced, and ToBase64 for encoding binary data as text.
Learning Objectives
After completing this lesson, you'll be able to:
- Choose the right EncodeForX function for where a value is actually being output.
- Explain why EncodeForHTML/EncodeForURL/EncodeForJavaScript replaced their older equivalents.
- Encode binary data as text with ToBase64.
Matching the Function to Where the Value Lands
Untrusted Value
Where Is It Being Output?
Matching EncodeForX Function
Safe to Render
The right function depends entirely on context, HTML body, a URL, or inline JavaScript each need a different set of characters escaped.
The EncodeForX Family
| Function | Use It For | Example |
|---|---|---|
| EncodeForHTML(string) | Output inside the body of an HTML tag | encodeForHTML("<test>") → <test> |
| EncodeForURL(string) | A value being embedded in a URL | encodeForURL("<tag>") → %3Ctag%3E |
| EncodeForJavaScript(string) | A value inside JavaScript code (e.g. a string literal) | encodeForJavaScript("foo()") → foo\x28\x29 |
Each takes an optional second canonicalize argument (default false); set it true when a value might already be encoded once and needs normalizing before the real encoding pass.
A Real Example: Three Contexts, Three Functions
userComment = "<script>alert(1)</script>"; // Rendered into an HTML page htmlSafe = encodeForHTML(userComment); // Embedded into a link's query string linkSafe = "/search.cfm?q=" & encodeForURL(userComment); // Embedded inside an inline <script> block jsSafe = "var comment = '" & encodeForJavaScript(userComment) & "';";
Using EncodeForURL on a value that's actually being rendered into HTML (or vice versa) doesn't protect against that context's real injection vector, the function has to match where the value actually lands.
What They Replaced, and Why
| Legacy Function | Status | Replaced By |
|---|---|---|
| HTMLEditFormat(string) | Deprecated since ColdFusion 11, removed entirely in ColdFusion 2025 | EncodeForHTML — HTMLEditFormat had real limitations encoding <, >, and & |
| URLEncodedFormat(string) | Still present, but Adobe's own docs now recommend against it for new code | EncodeForURL |
| JSStringFormat(string) | Still present, weaker protection | EncodeForJavaScript — Adobe's docs describe it as providing less XSS protection |
Encoding Binary Data: ToBase64
encoded = toBase64("Test String");
// VGVzdCBTdHJpbmc=
imageEncoded = toBase64(toBinary(imageRead("photo.jpg")));Base64's standard alphabet includes +, /, and =, none of which are safe to drop directly into a URL. Lucee adds Base64UrlEncode()/Base64UrlDecode() specifically for that case, an extension Adobe ColdFusion doesn't document.
Closing a Real Gap: Non-ASCII Filenames in Content-Disposition
The File Downloads lesson noted that Adobe ColdFusion automatically encodes a Content-Disposition filename using the file's own character encoding. For broader compatibility across clients, the standard approach is providing both a plain ASCII fallback and an explicitly percent-encoded filename* parameter, built with EncodeForURL.
<cfset rawFilename = "résumé-report.pdf">
<cfheader
name="Content-Disposition"
value="attachment; filename=""report.pdf""; filename*=UTF-8''#encodeForURL(rawFilename)#">filename provides a safe ASCII fallback for older clients, filename* provides the real, correctly-encoded name for clients that support it, both point at the same underlying file.
Common Beginner Mistakes
Using HTMLEditFormat or URLEncodedFormat in new code
HTMLEditFormat is removed entirely as of ColdFusion 2025, and Adobe's own docs recommend EncodeForURL over URLEncodedFormat for new applications. Reach for the EncodeForX family instead.
Using the wrong EncodeForX function for the actual output context
EncodeForURL on a value being rendered into HTML (or the reverse) doesn't protect against that context's real injection vector, the function has to match where the value actually lands.
Assuming ToBase64 output is safe to drop directly into a URL
Standard Base64 includes +, /, and =, characters that aren't URL-safe. Use a URL-safe variant (Lucee's Base64UrlEncode, for example) or encode it again with EncodeForURL.
Best Practices
- Match the encoding function to exactly where the value is being rendered, HTML body, URL, or JavaScript.
- Prefer EncodeForHTML/EncodeForURL/EncodeForJavaScript over their deprecated predecessors in new code.
- Set canonicalize=true when a value might already be partially encoded, to normalize it before the real encoding pass.
- Provide both an ASCII fallback and a properly percent-encoded filename* when a downloaded file's name contains non-ASCII characters.
Interview Questions
Why did EncodeForHTML replace HTMLEditFormat?
HTMLEditFormat had real limitations encoding <, >, and &. It's deprecated since ColdFusion 11 and removed entirely in ColdFusion 2025, EncodeForHTML addresses those gaps and is the current recommendation.
Why isn't EncodeForURL a substitute for EncodeForHTML, or the reverse?
Each escapes a different set of characters for a different output context. Using the wrong one doesn't protect against that context's actual injection vector, HTML body versus a URL are genuinely different attack surfaces.
Why can't standard Base64 output be dropped directly into a URL?
Its alphabet includes +, /, and =, none of which are URL-safe as-is. A URL-safe Base64 variant, or an additional pass through EncodeForURL, handles it correctly.
What does the canonicalize argument on EncodeForHTML/EncodeForURL/EncodeForJavaScript do?
When true, it normalizes a value that might already be encoded (mixed or multiple encodings) before the actual encoding pass runs, rather than encoding an already-encoded value on top of itself.
Summary
In this lesson, you used EncodeForHTML, EncodeForURL, and EncodeForJavaScript for their respective output contexts, covered why they replaced HTMLEditFormat, URLEncodedFormat, and JSStringFormat, encoded binary data with ToBase64, and closed the non-ASCII filename gap from the File Downloads lesson with a properly encoded filename* parameter.
What's Next?
The next lesson moves to sending email from a ColdFusion application, starting with an overview before the cfmail, cfimap, and cfpop tags in the lessons that follow.