You can find the code at: github.com/luis-ota/luis-ota-portfolio.
view-source dissection: the mailto that vanished from my own html

technique: read the deployed html like an attacker and a scraper would. the address was not there.
curl does not lie
<span class="canal-valor">
<span class="__cf_email__" data-cfemail="5c3029352f1c2b352e3938722e2f">[email protected]</span>
</span>
and the link:
<a href="/cdn-cgi/l/email-protection#204c5549536057495245440e5253">
my browser showed [email protected]. the raw html shows a cloudflare artifact and a hex blob. both are true. the difference is a script.
what the cdn does, mechanically
cloudflare's scrape shield scans html for email patterns and replaces them with:
- a
<span class="__cf_email__">whose text is[email protected], - a
data-cfemailattribute: the address, xor'd byte by byte with the first byte as key, - a rewritten
hrefpointing at/cdn-cgi/l/email-protection#..., - an injected script that reverses all of the above at runtime.
the blob is not encryption. decoding is a loop. i decrypted it in a few lines to confirm the encoded address was in fact the new one, not a cached old one.
the consequences:
- without javascript, visitors see
[email protected], - automated checks of my own html see the wrong thing,
- the link goes through cloudflare rather than straight to mailto,
- view-source and curl disagree with the browser, which makes you doubt yourself first and the cdn second.
the fix, layer by layer
keep the text readable without js by storing the @ as an html entity. the browser decodes it; the scanner's regex does not see an email.
<a href="mailto:luis@wired.rs" data-email="luis@wired.rs">luis@wired.rs</a>
cloudflare rewrote the href anyway (it detects mailto:), so a second layer:
const link = document.querySelector("a[data-email]");
if (link) link.href = "mailto:" + link.getAttribute("data-email");
the data attribute survives the rewrite. js restores the link. the no-js case still shows a readable address and points at cloudflare's redirect, which works.
checklist for any cdn-rewritten html
- curl the deployed page, not just the browser tab.
- view-source it.
- test with javascript disabled.
- diff what you wrote against what is served.
- prefer data attributes for anything the cdn likes to rewrite.
middleboxes consider some of your html theirs to edit. the only way to keep the product intact is to serve them something they are happy to leave alone.
image credits
- cover: Rainbow fan sitting under black old fashioned typewriter keyboard keys by Danielle Zarcaro (cc0 1.0)
- image: Microsoft Type Cover 2 - IMG_4252 by Nicola since 1972 (by 2.0)