Blog · Supply chain
A spec-valid SupplyChain hop can still be pooled inventory. ads.txt certifies the seller ID, not the site.
Buyers built a three-file trust stack for a reason: ads.txt says who may sell a domain, sellers.json says who that account is, and the SupplyChain object names the hops on this request. Dark pooling is the case where all three agree and the inventory is still not the site you thought you bought. The files certify a seller ID. They do not certify that the ID is used by only one property, or by properties under one owner.
What the metric actually measures
Pooling, in the ordinary sense, is allowed. Two sites under one publisher sharing a DIRECT account is how a network runs ads.txt without minting a new seller ID per subdomain. Dark pooling is the industry term for the other case: organizationally unrelated domains, often of different reputation, listing the same DIRECT identifier. Payment after the auction goes to the owner of that seller ID. The bid request can still name a domain the buyer would never clear.
Vekaria, Nithyanand, and Shafiq spelled the pass condition at IEEE S&P 2024. A low-quality site copies a vetted publisher's seller ID into its ads.txt as DIRECT. The exchange's sellers.json still lists that ID. Every basic supply-chain check succeeds, because the ID is real. Invalidating every shared ID would also kill legitimate subsidiaries. The remaining work (are these properties related, did the exchange actually vet this domain) is not in the three files.
Papadogiannakis, Kourtellis, Papadopoulos, and Markatos crawled more than 7 million Tranco domains in February 2023 for WWW 2025. They fetched ads.txt from 456,971 domains and extracted 81,985,768 valid entries, including 591,546 distinct DIRECT publisher identifiers. They treat a DIRECT ID as pooled when more than one website uses it, then ask which of those pools mix unrelated properties. That is a file census, not a live bidstream. It is still the right population for the authorization claim, because the claim lives in those files.
The pools that contain objectionable sites are not small
Across all DIRECT pools they measured, the median size is 4 sites and the mean is about 122. That mean is a long tail of large networks, not a typical publisher. Pools that contain at least one misinformation site, using MediaBias/FactCheck labels, have a median of 336.5 and a mean of about 2,975. Pools that contain at least one piracy site, using NextDNS torrent and warez lists, have a median of 645 and a mean of about 4,915. They report that earlier dark-pool size estimates, including the S&P 2024 crawl, were low by a factor of 15 once the census is this wide and restricted to DIRECT IDs.
Ninety-two percent of sites that served an ads.txt file listed at least one Google DIRECT publisher ID. Popular networks are where shared IDs concentrate, which is also where a buyer's allowlist is most likely to treat the ID as a quality signal. The WWW paper estimates that identifier pooling lets bad actors absorb thousands of dollars from the ecosystem; it does not publish a global dollar total. Treat that as direction, not a TAM.
They also found 30 ad resellers that list themselves as content owners in other networks. Some of those resellers work with almost 200 objectionable or illegal sites, and that pattern held across a seven-month window. That is a different abuse (intermediary as publisher) sitting next to pooling. Both survive a hop check that only asks whether asi and sid appear in sellers.json.
What a bid request can and cannot prove
OpenRTB will carry site.domain or app.bundle, source.schain, and often a publisher ID the exchange minted. A linter can decide the structural questions: required fields, complete, adjacent duplicate nodes, hp in range, payment hops present in a local ads.txt and sellers.json cache. RTBlint does that with --resolve --cache. It is a real check. It is also exactly the check the pooled site is designed to pass.
site.domain the page the buyer thinks they bought publisher.id exchange account, often the pooled seller ID source.schain.nodes asi + sid for each payment hop ads.txt domain, seller ID, DIRECT | RESELLER sellers.json seller_id, seller_type, domain (or confidential)
None of those rows answers: how many other domains list this DIRECT ID, and are they under the same owner? Confidential sellers.json entries make even the domain lookup fail closed or fail open, depending on your policy. A complete chain with hp=1 on every node is a disclosure of money hops. It is not a census of the ID.
SupplyChain v1.1 adds custody nodes with hp=0. That is a different transparency problem (who touched the request). It does not fix pooling. A pooled DIRECT ID still sits on a payment node. See the v1.1 hop note for what hp=0 changes, and do not fold that into this one.
What to do
- Keep the hop check. Reject requests whose payment nodes are absent from ads.txt or sellers.json. That still kills fabricated IDs and unauthorized resellers. It is not optional because pooling exists.
- Count domains per DIRECT ID, off the bid request. Crawl ads.txt for the seller IDs you actually buy. A median-4 pool is a network. A median-336 pool that includes a misinformation label is a different object. The WWW crawl is the method; your allowlist is the population that matters.
- Do not treat Google (or any dominant) DIRECT as a brand-safety proxy. 92% of ads.txt sites in that crawl already have one. The ID is common by construction.
- When sellers.json marks the account confidential, decide whether you bid. The file cannot name the property. Passing the hop is passing a redacted hop.
- Split
site.domain/app.bundlefrom the seller ID in reporting. If the domain you paid for never appears in the ID's ads.txt cluster, the authorization files and the inventory claim have diverged.
Paste a bid request into the tester, or run the CLI with a local ads.txt and sellers.json cache. Field context is in the supply chain reference and the trust stack guide. RTBlint is independent of IAB Tech Lab and of the papers cited here. It does not detect fraud, IVT, or whether two domains share an owner. It detects malformed or unauthorized hops. Owner-graph and pool-size checks are a different job, and they are the job dark pooling actually requires.
Sources
- Vekaria, Nithyanand, Shafiq. The Inventory is Dark and Full of Misinformation. IEEE S&P 2024. arXiv:2210.06654. Mechanism: shared seller ID passes ads.txt and sellers.json; 669 misinformation sites in the labeled set.
- Papadogiannakis, Kourtellis, Papadopoulos, Markatos. Welcome to the Dark Side. WWW 2025. arXiv:2306.08418. 7M+ domains, 456,971 ads.txt files, DIRECT pool-size medians, 15× revision of prior pool size, 30 reseller-as-publisher cases.
- IAB Tech Lab ads.txt and sellers.json specifications. What DIRECT and the seller ID are defined to mean.