The first Friday of October 2021 delivered a textbook zero-day scramble: Apache HTTP Server disclosed CVE-2021-41773 and CVE-2021-42013 — path traversal flaws in a rewrite-module feature most admins didn’t know they were running. The number that stunned practitioners: scanning and exploitation began within roughly 24 hours of the 4 October advisory, faster than most enterprises move a single emergency change through CAB. By day three, public mirrors recorded hundreds of unique attacking IPs; by week’s end the trail included webshells, credential dumps, and early ransomware reconnaissance. The bug’s real lesson wasn’t the traversal itself — it was that “safe-by-default” collapsed the moment an admin turned on CGI scripting with the wrong directory grants, and that internet-scanner telemetry (Censys/Shodan-style) surfaced compromised hosts before their own owners knew.
CVE-2021-41773 (and its incomplete-fix successor CVE-2021-42013, published 5 October 2021) are path-traversal vulnerabilities in Apache HTTP Server 2.4.49/2.4.50 affecting configs with Options +FollowSymLinks or SymLinksIfOwnerMatch enabled and a Directory block granting CGI execute — in practice, the Alias-like mapped directories where admins enabled cgi-script handling. Exploitation was a single crafted GET-liner: request a path like
/cgi-bin/.%2e/.%2e/.%2e/etc/passwd and the normalisation bypass walked out of the DocumentRoot to read arbitrary files (source code, config, shell histories); with CGI enabled the same primitive became remote-code-execution by invoking a handler binary. Mass scanning started ~24h post-disclosure (3–4 October); Rapid7/GreyNoise reported hundreds of unique scan sources within days, alongside confirmed webshell infections and credential dumps feeding later access. Fix: upgrade to Apache 2.4.51 (the 42013 fix closed the traversal variant entirely); detect via access-log patterns traversing .%2e sequences, unexpected files read outside docroot, and anomalous CGI process spawns. The deeper 2026 lesson: input-normalisation edge cases in url-path handling remain a top RCE vector class across every web server generation — and patch velocity expectations set by Log4Shell nine weeks later would have made this event look quaint.
What happened
Apache’s 4 October 2021 advisory covered CVE-2021-41773: the mod_alias/merge_path handling in 2.4.49 mis-normalised URLs encoded as .%2e/, letting requests escape aliased directories when FollowSymLinks-style options were on. The real-world blast zone was narrower than headlines implied (CGI-enabled configs only for RCE; plain traversal for file read under specific Options), but the exposed population skewed dangerous: cgi-bin directories are disproportionately live on legacy enterprise apps, appliance firmware, and hosting farms where “webserver config drift” accumulates for decades.
The botch that hardened the event’s notoriety: the first patched release (2.4.50) was itself incomplete — Researchers (private disclosure, coordinated with Apache) showed the encoding variant %%32%65 still traversed, forcing 5 October’s CVE-2021-42013 and the true fix in 2.4.51. Enterprises that had emergency-patched on day one learned the most corrosive lesson in vulnerability management: verify the patch, don’t trust the patch. Meanwhile telemetry firm GreyNoise tracked scan volume jumping from near-zero to double-handled hundreds of unique sources in 72 hours; Censys-style outward scans found pre-existing webshells on hosts whose logs showed earlier, quieter exploitation.
How it worked
The normalisation flaw and its exploit shape:
request: GET /icons/.%2e/.%2e/.%2e/etc/passwd
(icons = Alias-mapped dir with Options FollowSymLinks)
server: path merge normalises "%2e" -> "." segment-wise,
".%2e" survives as a ".."-equivalent token
-> final path resolves OUTSIDE the alias root
file read: arbitrary files as web user (config, source,
.env, shell history, ssh keys readable by daemon)
RCE step: if Directory grants Options +ExecCGI +
AddHandler cgi-script (classic cgi-bin):
GET /cgi-bin/.%2e/.../bin/sh variants or crafted
CGI invocation -> command execution as apache user
incomplete fix (2.4.50): blocked ".%2e" but NOT
double-encoded "%%32%65" -> 42013, fixed in 2.4.51
The defensive bedrock this event etched: web-server path handling is parser-adjacent code that deserves fuzzing-battery treatment, and Options/ExecCGI combinations are configuration-level RCE enablers most hardening guides now explicitly blacklist. That config-drift angle — legacy cgi-bin grants nobody remembers enabling — is the same territory our web attack-surface coverage maps for modern stacks.
Impact and numbers
| Metric | Value | Source |
|---|---|---|
| Disclosure | 2021-10-04 (41773); 2021-10-05 (42013) | Apache advisories |
| Affected versions | 2.4.49 (both); 2.4.50 (42013 only) | Apache |
| Internet-wide exposure | Tens of thousands of servers on 2.4.49/50 at scan time | Censys/Shodan-era scans |
| Scan sources post-disclosure | ~100s unique IPs within 72h; thousands within a week | GreyNoise/Rapid7 |
| Exploit complexity | Single crafted GET (traversal); + CGI grants for RCE | public PoCs |
| Confirmed abuse | Webshells, file exfiltration, Mirai-variant coinminer drops | incident reports/vendors |
| True fix | Apache 2.4.51 | Apache |
Timeline
| Date | Event |
|---|---|
| 2021-09-29 | Apache 2.4.50 released (incomplete traversal fix) |
| 2021-10-04 | CVE-2021-41773 disclosed; patch guidance; scanning begins |
| 2021-10-05 | Bypass found in 2.4.50 → CVE-2021-42013 disclosed same day |
| 2021-10-06+ | Mass scanning; webshell/RCE incidents; coinminer drops reported |
| 2021-10-07 | Apache 2.4.51 — complete fix |
| 2021-10–12 | Long tail: appliance/hosting fleets patched; retro-active compromise hunts |
Why it still matters in 2026
Because the exploit-class never retired: URL-path normalisation bugs have since surfaced in nginx variants, reverse proxies, API gateways, and object-storage front-ends — every generation re-implements the wheel and re-imports the edge cases. Operationally, the event set three durable precedents. First, verify-the-patch doctrine (the 42013 bypass) is now standard runbook language: after any emergency upgrade, validate the CVE’s PoC against your own host before closing the ticket. Second, exposure-driven prioritisation: the attackable sub-population (CGI-enabled directories) was a tiny fraction of “affected” installs, teaching defenders to patch by configuration-reality, not CVE-banner-reach — the same triage discipline we apply across critical-infrastructure threat coverage. Third, scanner-telemetry as an incident-trigger: outward scans found compromise markers before owners did, prefiguring today’s expect-discovery philosophy — if a public PoC exists for your exposure, assume probes began before your morning standup.
Detection and hardening takeaways
- Sweep configs for traversal-enabling Options. Inventory every Directory/Alias block with FollowSymLinks, SymLinksIfOwnerMatch, or ExecCGI grants; kill CGI execute on any path that doesn’t demonstrably need it — the RCE door closes with one config line.
- Alert on encoded-dot access-log signatures. Patterns like
.%2e,%%32%65, and repeated traversal sequences against mapped dirs are scanner behaviour even when they 404; tune WAF rules to flag, correlate by source IP across the estate. - Verify patches with the PoC. The 2.4.50 bypass burned everyone who trusted the version bump: run the actual traversal payload against a staged host post-upgrade before declaring remediated.
- Treat CGI as legacy attack surface. Migrate remaining cgi-bin workloads to modern app servers or reverse-proxied runtimes; every surviving CGI handler is a config-drift RCE waiting for its CVE.
- Monitor outward telemetry for your own hosts. Censys/Shodan/GreyNoise-style queries on your ranges surface webshells and scan-artifacts early; ownership of discovery beats hoping attackers stay quiet.
FAQ
Was every Apache server vulnerable?
No — and that nuance drove the buggy early headlines. Version 2.4.49/2.4.50 was required, plus specific configuration (mapped directories with FollowSymLinks-style options; CGI execution grants for the RCE variant). Most default installs were file-read-safe and RCE-immune. But exposed CGI fleets were over-represented in legacy hosting and appliances, exactly where patch latency is worst.
Why did the first fix fail?
The 2.4.50 patch blocked the literal .%2e encoding researchers had reported, but the underlying normalisation flaw still mishandled a double-encoded variant (%%32%65 decodes to %2e then .). Classic incomplete-blacklist fixing at the parser layer — the complete 2.4.51 fix hardened the normalisation itself.
How does this compare to Log4Shell nine weeks later?
Different scale, same doctrine. Log4Shell’s affected population was orders larger (a library embedded everywhere vs a config-gated server feature), but both events taught identical discipline: exposure-reality over banner-reach triage, PoC-verified patching, and assumption of immediate scanning. Apache administrators who rehearsed on 41773 in October handled December’s Log4Shell migrations measurably better — crisis-drill value is real.
