What 86 public x402 endpoints send back
A measurement, not a review. Every number below comes from a script run against stored probe records, and the data it produced is published next to this page, so any row can be checked rather than taken on trust.
What was measured, and how
On 2026-10-27 this box probed a public list of x402 endpoints and stored every
response. The 91 responses that came back as HTTP 402, meaning
the host was actually selling something, deduplicated to one URL per host and path:
86 endpoints on 52 hosts. Each endpoint
was then opened once with product.audit(url), which follows at most
5 hops, takes 3 timed samples, records status, redirect chain, TLS version, cipher,
issuer and expiry, the security headers worth checking, and reads at most 64 KiB
per hop. Each host's DNS was audited with dnsaudit.audit(zone), which
reads A, AAAA, NS, MX, SPF, DMARC, DKIM selectors, CAA and DNSSEC over DNS over
HTTPS. Both detectors are stdlib only, deterministic, and already shipped in the
repository. Hosts were measured one at a time with a 0.4 s gap, a 30 s deadline per
target, and at most one retry, so the run cannot resemble a flood and cannot hang
on a hostile host. No host was ever sent a private, loopback, link-local or
reserved target: the detector resolves the name once, refuses the request if any
answer is non-public, and connects to the address it checked.
Two decisions decide whether the numbers mean anything, so both are stated
here. First, dnsaudit is given the DNS zone, not the
hostname: most endpoints here are subdomains, a subdomain legitimately has no NS
record of its own, and asking for one manufactured a critical finding on 40 of 52
hosts in the first run of this same script, before the fix. The script walks each host up to the first name that answers
NS and audits that name once, so 52 hosts resolve to
46 zones, and 46 of them answered. Second, on a shared
hosting suffix (workers.dev, onrender.com, railway.app) the seller does not control
the zone, so those zones are flagged and kept out of the seller-zone column rather
than counted against the seller. HTTP 402 itself is not a defect, and neither is
405 on a plain GET to a POST-only endpoint or 400 for a GET with no JSON body. Of
the plain GETs sent, 74 answered
402 again, 8 answered 405 and
1 answered 400; those are counted as
expected signals, not as defects. A host that failed is counted as failed, never
as clean.
A finding is a fact about one response, at one moment, from
one vantage point. It is not proof of compromise, not a score, and not an
accusation. A correct finding can also be a deliberate choice: an API that wants
browser clients sets Access-Control-Allow-Origin: * on purpose, and
a name that only sells an endpoint publishes a null MX on purpose. Latency is
measured from a single box in Singapore, so it describes that path and not the
endpoint's best case.
What came back, by final status: 402 on 74, 405 on 8, 200 on 2, no response on 1, 400 on 1. The two 200s were checked against their stored bodies: both served the endpoint's own tool manifest on the GET route, not the paid record, so they are documented descriptors and not a paywall leak. The TLS protocol agreed was TLSv1.3 on 85 of 85. The soonest certificate expiry is 35 days away, and median p50 latency was 559 ms from this box. TLS is not the weak part of this market. The weak parts are the headers an operator sets after the endpoint works, and the DNS records nobody looks at again.
- 86endpoints measured
- 52hosts, 46 DNS zones
- 86endpoints with at least one anomaly
- 36of 36 seller zones had a DNS finding
- 0endpoints where the detector itself failed
The most frequent endpoint misconfigurations
First column counts endpoints, denominator 86. Second counts distinct
hosts, denominator 52, because one seller that publishes many
endpoints can look like a market-wide pattern. Sorted by endpoint count, first ten
shown; the full list is in out/index.json.
| id | endpoints | hosts | mechanism | consequence |
|---|---|---|---|---|
missing_content_security_policy | 75/86 | 46/52 | no Content-Security-Policy header | if a response is ever rendered, nothing constrains what the browser runs |
cors_wildcard | 59/86 | 30/52 | Access-Control-Allow-Origin: * | any page a visitor loads can call the endpoint and read the answer, which is either deliberate or unnoticed |
missing_strict_transport_security | 37/86 | 26/52 | no Strict-Transport-Security header | a first request over http stays downgradable for every later visit |
missing_x_content_type_options | 36/86 | 28/52 | no X-Content-Type-Options header | a browser may sniff a JSON error page as another content type and execute it |
missing_cache_control | 29/86 | 16/52 | no Cache-Control on the final response | an intermediary may store a response that was meant for one caller |
slow_p95 | 8/86 | 6/52 | p95 latency above 1500 ms from one vantage point | a client may time out before the payment is confirmed and retry into a second charge |
server_version_disclosed | 6/86 | 1/52 | the Server header carries a version number | an attacker skips fingerprinting and goes straight to the matching exploit |
missing_content_type | 3/86 | 3/52 | no Content-Type on the final response | a client parses a payment challenge as text and drops it |
tls_error | 1/86 | 1/52 | https requested but no TLS session was established | the endpoint cannot be reached securely at all, so nothing downstream matters |
unreachable | 1/86 | 1/52 | no completed HTTP response to the audit request | a client that cannot get a response cannot be asked to pay, and a buyer reads it as downtime |
DNS and mail findings, counted per zone
A zone is the unit that owns an NS, MX, SPF, CAA or DNSSEC record, so counting per host would count one platform record many times. All zones is the denominator 46; seller zones excludes the 10 zones on a shared hosting suffix, leaving 36 the seller controls. Where the two columns differ, the finding belongs to a hosting platform rather than to the seller.
| id | seller zones | all zones | mechanism | consequence |
|---|---|---|---|---|
no_dnsseclow | 31/36 | 41/46 | the zone is not DNSSEC-signed | a resolver cannot tell a forged answer from a real one |
no_dkim_probeinfo | 31/36 | 40/46 | none of the common DKIM selectors answered | cannot show a signature exists, which is not the same as no signature |
no_caalow | 28/36 | 36/46 | no CAA record | any public CA may issue a certificate for the name |
spf_softfailmedium | 20/36 | 21/46 | SPF ends in ~all | forgeries are marked, not rejected |
no_dmarchigh | 18/36 | 25/46 | no DMARC record | a receiver has no instruction for a message that fails SPF or DKIM |
no_spfhigh | 12/36 | 21/46 | no SPF record | anyone may send mail claiming to be this name |
no_mxhigh | 10/36 | 19/46 | no MX record | mail to this name is undeliverable, so a receipt or a support reply from it is not |
dmarc_no_rualow | 9/36 | 9/46 | DMARC has no rua= address | forgeries happen with nobody receiving the report |
dmarc_p_nonemedium | 8/36 | 10/46 | DMARC policy is p=none | forged mail is reported and still delivered |
spf_neutralhigh | 1/36 | 1/46 | SPF ends in ?all | the record asserts nothing about who may send |
nameservers_share_subnetlow | 1/36 | 2/46 | nameservers resolve into the same /24 | two names, one failure domain |
Every host, one row each
What the endpoint did, then what the zone behind its name says. A row with none means the detector ran and found nothing, never that it was skipped. Rows marked platform zone sit on a shared hosting suffix, where the zone's records are the platform's to set. A host that could not be measured says so.
| host | endpoints | endpoint anomalies | TLS days | p95 ms | zone findings |
|---|---|---|---|---|---|
| 2s.io2s.io | 1/1 | cors_wildcard | 87 | 338 | no_spfdmarc_p_nonedmarc_no_ruano_caano_dnssecno_dkim_probe |
| abr.kloudle.devkloudle.dev | 1/1 | cors_wildcardmissing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 76 | 774 | no_dmarcspf_neutralno_caano_dnssecno_dkim_probe |
| agent-bounty-feed.dailydollar.workers.devdailydollar.workers.dev (platform zone) | 1/1 | cors_wildcardmissing_cache_controlmissing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 86 | 120 | no_dmarcno_mxno_spfno_caano_dnssecno_dkim_probe |
| agent-evidence-api.thx93.workers.devthx93.workers.dev (platform zone) | 1/1 | missing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 54 | 698 | no_dmarcno_mxno_spfno_caano_dnssecno_dkim_probe |
| agent-evidence.thx93.devthx93.dev | 1/1 | missing_content_security_policy | 84 | 678 | spf_softfailno_caa |
| agentbureau-api.datafortress.clouddatafortress.cloud | 1/1 | missing_cache_controlmissing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 87 | 736 | dmarc_p_nonespf_softfaildmarc_no_ruano_dnssecno_dkim_probe |
| agentshare.devagentshare.dev | 1/1 | missing_cache_controlmissing_content_security_policymissing_strict_transport_security | 38 | 141 | no_dmarcspf_softfailno_caano_dnssecno_dkim_probe |
| alphapipeline-eu.onrender.comonrender.com (platform zone) | 2/2 | missing_content_security_policy x2missing_strict_transport_security x2missing_x_content_type_options x2 | 54 | 642 | no_mxno_spfdmarc_p_noneno_dnssecno_dkim_probe |
| api-staging.aomi.devaomi.dev | 1/1 | cors_wildcardmissing_content_security_policyslow_p95 | 51 | 2819 | spf_softfailno_caano_dnssecno_dkim_probe |
| api.agents-trust.comagents-trust.com | 1/1 | missing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 37 | 295 | no_dmarcspf_softfailno_caano_dnssecno_dkim_probe |
| api.babyblueviper.combabyblueviper.com | 2/2 | missing_cache_control x2 | 49 | 708 | no_mxno_spfno_caano_dnssecno_dkim_probe |
| api.chit402.comchit402.com | 1/1 | missing_cache_controlmissing_content_security_policymissing_strict_transport_security | 36 | 901 | no_dmarcspf_softfailno_caano_dnssecno_dkim_probe |
| api.lumitrades.iolumitrades.io | 2/2 | cors_wildcard x2missing_content_security_policy x2missing_strict_transport_security x2missing_x_content_type_options x2slow_p95 x2 | 85 | 2750 | no_caano_dnssecno_dkim_probe |
| api.priors.tradepriors.trade | 1/1 | cors_wildcardmissing_content_security_policy | 58 | 615 | spf_softfaildmarc_no_ruano_caano_dnssecno_dkim_probe |
| api.wayleave.devwayleave.dev | 1/1 | cors_wildcardmissing_content_security_policy | 57 | 284 | spf_softfailno_caano_dnssec |
| api.wsystem.devwsystem.dev | 2/2 | missing_cache_control x2 | 80 | 622 | dmarc_p_nonespf_softfailno_caano_dnssecno_dkim_probe |
| api.xona-agent.comxona-agent.com | 1/1 | missing_cache_control | 35 | 121 | dmarc_p_nonespf_softfaildmarc_no_ruano_caano_dnssecno_dkim_probe |
| api.xynaptic.ioxynaptic.io | 5/5 | missing_cache_control x5missing_content_security_policy x5missing_x_content_type_options x5cors_wildcard x4slow_p95 | 54 | 2132 | no_dmarcspf_softfailno_caano_dnssecno_dkim_probe |
| beliefstate.aibeliefstate.ai | 1/1 | cors_wildcardmissing_content_security_policymissing_x_content_type_optionsslow_p95 | 43 | 2200 | dmarc_no_ruano_caano_dkim_probe |
| bridge-api.argosbot.ioargosbot.io | 1/1 | missing_content_security_policy | 43 | 520 | no_dmarcno_mxno_spfno_dnssecno_dkim_probe |
| canaryguard-402.onrender.comonrender.com (platform zone) | 1/1 | cors_wildcardmissing_content_security_policy | 54 | 763 | no_mxno_spfdmarc_p_noneno_dnssecno_dkim_probe |
| fresh402.kirilllabs.workers.devkirilllabs.workers.dev (platform zone) | 1/1 | missing_content_security_policymissing_strict_transport_security | 61 | 685 | no_dmarcno_mxno_spfno_caano_dnssecno_dkim_probe |
| gethirepulse.xyzgethirepulse.xyz | 2/2 | cors_wildcard x2missing_content_security_policy x2missing_strict_transport_security x2 | 81 | 469 | no_dmarcspf_softfailno_caano_dnssecno_dkim_probe |
| getskavio.comgetskavio.com | 1/1 | cors_wildcardmissing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 88 | 835 | dmarc_p_nonespf_softfaildmarc_no_ruano_caano_dnssecno_dkim_probe |
| grokbot-dashboard.a3migos.workers.deva3migos.workers.dev (platform zone) | 1/1 | cors_wildcardmissing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 81 | 659 | no_dmarcno_mxno_spfno_caano_dnssecno_dkim_probe |
| hcrb.inhcrb.in | 1/1 | cors_wildcardmissing_content_security_policy | 87 | 363 | no_dmarcspf_softfailno_caano_dnssecno_dkim_probe |
| inference.bsvkey.combsvkey.com | 1/1 | missing_content_security_policy | 88 | 1480 | no_dmarcno_mxno_spfnameservers_share_subnetno_dnssecno_dkim_probe |
| kari.mayim-mayim.commayim-mayim.com | 1/1 | cors_wildcardmissing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 78 | 324 | spf_softfaildmarc_no_ruano_caano_dnssecno_dkim_probe |
| keplerops--ddb76fd4cf5411f1be831607ee4eb77e.web.val.runval.run (platform zone) | 1/1 | cors_wildcardmissing_content_security_policy | 45 | 587 | no_mxno_spfdmarc_p_noneno_caano_dnssecno_dkim_probe |
| keyring-agent.blockchhub.linkblockchhub.link | 1/1 | cors_wildcardmissing_cache_controlmissing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 68 | 262 | no_mxdmarc_no_ruano_caano_dnssec |
| lightningfaucet.comlightningfaucet.com | 3/3 | cors_wildcard x3 | 65 | 722 | spf_softfail |
| m2mfreedom.comm2mfreedom.com | 7/7 | missing_cache_control x7cors_wildcard x6missing_content_security_policy x6missing_strict_transport_security x6server_version_disclosed x6missing_content_typeslow_p95tls_errorunreachable | 81 | 1933 | no_dmarcno_mxno_spfno_caano_dnssecno_dkim_probe |
| mezo.ochinimus.appochinimus.app | 1/1 | cors_wildcardmissing_content_security_policymissing_x_content_type_options | 74 | 586 | no_dmarcno_mxno_spfno_caano_dnssecno_dkim_probe |
| pay.paidwithtab.compaidwithtab.com | 2/2 | cors_wildcard x2missing_cache_control x2missing_content_security_policy x2missing_strict_transport_security x2missing_x_content_type_options x2 | 45 | 1081 | dmarc_p_nonespf_softfailno_caano_dnssecno_dkim_probe |
| practical-ambition-production.up.railway.apprailway.app (platform zone) | 1/1 | missing_cache_controlmissing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 59 | 265 | spf_softfailnameservers_share_subnetno_dnssec |
| rugshield-402.onrender.comonrender.com (platform zone) | 1/1 | cors_wildcardmissing_cache_controlmissing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 54 | 682 | no_mxno_spfdmarc_p_noneno_dnssecno_dkim_probe |
| sandbox.node4all.comnode4all.com | 1/1 | cors_wildcardmissing_content_security_policymissing_x_content_type_options | 74 | 353 | no_dmarcno_spfno_dnssecno_dkim_probe |
| scrapeagent.xyzscrapeagent.xyz | 1/1 | cors_wildcardmissing_content_security_policymissing_x_content_type_options | 39 | 329 | no_dmarcno_mxno_spfno_dnssecno_dkim_probe |
| stableenrich.devstableenrich.dev | 1/1 | missing_content_security_policymissing_content_typemissing_x_content_type_options | 86 | 342 | no_dmarcno_mxno_spfno_dnssecno_dkim_probe |
| three.wsthree.ws | 1/1 | cors_wildcard | 85 | 1025 | no_dmarcno_spfno_caa |
| tokensafe.x402api.workers.devx402api.workers.dev (platform zone) | 1/1 | missing_cache_controlmissing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 68 | 184 | no_dmarcno_mxno_spfno_caano_dnssecno_dkim_probe |
| travel.hanibal-ai.comhanibal-ai.com | 1/1 | missing_content_security_policy | 85 | 873 | no_dmarcno_mxno_spfno_caano_dnssecno_dkim_probe |
| verified-catalog-lookup.withgrokbot.workers.devwithgrokbot.workers.dev (platform zone) | 2/2 | cors_wildcard x2missing_content_security_policy x2missing_strict_transport_security x2missing_x_content_type_options x2 | 63 | 193 | no_dmarcno_mxno_spfno_caano_dnssecno_dkim_probe |
| vm5-openapi-x402.onrender.comonrender.com (platform zone) | 2/2 | cors_wildcard x2missing_content_security_policy x2missing_strict_transport_security x2 | 54 | 631 | no_mxno_spfdmarc_p_noneno_dnssecno_dkim_probe |
| x402-bounty-radar.nikolas-sapalidis.workers.devnikolas-sapalidis.workers.dev (platform zone) | 1/1 | missing_cache_controlmissing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 90 | 709 | no_dmarcno_mxno_spfno_caano_dnssecno_dkim_probe |
| x402-seller-m8nx.onrender.comonrender.com (platform zone) | 1/1 | missing_cache_controlmissing_content_security_policymissing_content_typemissing_strict_transport_securitymissing_x_content_type_options | 54 | 79 | no_mxno_spfdmarc_p_noneno_dnssecno_dkim_probe |
| x402-seller-pmlm.onrender.comonrender.com (platform zone) | 1/1 | cors_wildcardmissing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 54 | 872 | no_mxno_spfdmarc_p_noneno_dnssecno_dkim_probe |
| x402.gno.devgno.dev | 1/1 | missing_content_security_policymissing_strict_transport_securitymissing_x_content_type_options | 90 | 703 | no_dmarcno_mxno_spfno_caano_dnssecno_dkim_probe |
| x402.ochinimus.appochinimus.app | 1/1 | missing_content_security_policymissing_x_content_type_options | 74 | 1176 | no_dmarcno_mxno_spfno_caano_dnssecno_dkim_probe |
| x402.tbs-digital.comtbs-digital.com | 1/1 | cors_wildcardmissing_content_security_policy | 82 | 874 | dmarc_p_nonespf_softfaildmarc_no_ruano_caano_dnssecno_dkim_probe |
| x402.workfern.comworkfern.com | 1/1 | missing_content_security_policymissing_x_content_type_options | 86 | 363 | no_dmarcspf_softfailno_caano_dnssecno_dkim_probe |
| yruz.oneyruz.one | 15/15 | cors_wildcard x15missing_content_security_policy x15slow_p95 x2 | 62 | 3592 | dmarc_p_nonespf_softfailno_dkim_probe |
Reproducing this
The raw output is published as x402-hygiene-data.json: every endpoint, response status, header, certificate, latency sample and DNS finding behind the tables above. That file is the evidence; the tables are a view of it. No key, no account and no paid API call is involved in producing either.
cd research/zero-capital/money/x402-hygiene-2026-10-27 python3 build.py # stored 402 records -> out/index.json python3 render.py # out/index.json -> this page
The script that writes the file lives in the working repository and is available on request; the data is the part that makes the claims checkable, so it is the part that is published. 737 stored records were read, 737 parsed, 91 at HTTP 402, 5 duplicates collapsed on host and path. Nothing is re-probed from the wider discovered surface, so a rerun is cheap and comparable to this one, and any single host can be measured alone by calling the same two functions.