The Two-Hundred Mask: Reading Intent When Nothing Returns 404
TI-2026-086P ยท Series: The Wardrobe ยท Case 16 ยท Classification: HIGH ยท Confidence: HIGH
Every case so far has been about one mask โ the forged crawler identity in the User-Agent. This case is about the second mask, the one the estate itself puts on. On an auth-proxy-fronted network, a scanner's probe almost never gets an honest 404: the login proxy answers 200 or 401, the catchall answers 200, and the status code โ the field a defender instinctively trusts to tell attack from noise โ goes as blank as the User-Agent is false. So every probe here lies twice: about who is asking, and about whether it worked. This case is how you read the truth when both the visitor and your own server are wearing a mask.
Executive Summary
Here is the single number that makes the case. The Vhost Sweep AS8075 campaign โ 19 IPs, 10,849 requests โ carries an effective bad-rate of 0.96 at a raw 404-rate of 0.00. Its sibling Vhost Sweep AS16509 reads 0.91 at 0.00. Read those side by side:
- A defender counting error codes โ 404 spikes, WAF error-rate rules, "how many probes missed" โ sees zero. Nothing 404s. By that metric there is no attack.
- The intent-aware classifier sees ninety-six percent bad.
The gap between those two numbers is the blind spot, and it is created by the estate's own architecture. Authelia, the forward-auth proxy, answers scanner paths on protected hosts with 200 (it serves the login single-page app) or 401 โ never the 404 the scanner expected. Catchall routes answer nonexistent hosts with 200. So the status code is masked to uselessness, and stacked on the attacker's forged crawler UA it becomes a second mask: the probe lies about who (spoofed identity) and about whether it worked (masked status).
The resolution is the discipline the whole series runs on, applied to a second field: read the thing the deceiver does not control. For identity that was provenance, not the string (086E). For success it is method and target, not status โ decode the real path the scanner asked for and classify by intent, and the badness the 200 hid comes straight back.
Two Masks, Stacked
Take one node and watch both masks operate. 34.95.201.0, the Fake-ia_archiver member from 086C, fired 79 distinct .env paths at peertube.shuffle-on.com, and the dossier records "92% of hits masked behind 200s." Read that literally through a status lens and it is nonsense in the attacker's favour: a "crawler" made 79 requests and got 79 200 OKs. No errors, no 404 storm, a clean-looking log line. Both masks are doing their job โ the UA says Internet Archive, the status says success, and both are lies.
35.240.197.184, the Fake-Googlebot vhost-enumerator, shows the mixed case: 12 requests, 10 ร 404, 1 ร 401, 8% masked-200, guessing nine nonexistent internal subdomains (lsn-auth, lsn-pgadmin, lsn-redis, lsn-qdrantโฆ). Here some probes 404 and some are masked โ a status-count would catch part of it and miss the rest, which is worse than missing all of it, because a partial signal invites a partial rule that the attacker then tunes against.
The point generalises past any node. On an estate where the proxy and the catchall between them absorb almost every scanner path into a 200 or a 401, the honest 404 is the exception, not the rule. The status code is not occasionally unreliable here; it is architecturally masked by default. And that mask sits on top of the identity mask the whole series has been unmasking. A defender who trusts the User-Agent is deceived by the attacker; a defender who trusts the status code is deceived by their own server; a defender who trusts both sees a fleet of legitimate crawlers having a completely successful, entirely benign day.
Why the Server Masks Its Own Status
It is worth being clear that the response mask is not a flaw โ it is a defence, and a good one, which is exactly what makes it dangerous to read naively.
The masked-200 starves the harvester of its oracle. A secret-file sweep works by reading the status: 404 for the 149 filenames that do not exist, 200 for the one that does, and that difference is how the harvester finds the prize (086C). When Authelia returns a uniform 401, or the catchall a uniform 200, every path answers the same, so the harvest learns nothing โ it cannot tell a real .env from a miss. The response mask is the estate denying the attacker the very signal the attacker came for. That is why 34.95.201.0's 79-path sweep found nothing: not because the files were absent, but because the response carried no information about their absence or presence.
So the masked-200 is simultaneously defensively excellent (it beats the harvest) and observationally treacherous (it beats a status-reading defender). The same uniformity that denies the attacker an oracle denies the naive defender a signal. Both parties are looking at the status code; both are being told the same uninformative thing; and only the party that stops looking at the status code โ and reads the intent underneath โ recovers the truth. The estate defends by masking; the estate detects by refusing to trust its own mask.
Piercing Both Masks: Method and Host, Not Status
The pipeline recovers the intent the two masks hide with the same move that recovered identity in 086E โ it reads the field the deceiver cannot control. Two of them, here:
The decoded target. When Authelia intercepts a scanner and returns the login SPA, it encodes the actual path the scanner asked for in the ?rd= (redirect) query parameter โ that is how the proxy knows where to send you after login. The pipeline decodes ?rd= to recover the real target: /.env, /wp-admin, a guessed subdomain. The 200 is a mask over the request, but the request survives inside the redirect the mask itself carries. The attacker cannot forge that away without ceasing to reach the target.
The target-host-type. The classifier records, for every probe, whether the host it hit was exposed_public, internal, served_by_real_service, or nonexistent_guessed, and by what method. 35.240.197.184 is filed target_host_type=nonexistent_guessed, nonexistent_hosts=9, method={GET:12} โ the classifier reads vhost_enum from the fact that the client is guessing hostnames that were never published, not from any status code, all of which were masked. A probe that guesses nine nonexistent internal subdomains is reconnaissance whether the server answers 200, 401, or 404.
Feed those two fields โ decoded target and host-type โ into intent classification, and the effective bad-rate is computed from intent, not status. That is the whole reason it can read 0.96 while the raw 404-rate reads 0.00: the two metrics measure different things, and only one of them is looking at a field the masks do not control. This is the web-threats disambiguation programme's founding purpose โ to make the pipeline method- and host-aware precisely so the HTTP-200 mask cannot hide intent โ and the metric divergence is the proof it works.
Steelmanning: "You're just moving trust from status to your own classifier"
The fair objection: replacing "trust the status code" with "trust the intent label" does not remove trust, it relocates it โ now everything rides on the classifier's ?rd= decode and its host-typing being correct, and those can be wrong too (a mis-decoded redirect, a mis-typed host). Is intent-classification any less a single point of failure than the status code was?
Two answers, and they are the series' recurring shape. First, the relocation is toward a field the deceiver does not control, which is the entire value: the attacker controls its User-Agent and, indirectly, forces the masked status by hitting protected paths, but it does not control what the ?rd= parameter records about the path it requested, nor what host-type its target actually was. Trust moved from two attacker-influenced fields (UA, and status-via-path-choice) to one attacker-fixed field (the target it went after). Second, the classifier's reading is corroborated and cross-checked โ the same probe is scored by intent, cross-referenced to the fleet (086A), the provenance verdict (086E), and third-party reputation (the corroborators of the next case), so a single mis-decode does not carry a verdict alone. The objection correctly notes that intent classification is not trust-free; the answer is that it is trust placed where the attacker's two masks cannot reach, and it is checked against independent signals rather than believed on its own.
What Holds, and What Is Bounded
Documented, HIGH confidence: the ebr-0.96-at-404-rate-0.00 divergence for the vhost-sweep campaigns; the masked-200 percentages on the specific nodes; the Authelia ?rd= decode and target-host-type classification as the piercing mechanism; the masked-200's dual role (harvest starvation + status blindness).
Bounded: the exact share of all estate traffic that is masked-200 versus honest-404 is not quantified here beyond the per-campaign and per-node figures; the claim is that on an auth-proxy estate the mask is the default, evidenced by the 0.00 raw-404 campaigns, not that a specific global percentage holds. The ?rd= decode's own error rate is a monitoring follow-up (paired with 086L's curation-freshness follow-up).
Why It Matters
The Two-Hundred Mask completes the deception picture by naming the mask nobody thinks of as a mask โ the server's own status code. The series has spent fifteen cases teaching that the User-Agent is not identity; this case teaches the harder half, that the status code is not outcome. On a modern edge fronted by an auth proxy, a 200 does not mean the request succeeded, a 401 does not mean it was a login attempt, and the near-total absence of 404s does not mean the absence of attack โ it means the presence of masking. A defender who has learned to distrust the visitor's claimed identity but still trusts their own server's status code has unmasked one deceiver and been fooled by the other.
The resolution is one principle applied twice: read the field the deceiver cannot control. Against the attacker's identity mask, that field is provenance. Against the architecture's status mask, it is the decoded target and the host-type. In both cases the deceived field (UA, status) is discarded and the intent underneath โ who can you prove you are, what did you actually go after โ is what carries the verdict. The two masks fall to the same discipline, and the metric that reads 0.96 badness through a 0.00 error-rate is what it looks like when a defender stops believing what they are told and starts reading what was done.
Cross-references
- TI-2026-086C โ The Archivist's Coat โ the 200-wall as harvest starvation; here read as the observability problem it also creates.
- TI-2026-086E โ The Newest Trust โ identity judged by provenance-not-string; this case judges outcome by target-not-status, the same discipline against a second mask.
- TI-2026-059D โ Scanners in the Mirror / The Front Door โ the Authelia
?rd=decode and masked-200 mechanics this case generalises. - TI-2026-086I โ The Costume Fits the Crime โ intent classification, the signal that survives both masks.
Next in the series โ TI-2026-086Q, The robots.txt Tell: what the masks do โ and pointedly do not do โ with the one file every real crawler reads first.
TLP:WHITE. Defensive architecture and attacker fleet metrics only. No internal addresses or secrets disclosed.