You uploaded a 16×16 pixel icon file. You forgot about it. That file is now identical across every server, staging environment, and internal tool your organization runs — and an attacker just found all of them in under two minutes without sending a single packet to your network.

TL;DR

  • Favicon files are often deployed identically across hundreds of servers, creating a unique fingerprint
  • A single Shodan query using the favicon’s hash can map your entire infrastructure — including servers behind WAFs and CDNs
  • The technique is passive: no scanning, no alerts, no logs on your side
  • One real-world example: one favicon hash returned 363 hostnames, 373 IPs, and 5,091 open ports
  • Defense requires either uniquifying your favicon per environment or blocking direct-IP access at the origin

Why This Matters to You

Most organizations think about attack surface in terms of DNS records, exposed ports, and leaked credentials. The favicon isn’t on that list — it’s a decoration, not infrastructure. That’s exactly why it’s dangerous.

This technique works against everyone from small SaaS companies to government agencies. It requires no special access, no exploitation, and no interaction with the target. It’s purely passive, and it works right now.


What Is Favicon Hash Fingerprinting?

A favicon (short for “favorites icon”) is the small icon shown in browser tabs and bookmarks. Most websites serve it at /favicon.ico.

The attack relies on a simple observation: organizations deploy the same favicon binary across all their infrastructure — the main site, subdomains, staging servers, internal portals, even cloud instances. That binary produces a consistent hash value.

Shodan — an internet-wide scanning service that continuously indexes every internet-facing device — stores and indexes these hashes. The search filter http.favicon.hash:[value] lets anyone query the global index and retrieve every IP address serving that exact icon.

The hash algorithm used is MurmurHash3 (mmh3) — a fast, non-cryptographic hashing function applied to the Base64-encoded favicon data. It’s chosen for speed, not security. The result is a signed 32-bit integer like -1752256170 or 516963061.


Red Team: From One Icon to Full Infrastructure Map

Step 1 — Calculate the target’s favicon hash

Terminal window
# Install mmh3
pip install mmh3 requests
# Calculate hash from target
python3 -c "
import mmh3, requests, base64
r = requests.get('https://target.example/favicon.ico', timeout=10)
favicon_b64 = base64.encodebytes(r.content)
hash_val = mmh3.hash(favicon_b64)
print(f'Favicon hash: {hash_val}')
"

The Base64 encoding step is critical — Shodan hashes the encoded string, not the raw bytes. Getting this wrong produces a hash that matches nothing.

Step 2 — Query Shodan

Terminal window
# Using Shodan CLI
shodan search --fields ip_str,port,hostnames "http.favicon.hash:-1752256170"
# Or via the API
curl "https://api.shodan.io/shodan/host/search?key=APIKEY&query=http.favicon.hash:-1752256170"

You can also use the Shodan web interface directly — no CLI required.

Step 3 — Extract hostnames and IPs

Terminal window
# Parse JSON output with jq
shodan search --format=json "http.favicon.hash:-1752256170" \
| jq -r '.. | arrays[].hostnames?' \
| grep -v null \
| sort -u > discovered_hosts.txt
wc -l discovered_hosts.txt

Step 4 — Feed into port scanner

Terminal window
# Quick nmap sweep on discovered targets
nmap -iL discovered_hosts.txt -p 80,443,8080,8443,22 -T4 --open -oG results.txt
# Or masscan for speed on large lists
masscan -iL discovered_hosts.txt -p 0-65535 --rate 10000

Real-world scale

The SANS ISC case study used a single government domain. Result: 363 hostnames resolved to 373 IPs with 5,091 open ports discovered — in minutes, without touching the target network.


The WAF Bypass: The Most Dangerous Application

Web Application Firewalls (WAFs) like Cloudflare, Akamai, and AWS WAF sit in front of your servers, hide the real IP address, and filter malicious traffic. Attackers can’t scan directly — they only see the WAF’s IP.

Except when the origin server serves the same favicon as the WAF-protected domain.

