lncrawl-scraper 1.1.0 · 2026-07-30 16:45 +04

Live verification against real Cloudflare-protected sites

Every code path in the scraper, exercised against production Cloudflare deployments rather than fixtures — the transport group, the diagnosis classifier, the escalation ladder, a real browser solve, the archive tier, and a live tor-pool. 28 of 31 scenarios pass. A stubbed transport can confirm that the code does what it says; only this can confirm that what it says is true of a real server.

28/31
scenarios passed
108
assertions verified live
0 failed
315
hosts probed
163 behind Cloudflare

The corpus

Every base URL in lncrawl's source index was probed twice — once with a plain requests session, once with the impersonating transport — and each response classified by the library's own diagnosis. That pairing is the measurement: the only difference between the two requests is the network signature.

315
hosts probed
163
behind Cloudflare
35
refused a plain client, served the impersonated one

What fronts these hosts

EdgeHosts
Cloudflare159
nginx46
cowboy30
unreachable20
apache15
DDoS-Guard6
unknown6
tengine5
litespeed4
caddy4

Through a Tor exit

Of 45 Cloudflare hosts reached through the local tor-pool: 33 served outright, 8 challenged, 0 reputation-blocked.

A negative result worth keeping: the reputation layer is not uniformly hostile to Tor on this corpus. The model treats a Tor exit as clearing nothing at layer 1, which is conservative rather than measured — and the consequence is that a browser solver buys more here than a residential proxy would.

Which detection layer each client meets Hosts, out of 315 probed. Lower is better — a layer met is a layer that has to be answered.
plain requests impersonated transport
L9 Managed JavaScript challenge
41
24
L8 Per-zone behavioural model
19
18
L6 Browser and JavaScript fingerprint
11
14
L11 Bot Fight Mode
17
0
L12 Super Bot Fight Mode
1
6
L15 Operator edge code
4
0
L10 Turnstile
0
1
L19 Identity-provider gate
1
0

Reading the chart: the impersonated client meets the managed challenge on far fewer hosts, and meets the lighter scoring tiers less often — those are the layers a network signature answers. It meets the behavioural layer more often, which is not a regression: that is this session's own request volume against the same hosts being rate limited, and it is the one layer no client-side change addresses.

Scenarios

Each one names the layer it exercises and what a pass actually proves — "it returned 200" is not evidence about a detection layer on its own. Expand any row for the individual assertions and the values observed.

Transport — layers 2–5

pass S01 A plain client is refused where an impersonated one is served L2L3L4L5 8.31s

What a pass proves. Layers 2-5 are one barrier: the only difference between these two requests is the network signature, and it decides the outcome.

against looked up from the last probe
  • ·hosts presenting the condition todayhttps://novelfull.com/, https://novelfull.net/
  • https://novelfull.com/ — plain refused, impersonated servedplain=403 impersonated=200 (52587 bytes)
  • https://novelfull.net/ — plain refused, impersonated servedplain=403 impersonated=200 (103290 bytes)
  • the profile sends a browser User-Agent we never wroteMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
  • no Python client string is presentMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
  • ·header set the profile emittedAccept, Accept-Encoding, Accept-Language, Host, Priority, Sec-Ch-Ua, Sec-Ch-Ua-Mobile, Sec-Ch-Ua-Platform, Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site, Sec-Fetch-User, User-Agent, Via, X-Forwarded-For, X-Forwarded-Port, X-Forwarded-Proto, X-Forwarded-Ssl, X-Request-Start
pass S02 A pinned old profile is flagged; a family alias is not L3 0.0s

What a pass proves. A stale impersonation profile predates the post-quantum key share current builds send, so pinning one contradicts the User-Agent it claims.

  • the bare alias is accepted silently
  • a two-year-old pin is flaggedimpersonation target 'chrome99' is older than the available 'chrome136'. A stale profile is itself a signal: use the bare 'chrome' alias so the fingerprint tracks the newest supported build.
