Exercise 2: Why esc_html() on a URL Attribute Is Still a Real Vulnerability — Possible Solution
====================================================================
WHAT EACH FUNCTION IS ACTUALLY DESIGNED FOR, PER THIS CHAPTER
------------------------------
Per this chapter's own table, esc_html() is for "plain text inside an
HTML element's body," while esc_url() is specifically for "a URL, most
often inside an href or src attribute." These are two functions built
for two structurally different output contexts, not interchangeable
general-purpose "make this safe" functions.
WHY USING THE WRONG ONE DEFEATS THE ACTUAL PROTECTION
------------------------------
Per this chapter's own warn-box, "using esc_html() on data being placed
inside an attribute (rather than esc_attr()) doesn't provide the
correct protection for that specific context" - the same reasoning
applies directly to using esc_html() where esc_url() belongs. esc_html()
is built to escape characters that are dangerous specifically inside an
HTML element's body content (like < and >), but it isn't built to
handle the specific dangers of URL/attribute contexts - such as a
malicious value using a javascript: pseudo-protocol, or breaking out of
the surrounding href="..." attribute boundary entirely. esc_html()
simply wasn't designed to guard against those specific attack patterns.
WHY THIS DIRECTLY MATCHES XSS - CROSS SITE SCRIPTING'S OWN GENERAL LESSON
------------------------------
Per this chapter, this "matches exactly the 'encode for the context,
not generically' lesson XSS — Cross Site Scripting already taught in
the abstract." That course's own general principle is that different
output locations (HTML body text, an HTML attribute, a URL, a
JavaScript string) each require their own specific escaping rules,
because each context has its own distinct rules for what characters or
patterns are dangerous. Using any single escaping function
indiscriminately everywhere - even a real, legitimate escaping
function - fails to account for context-specific danger, which is
precisely the mistake happening here.
THE CONCRETE RISK
------------------------------
An attacker able to control the value being output as a URL could craft
a value that esc_html() fails to neutralize but that would genuinely
break out of the attribute or execute malicious behavior when rendered
inside an href attribute specifically - exactly the kind of
context-specific XSS vector esc_url() exists to prevent and esc_html()
was never built to catch.
WHY THIS WORKS AS AN ANSWER
------------------------------
It distinguishes precisely what each function is designed to protect
against per this chapter's own table, explains mechanically why using
the wrong one leaves the actual context-specific danger unaddressed,
and ties the reasoning directly back to XSS's own general
context-dependent encoding principle this chapter explicitly invokes.