Browser → Cloudflare (WAF) → Origin Server (hidden)
Also serves favicon.ico
Shodan found this IP
Direct access bypasses WAF

The workflow:

  1. Get the favicon hash from target.example
  2. Search Shodan for that hash
  3. Find an IP that isn’t Cloudflare’s — that’s the origin
  4. Access the origin directly: curl -H "Host: target.example" http://<origin-ip>/

WAF bypassed. No rate limiting. No DDoS protection. No filtering. The organization thought they were protected.

This is why favicon fingerprinting is considered one of the highest-value passive recon techniques — it doesn’t just enumerate infrastructure, it can neutralize an entire defensive layer.


Beyond Shodan: Other Platforms

PlatformQuery syntaxNotes
Shodanhttp.favicon.hash:-1752256170Most widely used
FOFAicon_hash="-1752256170"Large Asian index, often finds different results
ZoomEyeiconhash:"-1752256170"Good coverage of Chinese infrastructure
Censysservices.http.response.favicons.md5_hashUses MD5, different hash required

Running the same favicon across multiple platforms often surfaces additional results — different scanners index at different times and miss different endpoints.


Blue Team: Detection and Defense

Immediate actions

1. Find your own favicon hash

Before an attacker does:

Terminal window
python3 -c "
import mmh3, requests, base64
r = requests.get('https://yourdomain.com/favicon.ico')
print(mmh3.hash(base64.encodebytes(r.content)))
"

Search Shodan for that hash now. The results are your current exposure map.

2. Block direct origin IP access

The WAF bypass only works if your origin server accepts direct connections. Configure your origin to only accept traffic from your CDN/WAF’s IP ranges:

# nginx — allow only Cloudflare IP ranges
location / {
allow 173.245.48.0/20;
allow 103.21.244.0/22;
# ... (full Cloudflare IP list)
deny all;
}

Or with nftables:

Terminal window
chain input {
type filter hook input priority 0;
tcp dport { 80, 443 } ip saddr != { 173.245.48.0/20, 103.21.244.0/22 } drop
}

3. Uniquify your favicon per environment

If every environment serves a different favicon, no single hash maps your entire infrastructure. Options:

  • Append an environment-specific pixel to the favicon at build time
  • Serve a generic/different favicon on internal and staging hosts
  • Use Astro/webpack to hash-append the filename: favicon.abc123.ico
Terminal window
# Quick example: add invisible 1-pixel difference per environment
python3 -c "
from PIL import Image
import os
img = Image.open('favicon.png')
px = img.load()
# Change one pixel based on environment seed
seed = int(os.environ.get('ENV_SEED', '0'))
px[0, 0] = (seed % 256, 0, 0, 255)
img.save('favicon.png')
"

Detection: Are attackers searching for your favicon?

Shodan scans don’t show up in your logs — the query happens on Shodan’s index, not your servers. However, if an attacker found your origin IP and is attempting WAF bypass, you’ll see:

# nginx access log — direct-IP requests without proper Host header
# or from non-CDN IPs
grep "favicon.ico" /var/log/nginx/access.log | grep -v "Cloudflare\|Googlebot"

Set up alerting for requests to /favicon.ico from IPs outside your CDN’s known ranges. This won’t catch passive Shodan searches, but it will flag active exploitation attempts.

Canary favicons for honeypot detection

Deploy a unique favicon on a decoy host and monitor Shodan for queries against that hash — or monitor for connection attempts to the decoy IP. Any hit indicates an attacker actively fingerprinting your infrastructure.


What You Can Do Today

  1. Calculate your favicon hash — run the Python snippet above against your production domain
  2. Search Shodanhttp.favicon.hash:[your_hash] — review everything that shows up
  3. Check origin IP exposure — are any of those results your actual servers, not your CDN?
  4. Restrict origin server access — if you use Cloudflare, Akamai, or any CDN, deny all non-CDN traffic at the firewall level
  5. Audit staging/internal hosts — these are the most common culprits; they serve the production favicon but aren’t behind the WAF

The whole audit takes about 15 minutes. The alternative is leaving it for someone else to find first.



Sources