pass S03 A Cloudflare-fronted page is retrieved and parsed L2-L5L11L12 3.28s

What a pass proves. The baseline tier handles a real protected site end to end, including the soup, JSON and file helpers.

against https://novelfull.net/
  • a page came back with a titleRead free English translated Light Novel - NovelFull
  • the tier used was the cheapest one
  • nothing was recorded as binding
  • links were extracted139 followable
  • get_file wrote the body103290 bytes
  • ·explain()novelfull.net binding layer : nothing has blocked yet tier : direct pacing : 1.2s mean interval requests : 41 ok / 0 failed clearance : none ladder : direct(10) exits : direct

Diagnosis

pass S05 A challenge served with a 403 is diagnosed as a challenge L9L10 5.31s

What a pass proves. The status code says 'forbidden' and the correct remedy is a browser, not a new address. A conventional client rotates its proxy here and gets nowhere.

against https://centralnovel.com/
  • https://centralnovel.com/ -> L9 Managed JavaScript challengeHTTP 403 diagnosed solve (L9 Managed JavaScript challenge): challenge served with 403
  • https://centralnovel.com/ asks for a solve, not a rotation
  • https://ranobes.top/ -> L10 TurnstileHTTP 200 diagnosed solve (L10 Turnstile): challenge served with a success status
  • https://ranobes.top/ asks for a solve, not a rotation
pass S06 A challenge with no solver configured stops and names what is missing L9 1.5s

What a pass proves. The failure is actionable: it names the layer and the capability that would reach it, instead of exhausting retries on a 403.

against https://centralnovel.com/
  • stopped at the challenge layerL9 Managed JavaScript challenge
  • the message names the missing capabilityL9 Managed JavaScript challenge is beyond every configured tier (direct is the strongest). Configure a browser solver. [stop: L9 Managed JavaScript challenge is beyond every configured tier (direct is the strongest). Configure a browser solver.]
pass S07 A host scored as automated escalates rather than rotating L12 0.66s

What a pass proves. Nothing distinguishes the scoring tiers from outside, so the diagnosis names the strictest emit-only one and asks for a stronger tier — not a new address.

against https://novelmania.com.br/
  • diagnosed as scoring rather than reputationescalate (L12 Super Bot Fight Mode): scored as automated
  • the action is to escalate, not rotate
inconclusive S08 An identity-provider gate raises immediately and is never retried L19 0.0s

What a pass proves. The layer reads a secret. Retrying is an infinite loop against a wall, so a single request is spent and the message names the only legitimate route.

