The Watchers: Seven Thousand Addresses to Read One Page
This series has now caught its own instrument four times. Letter E found it trusting a header the client forged. Letter I found it trusting a parameter the defence itself wrote. Letter J found it trusting a status code an SPA router attached at random. Letter K found it asking the right questions of the wrong object.
Between K and this letter, all four were fixed.
This is what changed โ and what the corrected instrument showed within an hour of being corrected, which is a population of 7,109 addresses that had been arriving here for two months and was, by construction, invisible.
What the corrections moved
| Before | After | |
|---|---|---|
Addresses labelled auth_bruteforce | 6 | 1 |
| Requests recognised as an application catch-all | 0 | 5,231 |
| Hosts known to serve one | 2 (named in Letter J) | 5 |
Addresses labelled distributed_scraper | 505 | 6,100 |
Estate-wide, of 288,430 requests in the corpus, 22,644 โ 7.9% โ now carry a status different from the one the origin returned:
| Origin said | The corrected reading | Requests |
|---|---|---|
| 200 | 401 โ an authentication challenge | 16,610 |
| 200 | 404 โ the file does not exist | 5,921 |
| 304 | 401 | 113 |
One request in thirteen was reporting something that did not happen.
What that correction did to this estate's own health metrics
The mask fix is not only about counting attackers. effective_status is what the pipeline uses to compute a host's bad rate โ the share of requests it failed to serve โ and that number feeds campaign detection, threat scoring and the ban pipeline. Correcting the catch-all changed it on five hosts, in one direction, by a lot:
| Host | Bad rate, reading the raw status | Bad rate, corrected |
|---|---|---|
lsn-ai.shuffle-on.com | 5.8% | 48.5% |
lsn-ragflow.shuffle-on.com | 13.4% | 52.6% |
peertube.shuffle-on.com | 4.1% | 46.9% |
lsn-meet.shuffle-on.com | 13.5% | 64.4% |
lsn-photos.shuffle-on.com | 58.5% | 73.9% |
Read the first two rows again. lsn-ai appeared to be a healthy service failing 6% of requests. It was actually failing to serve half of everything asked of it, and saying 200 OK while doing so. peertube looked like the healthiest host on the estate at 4.1%; it is at 46.9%.
Nothing was broken. Every one of those failures is a scanner asking for a file that does not exist, which is the correct thing for the host to refuse. The point is narrower and worse: a monitoring stack reading raw status codes would have reported those five services as fine, because the applications were reporting success while refusing. An instrument that cannot see a failure also cannot see an outage. That is the same defect as the security one, arriving from the other side.
What that does and does not mean
It would be neat to say the earlier letters were wrong. They were not, and the distinction is worth being precise about rather than glossing.
Every one of those four findings was a criticism of the instrument, made using the instrument. Letter K did not claim 505 addresses were the whole population โ it claimed the classifier found 505 of a population it could demonstrate was 964, and named the reason. Letter J did not claim two hosts were the whole condition โ it counted what it examined and said so. Fixing the instrument does not refute those letters. It dates them.
There is exactly one figure I would now write differently, and it is a scope statement rather than a measurement:
Letter J named
lsn-ragflowandlsn-aias the hosts answering invented paths with a 200. The audit that followed found the same condition onlsn-photosโ one 6,903-byte body across 489 distinct paths, larger than either host the letter named โ and onlsn-tautulii. Both had already been closed behind the authentication portal by the time the letter was written, which is why the letter's window and its remediation date are unaffected. But "two services" was the scope I looked at, not the scope that existed. It was four.
That correction is published here rather than quietly amended into Letter J, because a series about measurement error that silently edits its own back catalogue is not measuring anything.
And then the instrument showed something new
The fix to the cohort detector was mechanical: widen a window from 24 hours to 30 days, replace two absolute-zero tests with ratios, and refuse to relabel a scanner as a scraper. Letter K predicted it would recover the 459 addresses that letter's own population was missing.
It did. It also surfaced a second population, unrelated to the first, which nothing in eleven letters had ever counted.
| Distinct addresses | 7,109 |
|---|---|
| Requests | 7,251 |
| Addresses making exactly one request | 6,981 (98.2%) |
Requests carrying a Referer | 0 |
| Distinct paths requested | 68 |
| Window | 2026-06-11 โ 2026-08-11 |
Every one of those 7,251 requests carried the same User-Agent โ a current Chrome 142 on macOS, unremarkable in every way, the single most common string on the internet.
And they were not harvesting anything.
| Path | Requests | Addresses |
|---|---|---|
/threat-intel.html | 4,991 | 4,924 |
/live-feed.html | 1,436 | 1,426 |
/defense.html | 252 | 252 |
/threat-intel/ | 250 | 249 |
/ | 73 | 73 |
/workshop.html | 66 | 66 |
/knowledge.html | 56 | 56 |
/.env | 30 | 14 |
Four thousand nine hundred and twenty-four distinct addresses fetched the same single page, once each.
/threat-intel.html is the dossier index. /live-feed.html is the live feed. Between them they are 88.6% of this population's entire traffic. Nobody read a dossier. Nobody walked the corpus. Seven thousand addresses were spent on the question has the index changed.
The contrast is the finding
Letter K's population and this one use the same technique and are doing opposite things.
| Letter K โ the Nexus 5 | This letter โ the watchers | |
|---|---|---|
| Addresses | 964 | 7,109 |
| Requests | 1,204 | 7,251 |
| Distinct paths taken | 1,069 | 68 |
| Of the corpus | 755 dossier pages โ materially all of it | one index page, 4,991 times |
| Referer | none | none |
| Autonomous systems | 470 | 77 |
| Countries | 80 | 25 |
| Address overlap between them | โ | zero |
Both spend disposable addresses to defeat per-source counting. One does it to take the corpus. The other does it to watch the corpus for change โ and pays roughly six times as many addresses for the privilege of reading a single page.
That is a different economics and therefore a different purpose. Harvesting is a one-off: you take the 755 pages and you are done. Watching is a subscription: you must come back, and every return visit from the same address would be the thing that makes you countable. So you buy a new address each time.
Where they come from
The address supply is also different, and it is the detail that most constrains what this can be.
| Autonomous system | Addresses |
|---|---|
| AS22773 โ Cox Communications | 2,115 |
| AS212238 โ CDNEXT / Datacamp | 1,010 |
| AS3257 โ GTT Communications | 611 |
| AS398781 โ Oculus Networks | 510 |
| AS210906 โ Bite Lietuva | 364 |
| AS203020 โ HostRoyale Technologies | 331 |
Seventy-seven networks, twenty-five countries โ against Letter K's 470 networks and 80 countries. This is a smaller, denser pool, and it is mixed: Cox is a large US residential ISP, Bite is a Lithuanian consumer telco, while CDNEXT/Datacamp, Oculus and HostRoyale are proxy and hosting operations. Two thousand one hundred and fifteen distinct Cox addresses is not a botnet of compromised home routers at that density; it is what a residential proxy vendor's US pool looks like when you draw from it heavily.
The traffic is not evenly spread. It is a campaign:
| Date | Requests | Addresses |
|---|---|---|
| 2026-07-08 | 417 | 416 |
| 2026-07-10 | 693 | 690 |
| 2026-07-11 | 523 | 521 |
| 2026-07-12 | 772 | 772 |
| 2026-07-14 | 936 | 934 |
| 2026-07-15 | 1,105 | 1,105 |
| 2026-07-16 | 592 | 589 |
Look at the last column against the one before it. On 2026-07-15, one thousand one hundred and five requests arrived from one thousand one hundred and five addresses โ a ratio of exactly 1.000. Not approximately. Every address was used once and discarded, all day, at a rate of roughly one every 78 seconds.
Nine days, mid-July, then a taper to a trickle that is still running: two to twelve requests a day through August, the most recent on the day this letter was written.
What it probably is, and what I will not claim
The honest position is that a request for an index page tells you almost nothing about intent, and I have 7,251 of them and one page.
What the shape supports:
This is monitoring, not reading. The 98.2% one-request rate, the absence of any second page, and the concentration on an index and a feed are the signature of change-detection. Something wants to know when this estate publishes.
It is deliberately unattributable, and that is a choice with a cost. A monitoring service that wanted the index could poll it from one address once an hour โ 216 requests over nine days instead of 5,000 addresses, and this estate would have served every one without complaint. Letter C documented four crawlers doing exactly that, unimpeded. Renting a residential proxy pool to read a public index page is expensive, and it buys exactly one thing: nobody can tell it is the same watcher each time.
The /.env tail says the pool is shared. Fourteen of these addresses also requested /.env, thirty times. That is 0.2% of the population and it is almost certainly not the same operator โ it is the same rented address being used by a different customer of the same proxy vendor, which is the ordinary condition of bought infrastructure.
What I will not claim: who, or why. A competitor, a researcher, an aggregator, an automated feed, or somebody who simply wanted to know when their own name appeared here โ the edge log cannot distinguish them, and the country table describes where a proxy vendor's exit nodes are cheap rather than where anyone is sitting.
There is one asymmetry worth noting without over-reading it. Everything this population touches is published deliberately and is free to take. The index it watches announces new dossiers, and this series names real infrastructure and real operators. A watcher that wants early notice of what gets published here, and does not want to be identified as a watcher, is a coherent thing to be โ and so is a boring commercial change-monitor that treats every site the same way. I cannot separate them and am not going to pretend otherwise.
What changes here
Nothing defensive. Seven thousand addresses reading one public page at one request each is not an attack, is not a load problem โ 7,251 requests across 61 days is about five an hour โ and banning residential proxy exits would block real people while costing the operator the price of the next address. The standing decision on distributed low-volume cohorts applies unchanged.
One measurement change. This population and Letter K's are now both labelled distributed_scraper, which is wrong for one of them. A cohort that takes 755 distinct pages and a cohort that takes one page 4,991 times are different behaviours and should not share a label. The distinguishing statistic is already computed: distinct paths per address across the cohort. Harvesters spread; watchers concentrate. That split is worth adding before the label means nothing.
And a standing note on the corpus itself. Two independent operations now spend real money to read this site without being identifiable โ one taking everything, one watching for changes. That is a fact about what a published threat-intelligence corpus attracts, and it belongs in the record even though there is nothing to do about it. The dossiers stay public. That was never conditional on who reads them.
The part that was not fixed
Four defects were found and closed. A fifth thing was found and not closed, and a letter that reported only the repairs would be doing the same flattering arithmetic this series exists to refuse.
Twice now a value has appeared in this estate's ip_intel table that no identifiable code path could have written.
Letter G, the first: asn carrying RIPE Network Coordination Centre / AS16276 for addresses inside Meta's 57.141.0.0/16. A regional registry recorded as an operator, which split one requester into two in every ASN-grouped view and very nearly became a published claim that two unrelated parties shared a bug. The writer was never identified. It was remediated by detection โ a reconciliation script that re-checks stored ASNs against live BGP origin โ rather than by a fix.
Letter I, the second: five .env scanners carrying auth_bruteforce, the most severe authentication verdict this pipeline can issue, while Authelia's own log holds zero credential events for any of them across its entire five-month retention. Hunting that writer excluded every mechanism reachable for testing โ the upstream authentication log, the single writer of the counter it keys on, every inspectable version of the rule back through eight container images and two on-disk backups, every process on this host that touches the column, the rules table, and the absence of any database trigger. None of them can have done it. Something did.
The hunt produced one real finding, which was a latent hole rather than the culprit: the cleanup that removes a label when its rule is deleted refuses to touch reserved classifier intents โ correctly, since clearing them would destroy the classifier's own work โ but nothing stopped a rule from applying one. A guard on the way out with no guard on the way in. Any label created that way would have been permanently unclearable by every reset path in the system, which is precisely the shape of the observed damage. It is closed now. It is not evidence that it happened.
What exists instead is an admission written into the schema. Both investigations dead-ended on the same absence: the table records what it holds and never who put it there. So it now records who โ a trigger capturing the statement text, the database user, the application name, the client address and the backend process id, scoped narrowly to the two shapes that have actually gone unexplained plus every change to the rules table.
It has fired zero times since being armed, which is the expected and uninformative result. It says nothing about the two historical cases and cannot. What it changes is that a third will not begin from nothing.
I would rather end a letter about a repaired instrument on the thing still wrong with it than on the four things fixed. The count of defects this series has found in its own measurement now stands at five: four closed, one open, and the open one is the only one where I cannot tell you what happened.
Method and limits
Single source: the Traefik edge access log, corpus 2026-06-03 โ 2026-08-11, 288,430 requests from 27,049 addresses at the time of writing; the corpus is live, so totals drift upward and every figure here was taken from one snapshot and re-verified against it after the argument was drafted.
The population is defined by exact-match on one User-Agent string. That method's central weakness was stated in Letter K and applies identically here: selecting on a shared string guarantees the group shares it, so the string is not itself evidence of one operator. The evidence is what the group shares beyond the selection: zero referers across all 7,251 requests, a 98.2% one-request rate, a single-page concentration, and a nine-day burst whose request-to-address ratio is 1.000. The weakness is sharper this time than last, because Chrome 142 on macOS is the most common User-Agent on the internet rather than a distinctive stale default โ so this population is certainly contaminated with ordinary human visitors at the edges. The one-request-per-address and zero-referer properties are what exclude them, not the string.
That cuts the other way too: any member of this operation that arrived with a referer, or fetched a second page, is excluded from these figures by the same test. The 7,109 is a floor.
The before/after comparison in the first section is not a controlled experiment. The corpus grew between the two readings and the classify cycle ran repeatedly, so the deltas conflate the fixes with ordinary drift. The four figures quoted are dominated by the fixes โ auth_bruteforce 6โ1 and the app-catchall 0โ5,231 are direct consequences with no plausible drift explanation โ but the distributed_scraper 505โ6,100 includes both the corrected window and two months of accumulated traffic that the old 24-hour window could never have seen at once.
Attribution stops at "two distinct operations, neither identified." Nothing in this letter was produced by contacting, probing, or fetching from any address described.
Confidence: HIGH that this is monitoring rather than harvesting โ the single-page concentration and one-request rate are not reproducible by an organic readership. Confidence: HIGH on the correction figures, which are direct counts. Confidence: MEDIUM that it is one operator rather than several sharing a proxy vendor and a default User-Agent; the burst structure argues for one, the commonness of the string argues against certainty. Confidence: LOW on purpose, which is not recoverable from an index-page request and is not asserted.
The Census, Letter L. Previous: Letter K โ The Nexus 5. The series counts what arrives at one small estate's edge and what the counting gets wrong.