no host in the last probe is behind an identity-provider gate

    pass S09 Synthetic statuses are each diagnosed correctly, live L1L7L8L19 5.96s

    What a pass proves. The classifier is exercised against responses a real server produced, not fixtures.

    against https://httpbingo.org
    • HTTP 429: a throttle is a pacing problem-> backoff (L8 Per-zone behavioural model): rate limited
    • HTTP 503: a plain outage is worth one more try-> retry: origin unavailable
    • HTTP 401: authentication has no bypass-> refuse (L19 Identity-provider gate): authentication required (HTTP 401)
    • HTTP 404: the site's answer about a path is not a layer-> accept: HTTP 404
    • HTTP 502: an upstream error is transient-> retry: upstream error (HTTP 502)
    pass S24 A 404 is returned rather than blamed on a layer - 1.23s

    What a pass proves. The site's answer about a path says nothing about the client. Attributing it to a layer would retire a healthy address over a typo in a URL.

    against https://novelfull.net/
    • a 4xx came back as a valueHTTP 404
    • nothing was recorded as bindingNone
    pass S25 Every layer the corpus actually produces is diagnosed, and impersonation measurably reduces challenges L8L9L10L12L13L15L19 0.0s

    What a pass proves. The population-level result: what 501 real hosts do today, and what the transport profile is worth measured across all of them rather than anecdotally.

    against 501 hosts from lncrawl's source index
    • ·hosts probed315
    • ·reachable295
    • ·Cloudflare-fronted159
    • ·layers seen by a plain client{'L11 Bot Fight Mode': 17, 'L12 Super Bot Fight Mode': 1, 'L15 Operator edge code': 4, 'L19 Identity-provider gate': 1, 'L6 Browser and JavaScript fingerprint': 11, 'L8 Per-zone behavioural model': 19, 'L9 Managed JavaScript challenge': 41}
    • ·layers seen by the impersonated client{'L10 Turnstile': 1, 'L12 Super Bot Fight Mode': 6, 'L6 Browser and JavaScript fingerprint': 14, 'L8 Per-zone behavioural model': 18, 'L9 Managed JavaScript challenge': 24}
    • impersonation converts refusals into content on real hosts37 hosts
    • and reduces the number of hosts that challenge at all41 -> 25 challenged hosts
    • at least four distinct layers were exercised by real trafficL10 Turnstile, L12 Super Bot Fight Mode, L6 Browser and JavaScript fingerprint, L8 Per-zone behavioural model, L9 Managed JavaScript challenge
    • ·reputation blocks (L1) observed: 0 of 315none
    • the reputation layer is rare here, so a browser buys more than a proxy would0 hosts
    pass S31 A non-Cloudflare edge is named, and naming it does not break the page L12L14 8.64s

    What a pass proves. The classifier knows the rest of the mitigation market, and identification alone never turns a host that serves content into a refusal.

    • ·https://renovels.org/ answered 200DDoS-Guard
    • https://renovels.org/ is still served, not refusedHTTP 200
    • ·https://ranobes.net/ did not serveExhausted: L9 Managed JavaScript challenge for https://ranobes.net/: L9 Managed JavaScript challenge is beyond every configured tier (direct is the strongest). Configure a browser solver. [stop: L9 Managed JavaScript challenge is beyond every configured tier (direct is the strongest). Configure a browser solver.]
    • ·https://webnovelonline.com/ answered 200Fastly
    • https://webnovelonline.com/ is still served, not refusedHTTP 200
    • ·https://tl.rulate.ru/ answered 200DDoS-Guard
    • https://tl.rulate.ru/ is still served, not refusedHTTP 200
    • ·https://ranobelib.me/ answered 200DDoS-Guard
    • https://ranobelib.me/ is still served, not refusedHTTP 200
    • the edge was named for at least one host4/5

    Behaviour — layer 8

    pass S04 Warm-up and the referrer chain are visible on the wire L8 2.46s

    What a pass proves. A deep page arriving with no referrer and no prior history is a navigation pattern no person produces; both mechanisms are observable in the requests actually sent.

    against https://httpbingo.org
    • ·a first request's headersAccept, Accept-Encoding, Accept-Language, Host, Priority, Referer, Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site, Sec-Fetch-User, Te, User-Agent, Via, X-Forwarded-For, X-Forwarded-Port, X-Forwarded-Proto, X-Forwarded-Ssl, X-Request-Start
    • the first navigation cites the origin's front pagehttps://httpbingo.org/
    • and sec-fetch-site agrees with itsame-origin
    • the next request cites the page before ithttps://httpbingo.org/html
    • fetch metadata says same-originsame-origin
    • a cold deep page wants a homepage visit firsthttps://example.com/
    pass S10 A throttle widens the interval and keeps the address L8 3.42s

    What a pass proves. The rule that matters most: a 429 says the address works and is being asked for too much, so the remedy is arithmetic — not a new exit, which would reset the history the layer measures.

    against https://httpbingo.org
    • gave up at the behavioural layer, not at reputationL8 Per-zone behavioural model
    • the trail shows a backoff and no rotationgave up after 2 attempts; rate limited [backoff -> direct after 1.0s: rate limited | stop: gave up after 2 attempts; rate limited]
    • the interval widened1.0 -> 2.0
    • the address was NOT rotateddirect#httpbingo.org == direct#httpbingo.org
    pass S16 A throttle through Tor still does not rotate L8 6.58s

    What a pass proves. The possess-side veto holds even when a rotation is cheaply available: discarding the address would reset the accumulated history the layer reads.

    against https://httpbingo.org
    • gave up at the behavioural layer
    • no rotation appears in the trailgave up after 2 attempts; rate limited [backoff -> direct after 1.0s: rate limited | stop: gave up after 2 attempts; rate limited]
    • the Tor session was kept even though rotating was available127.0.0.1:9250#s-37eba7bdba7b
    • the interval widened instead1.0
    pass S20 What was learned survives the process L8 0.96s

    What a pass proves. A process that forgets cannot accumulate, and the behavioural layer reads exactly what accumulates. The binding layer is the most valuable thing to keep.

    against https://centralnovel.com/
    • ·first run concludedbinding=L9 Managed JavaScript challenge failures=1
    • a fresh scraper starts from the conclusionL9 Managed JavaScript challenge
    • the ledger came back1
    • ·the tier it would now start withdirect
    • the store is a real file
    • written owner-only, since it holds clearance cookies600
    pass S21 Two scrapers on one host share one identity L8 2.74s

    What a pass proves. Separate state would present as two visitors who contradict each other, arriving in bursts, one of them always cold.

    against https://httpbingo.org
    • the second scraper sees the first's history1
    • both hold the same address
    • both use the same pacing clock
    • the referrer chain is sharedhttps://httpbingo.org/html

    Addresses and tor-pool — layer 1

    pass S11 Traffic leaves through a tor-pool exit L1 4.5s

    What a pass proves. The pool is wired end to end: the session key becomes the SOCKS username, the credential travels as its password, and the egress IP is a Tor exit.

    against https://check.torproject.org/api/ip
    • ·this machine's own address91.73.67.32 (IsTor=False)
    • ·lease127.0.0.1:9250#s-2704a35aaf37 via socks5h://s-2704a35aaf37:tp_auth_disabled@127.0.0.1:9250
    • egress is a Tor exit{'IsTor': True, 'IP': '166.70.207.2'}
    • the exit differs from the local address
    • ·pool instances[{'id': 0, 'exit_ip': '104.244.73.190', 'country': 'LU', 'score': 0, 'state': 'healthy', 'kinds': {}}, {'id': 1, 'exit_ip': '185.220.101.14', 'country': 'DE', 'score': 0, 'state': 'healthy', 'kinds': {}}, {'id': 2, 'exit_ip': '192.42.116.45', 'country': 'NL', 'score': 0, 'state': 'healthy', 'kinds': {}}, {'id': 3, 'exit_ip': '166.70.207.2', 'country': 'US', 'score': 0, 'state': 'healthy', 'kinds'…
    pass S12 A session stays pinned to one exit across requests L1L8 19.46s

    What a pass proves. Stickiness is what makes a clearance reusable and lets per-zone history accrue. A rotating address would invalidate both.

    against https://check.torproject.org/api/ip
    • all four requests left from one exit166.70.207.2, 166.70.207.2, 166.70.207.2, 166.70.207.2
    • ·exit IP166.70.207.2
    pass S13 Rotating moves the session to a different exit L1 3.51s

    What a pass proves. Rotation is a reassignment inside the pool: the endpoint URL is unchanged, but the address behind it — and therefore the identity — is not.

    against https://check.torproject.org/api/ip
    • the endpoint URL is unchangedsocks5h://127.0.0.1:9250
    • the exit identifier changed127.0.0.1:9250#s-05f9ecc59bc9 -> 127.0.0.1:9250#s-f09cbea7cad4
    • the session key changed
    • ·exit IP before/after185.220.100.253 -> 185.220.100.253
    • egress is still Tor
    pass S14 A failure report reaches the pool with the kind derived from the layer L1L9 18.38s

    What a pass proves. This is the only signal that catches a soft block — a proxy relaying bytes cannot see a 403 or a captcha inside an HTTPS tunnel — and the pool weighs a report by its kind.

    against http://127.0.0.1:8080
    • L9 Managed JavaScript challenge -> 'captcha'
    • L1 IP reputation -> 'blocked'
    • L8 Per-zone behavioural model -> 'rate_limited'
    • None -> 'transport'
    • exactly one instance was told it hit a captchabefore={0: 0, 1: 0, 2: 0, 3: 0, 4: 0} after={0: 0, 1: 0, 2: 0, 3: 1, 4: 0}
    pass S15 Rotating between published ranges is refused, against live pool state L1 0.0s

    What a pass proves. THE headline rule. Every Tor exit is on the same published lists, so a reputation block cannot be fixed by another one — and the decision is driven by what the running pool actually offers, not by a hardcoded assumption.

    against http://127.0.0.1:8080
    • ·live pool offerstor, clearing layers []
    • a Tor pool clears nothing at layer 1
    • the planner refuses to rotateMove.STOP
    • and names the address kind as the constraintno configured exit clears the reputation layer — datacenter and Tor ranges are published, so rotating between them cannot help. A residential or mobile-carrier exit is the only thing that moves this layer
    • with a residential exit it does rotateMove.ROTATE
    pass S26 The reputation layer is not uniformly hostile to Tor L1 0.0s

    What a pass proves. A negative result worth recording: assuming every Cloudflare host refuses Tor would make the address strategy look more important than it is on this corpus.

    against 45 Cloudflare hosts via tor-pool
    • ·hosts probed through a Tor exit45
    • most were served outright33/45 served
    • ·challenged instead8/45
    • none produced a reputation block0 found
    • ·consequenceon this corpus the binding layer is the managed challenge, not the address — so a browser solver buys more than a residential proxy would.
    inconclusive S28 A real ASN ban is diagnosed as reputation and stops without wasting addresses L1 1.79s

    What a pass proves. The naturally-occurring case: this host bans the machine's whole ASN, so no client change of any kind can help. With no alternative address the stop is immediate rather than after spending the rotation budget on the same address.

    against https://www.readwn.com/

    the host is not banning this network right now: accept

    • ·observedaccept

    The ladder

    pass S17 A page is served from the archive with the original URL L0 49.74s

    What a pass proves. The cheapest way past a protected site is not to touch it. The response must carry the real URL, or relative links redirect the whole crawl into the snapshot.

    against https://centralnovel.com/
    • the archive has captures5 found
    • ·newest captures20260206124734, 20260524171405, 20260702085650
    • a snapshot came back210533 bytes
    • the response carries the ORIGINAL url, not the archive'shttps://centralnovel.com/
    • the capture timestamp is reported20260702085650
    • ·this is a host the live stack refuseshttps://centralnovel.com/ serves a challenge to the direct tier (see S05)
    pass S23 The ladder escalates on evidence and settles on the cheapest tier that works L9L14 31.1s

    What a pass proves. The planner walks up only as far as required, and the archive rescues a host the live stack refuses.

    against https://centralnovel.com/
    • ·configured ladderarchive(0) -> direct(10)
    • the challenged host was retrievedHTTP 200, 210533 bytes
    • via the archive, which the planner reached firstarchive
    • ·explain()centralnovel.com binding layer : nothing has blocked yet tier : archive pacing : 1.2s mean interval requests : 1 ok / 0 failed clearance : none ladder : archive(0) direct(10) exits : direct
    pass S27 A real browser solves a real challenge, then the cheap tier reuses it L6L7L9L10 18.28s

    What a pass proves. solve-once-and-reuse: the expensive tier runs once and the clearance is replayed on the identity that earned it, so later pages cost one HTTP request.

    against https://centralnovel.com/
    • ·direct tier against https://www.webnovel.com/{'status': 200, 'action': 'accept', 'layer': None}
    • ·direct tier against https://m.webnovel.com/{'status': 200, 'action': 'accept', 'layer': None}
    • ·direct tier against https://centralnovel.com/{'status': 403, 'action': 'solve', 'layer': 'L9 Managed JavaScript challenge'}
    • ·target chosenhttps://centralnovel.com/
    • ·ladderdirect(10) -> clearance(100)
    • the challenged host was retrievedHTTP 200, 210943 bytes
    • the browser ran exactly once1 solve(s)
    • the clearance tier is what workedclearance
    • a clearance was stored
    • ·clearance cookies['cf_clearance']
    • ·bound to User-AgentMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36
    • ·valid for31535998s
    • reuse #1 served without a new solveHTTP 200, 1 solve(s) total
    • reuse #2 served without a new solveHTTP 200, 1 solve(s) total
    • reuse #3 served without a new solveHTTP 200, 1 solve(s) total
    • ·explain()centralnovel.com binding layer : L9 Managed JavaScript challenge — reads a hybrid property, solve tier : clearance pacing : 1.5s mean interval requests : 12 ok / 1 failed clearance : 31535995s left ladder : direct(10) clearance(100) exits : direct

    Rendering — when the HTML is not the content

    pass S30 A browser renders a page whose HTML is not its content 35.35s

    What a pass proves. the one capability HTTP fidelity cannot substitute for, and the one failure that is silent: a shell parses to nothing and raises nothing.

    against https://www.wuxiaworld.com/
    • ·HTTP visible text from https://www.wuxiaworld.com/10 chars
    • ·target chosenhttps://www.wuxiaworld.com/ (content selector a.line-clamp-2)
    • ·rendered visible text9538 chars
    • the browser produced at least 5x the transport's text10 -> 9538 chars
    • the rendered page parses into a usable document137
    • a satisfied selector ends the wait early, on evidence1.8s against a 6s settle, 457 chars
    • ·text present when the selector appeared9538 settled -> 457 with a.line-clamp-2
    • a render is not recorded as a tier that workedtier='' successes=0
    • the render joined the referrer chainhttps://www.wuxiaworld.com/
    • a selector that never appears is an error, not an empty pageRenderError
    • ·explain()wuxiaworld.com binding layer : nothing has blocked yet tier : direct (unproven) pacing : 1.5s mean interval requests : 0 ok / 0 failed clearance : none ladder : direct(10) clearance(100) exits : direct

    Identity and content safety

    pass S18 Hidden and nofollow links are dropped from real pages L17 19.98s

    What a pass proves. The only layer that returns no error. Following a decoy link poisons the store and flags the session, and nothing in the response says so.

    against https://novelfull.net/
    • ·pages readhttps://tigertranslations.org/, https://chrysanthemumgarden.com/, https://novelfull.com/, https://novelfull.net/, https://dummynovels.com/, https://lightnovelfr.com/, https://freewebnovel.com/, https://ckandawrites.online/, https://www.mangaread.org/, https://mostnovel.com/
    • ·https://tigertranslations.org/35 followable, 0 rejected
    • ·https://chrysanthemumgarden.com/85 followable, 0 rejected
    • ·https://novelfull.com/114 followable, 0 rejected
    • ·https://novelfull.net/139 followable, 0 rejected
    • ·https://dummynovels.com/35 followable, 0 rejected
    • ·https://lightnovelfr.com/115 followable, 0 rejected
    • ·https://freewebnovel.com/120 followable, 1 rejected
    • ·https://ckandawrites.online/180 followable, 0 rejected
    • ·https://www.mangaread.org/201 followable, 1 rejected
    • ·https://mostnovel.com/63 followable, 6 rejected
    • real links survive across every page{'kept': 1087, 'rejected': 8}
    • genuine decoy markers were found and dropped{'inside an element hidden by inline style': 1, 'rel=nofollow': 7}
    • ·rejection reasons seen on real pages{'inside an element hidden by inline style': 1, 'rel=nofollow': 7}
    • ·false positives fixed during this runicon-font anchors and overlay/text anchor pairs were being dropped; both are real navigation. 11 of 11 rejections on one host were wrong.
    • a page from the site is not suspected
    • off-topic prose is flaggedvocabulary overlap 0% against 3 known pages (threshold 30%)
    pass S19 A clearance is refused under an identity that did not earn it L9 0.0s

    What a pass proves. The classic rotating-proxy failure, made structurally impossible: the cookie is bound to the address, User-Agent and TLS profile together.

    • valid under the identity that earned it
    • refused after the address movedthe identity changed since the clearance was earned
    • refused after the User-Agent changedthe identity changed since the clearance was earned
    • refused after the TLS profile changedthe identity changed since the clearance was earned
    pass S22 Requests are signed, and the signature verifies L18 0.92s

    What a pass proves. The one layer with no bypass. Deployed fail-open today, so a valid signature is a positive identification that skips the challenge machinery entirely.

    against https://httpbingo.org
    • the server received Signature-Inputsig1=("signature-agent" "@authority");created=1785415221;expires=1785415521;keyid="9Ie00ulnekN9EcOiGeObvQb3SsmovYz2ZP47-SRZ05w";alg="ed25519";tag="web-bot-auth"
    • the server received Signaturesig1=:mzBknpCyLs4mZ6QK+UZ8rOi6GbVEoao6OMh8qryHeG46EKLbej8rd38q9uIhvkql8eBNgcCi+l
    • the agent was declared
    • the tag is web-bot-auth
    • the algorithm is ed25519
    • the signature verifies against the published key
    • and does not verify for another authority
    • ·directory to publish/.well-known/http-message-signatures-directory -> kid 9Ie00ulnekN9EcOiGeObvQb3SsmovYz2ZP47-SRZ05w

    Other

    inconclusive S29 A proxy that refuses our credential is not blamed on the site L0 0.0s

    What a pass proves. A failure on our side of the proxy must not become a detection story. The SOCKS5 handshake has no status code, so this arrives as a bare transport error — and attributing it to layer 1 caused a rotation, a false 'blocked' report against a healthy exit, and a persisted verdict that the site refuses our address.

    against tor-pool with a deliberately wrong token

    tor-pool at http://127.0.0.1:8080 runs with AUTH_DISABLED, so any credential is accepted - restart it with AUTH_DISABLED=false to run this

    • ·not runtor-pool at http://127.0.0.1:8080 runs with AUTH_DISABLED, so any credential is accepted - restart it with AUTH_DISABLED=false to run this

    Environment

    scraper1.1.0
    Python (harness)Python 3.9.6
    Python (browser tier)Python 3.12.13
    curl_cffi0.13.0
    impersonation profilechrome136
    nodriver0.50.3
    browserGoogle Chrome (headed)
    tor-poolghcr.io/lncrawl/tor-pool:latest
    tor-pool exits5 instances
    local egress91.73.67.32

    Reproducing this

    uv run poe live-probe    # classify every host in lncrawl's source index (~4 min)
    uv run poe live-tor      # classify Cloudflare hosts through tor-pool
    uv run poe live          # run every scenario
    uv run poe live-report   # rebuild this page
    
    # the clearance tier needs its own interpreter (nodriver: Python 3.10-3.13) and Chrome
    /tmp/scr312/bin/python livetest/clearance.py

    Requirements and the politeness rules are in livetest/README.md. Targets are looked up from the probe rather than hardcoded, because site configuration moves: one host in this corpus switched from Turnstile to plain scoring between two runs an hour apart.