惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Hacker News: Front Page
博客园_首页
大猫的无限游戏
大猫的无限游戏
有赞技术团队
有赞技术团队
Microsoft Azure Blog
Microsoft Azure Blog
Recorded Future
Recorded Future
博客园 - Franky
Application and Cybersecurity Blog
Application and Cybersecurity Blog
U
Unit 42
S
Secure Thoughts
博客园 - 司徒正美
美团技术团队
C
Cisco Blogs
The GitHub Blog
The GitHub Blog
G
Google Developers Blog
V
Vulnerabilities – Threatpost
T
Troy Hunt's Blog
S
Security Affairs
爱范儿
爱范儿
AWS News Blog
AWS News Blog
Help Net Security
Help Net Security
Blog — PlanetScale
Blog — PlanetScale
T
Threatpost
F
Fortinet All Blogs
Scott Helme
Scott Helme
酷 壳 – CoolShell
酷 壳 – CoolShell
B
Blog RSS Feed
O
OpenAI News
S
Schneier on Security
Stack Overflow Blog
Stack Overflow Blog
T
Tor Project blog
AI
AI
D
DataBreaches.Net
PCI Perspectives
PCI Perspectives
T
Tailwind CSS Blog
Martin Fowler
Martin Fowler
P
Palo Alto Networks Blog
C
CERT Recently Published Vulnerability Notes
腾讯CDC
T
Tenable Blog
人人都是产品经理
人人都是产品经理
Recent Announcements
Recent Announcements
C
Cyber Attacks, Cyber Crime and Cyber Security
Jina AI
Jina AI
Hacker News - Newest:
Hacker News - Newest: "LLM"
Google Online Security Blog
Google Online Security Blog
S
Securelist
P
Proofpoint News Feed
L
LINUX DO - 最新话题
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Detecting paying Cloudflare customers (for fun and profit)
Henley Wing · 2026-05-03 · via DEV Community

A while back I got curious about whether you could tell the difference between a company paying Cloudflare serious money versus one that signed up for the free plan and forgot about it.

First thing I tried: response headers. Don’t bother. Cloudflare returns identical header names whether you’re running on Workers, sitting on an Enterprise contract, or using the free tier. That’s intentional – Cloudflare doesn’t want their product tier to leak through HTTP.

What isn’t intentional is everything else. Here’s a full walkthrough, ordered from weakest to strongest signal. Code samples are Python, but everything here is just DNS lookups and HTTP requests – translate to whatever language you want.


Baseline: Are They Even Using Cloudflare?

Before anything else you need to confirm you’re actually looking at a Cloudflare-proxied domain.

Cloudflare publishes their IP ranges publicly at cloudflare.com/ips. Resolve the domain’s A record, check if it falls inside those ranges. Or check the nameservers – Cloudflare customers using the full proxy will have ns1.cloudflare.com / ns2.cloudflare.com as their NS records.

def on_cloudflare(domain):
    a_records = dns_lookup_a(domain)
    if any(ip in cloudflare_ip_ranges for ip in a_records):
        return True

    ns_records = dns_lookup_ns(domain)
    return any("cloudflare" in ns for ns in ns_records)

Enter fullscreen mode Exit fullscreen mode

Cloudflare Radar publishes the top million domains by traffic. DNS-resolve all of them against the Cloudflare IP list and you’ve got a large working dataset in under an hour.

The catch: this puts you at roughly 20% of the web. That’s a lot of personal blogs and parked domains. The signals below are about separating the serious customers from the noise.


Signal #1: Dashboard SSO TXT Record

Straightforward to check, surprisingly revealing.

When a company configures SSO for their Cloudflare dashboard login (wiring it into Okta, Azure AD, or another SAML identity provider), the setup process adds a TXT record to their DNS zone:

cloudflare_dashboard_sso=1111111

Enter fullscreen mode Exit fullscreen mode

def has_dashboard_sso(domain):
    txt_records = dns_lookup_txt(domain)
    return any("cloudflare_dashboard_sso=" in r for r in txt_records)

Enter fullscreen mode Exit fullscreen mode

This used to be locked to Enterprise. Cloudflare has since relaxed that, so it’s not a guaranteed paid signal anymore. But practically speaking: nobody running a hobby project or a small business on the free tier is going to spend their afternoon setting up a SAML connector. The configuration effort alone filters out the noise. Treat it as a soft signal of intentional, serious usage.

Fast to run across the full Radar million since it’s just a DNS query.


Signal #2: Cloudflare Email Products (MX Records)

Two completely different Cloudflare email products, both detectable via MX record inspection.

Email Routing is a free forwarding service. When enabled, Cloudflare replaces the domain’s MX records with their own mail servers. The pattern looks like this:

MX 52  route1.mx.cloudflare.net
MX 98  route2.mx.cloudflare.net
MX 91  route3.mx.cloudflare.net

Enter fullscreen mode Exit fullscreen mode

Some zones use named variants instead: amir.mx.cloudflare.net, linda.mx.cloudflare.net, isaac.mx.cloudflare.net. Either way, the *.mx.cloudflare.net suffix is the tell. Since this is a free product it’s a weak signal on its own – but it does confirm the domain is actively managed in Cloudflare rather than just having DNS parked there.

Email Security (formerly Area 1) is the paid product. It’s an anti-phishing and email threat detection platform aimed squarely at enterprise security teams. When deployed in inline mode, it sits in front of the customer’s mail provider as the primary MX record, inspecting every inbound message before it reaches Google Workspace or Microsoft 365. The MX records point to Area 1’s inbound gateways rather than the customer’s mail provider directly – look for *.area1security.com or Cloudflare-owned inbound gateway hostnames.

def email_signals(domain):
    mx_records = dns_lookup_mx(domain)
    mx_hosts = [mx.lower() for mx in mx_records]
    return {
        "email_routing": any("mx.cloudflare.net" in mx for mx in mx_hosts),
        "email_security": any("area1security.com" in mx for mx in mx_hosts),
    }

Enter fullscreen mode Exit fullscreen mode

Email Security is Enterprise territory – it’s a dedicated security product with per-seat pricing and a sales process. Seeing those MX records on a domain is a strong indicator of an Enterprise relationship.


Signal #3: Bot Defense Cookies

Passive signal – no probing needed, just inspect cookies on a normal response.

__cf_bm shows up when any of Cloudflare’s bot defense products are active: Bot Management (Enterprise-only), Super Bot Fight Mode (Pro+), or Bot Fight Mode (free). The cookie itself doesn’t tell you which tier, but its presence means someone has actively configured bot protection beyond the defaults.

_cfuvid appears when a site is using cf.unique_visitor_id inside a WAF Rate Limiting Rule to track unique visitors behind shared IPs (corporate NATs, etc.). Available on any plan, but writing custom rate limiting rules signals intentional configuration rather than a default install.

def cookie_signals(response):
    cookies = response.headers.get("set-cookie", "")
    return {
        "bot_management": "__cf_bm=" in cookies,
        "rate_limiting":  "_cfuvid=" in cookies,
    }

Enter fullscreen mode Exit fullscreen mode

Neither cookie alone proves paid status. Together with other signals they help build the picture.


Signal #4: Custom Error Pages

A bit more involved, but one of the more reliable signals for Pro+ customers.

Cloudflare’s default error pages have consistent fingerprints you can match against:

  • "Attention Required! | Cloudflare" – WAF block page
  • _cf_chl_opt – challenge/CAPTCHA page
  • cf-error-details – diagnostic error pages

Pro plan and above lets customers replace these with custom error responses. Plenty of paying customers do this because Cloudflare’s default error page clashes with their brand.

The detection relies on a quirk: Cloudflare’s edge always writes the cf-ray header into every response. This Ray ID is generated at the edge – the customer’s origin server has no way of knowing it in advance. But when Cloudflare renders a custom error page, the edge also writes that same Ray ID into the response body.

So if the Ray ID from the response header appears in the body, and the body doesn’t match any default Cloudflare template, you’re looking at a custom error page from a paying customer.

def has_custom_error_page(response):
    if not (400 <= response.status < 600):
        return False
    if "cloudflare" not in response.headers.get("server", ""):
        return False

    ray_id = response.headers["cf-ray"].split("-")[0]
    if ray_id not in response.body:
        return False

    default_markers = [
        "Attention Required! | Cloudflare",
        "_cf_chl_opt",
        "cf-error-details",
        "__CF$cv$params",
        "/cdn-cgi/challenge-platform/scripts/jsd/main.js",
    ]
    return not any(m in response.body for m in default_markers)

Enter fullscreen mode Exit fullscreen mode

One false positive trap: Cloudflare’s bot detection JS beacon also embeds the Ray ID in normal HTML responses. The default_markers exclusion list catches this.

To trigger the error page, hit a nonexistent API path: https://api.example.com/api/v1/zzzz_not_real. APIs reliably return 4xx on unknown paths, which triggers Cloudflare’s error rendering. Marketing sites require probing paths like /wp-admin or /.env – more aggressive and more likely to get your scanner flagged.

Running this against api.* subdomains at scale, the hits were Swiss classifieds platforms, central banks, major retailers, government agencies. Exactly the profile you’d expect for paid customers.


Signal #5: Cloudflare Access (Zero Trust)

Cloudflare Access gates any web application behind a login screen, typically used to protect internal tooling: Grafana dashboards, GitLab instances, Jenkins, internal admin panels. In 2026 it’s also being used to lock down MCP servers.

When you hit an Access-protected endpoint without a valid session, Cloudflare redirects to the customer’s team page on cloudflareaccess.com. That redirect is the signal.

def has_cloudflare_access(url):
    response = http_get(url, follow_redirects=False)
    if response.status not in (301, 302, 303, 307, 308):
        return False
    return "cloudflareaccess.com" in response.headers.get("location", "")

Enter fullscreen mode Exit fullscreen mode

Internal tooling subdomains follow predictable patterns. For each domain, probe:

gitlab.<domain>
grafana.<domain>
jenkins.<domain>
internal.<domain>
admin.<domain>
wiki.<domain>
mcp.<domain>

Enter fullscreen mode Exit fullscreen mode

Most won’t resolve. Check the ones that do. Access has a free tier (up to 50 users) so it’s not a hard Enterprise gate, but the engineering investment of configuring Access policies and integrating an identity provider correlates strongly with paid usage.


Signal #6: OV or EV TLS Certificates

This one requires understanding the three tiers of SSL certificate validation.

DV (domain-validated) is what every free service issues, including Cloudflare’s Universal SSL. The certificate authority just checks you control the domain. Takes seconds. The cert subject contains only CN=.

OV (organization-validated) requires the CA to verify your company is a real legal entity – business registration, phone verification, the works. Takes days. The company name is embedded in the cert subject: O=, L=, ST=, C=.

EV (extended validation) is OV with a deeper background check: jurisdiction, physical address, operational existence. Subject fields include businessCategory, serialNumber, jurisdictionCountryName. Used primarily in regulated industries where compliance frameworks mandate it.

The detection angle: Cloudflare cannot issue OV or EV certificates. Universal SSL is DV only. So if a domain resolves to Cloudflare IPs but its certificate is OV or EV, the customer purchased a commercial cert and uploaded it via Custom Certificates – a Business plan feature ($200/month minimum) used almost exclusively by Enterprise customers.

You can identify certificate tiers programmatically via the certificatePolicies OIDs:

  • 2.23.140.1.2.1 – DV
  • 2.23.140.1.2.2 – OV
  • 2.23.140.1.1 – EV
def cert_tier(host):
    cert = fetch_tls_cert(host)
    if has_ev_subject_fields(cert) or "2.23.140.1.1" in cert.policy_oids:
        return "EV"
    if "O=" in cert.subject and "2.23.140.1.2.2" in cert.policy_oids:
        return "OV"
    return "DV"

def has_paid_cert(domain):
    if not any(ip in cloudflare_ip_ranges for ip in dns_lookup_a(domain)):
        return False
    return cert_tier(domain) in ("OV", "EV")

Enter fullscreen mode Exit fullscreen mode

Testing against fendt.com: OV cert issued by DigiCert with O=AGCO GmbH, served from Cloudflare IPs. AGCO is a $14B multinational – the finding makes sense. OV/EV on a Cloudflare-served domain is one of the strongest single signals for Enterprise status.


Signal #7: Static IPs

By default, Cloudflare is anycast. A single IP like 104.21.3.47 could be serving thousands of completely unrelated domains simultaneously. The IP belongs to Cloudflare and is shared across their entire customer base.

Static IPs are an Enterprise-only feature where Cloudflare allocates IPs from their range exclusively to a single customer. Nothing else resolves to those IPs. Common in financial services and B2B SaaS where clients require stable IP addresses for firewall allowlisting.

Detection requires aggregate data. Build a frequency map across your full domain dataset:

def find_static_ip_candidates(all_cloudflare_domains):
    ip_to_domains = {}
    for domain in all_cloudflare_domains:
        for ip in dns_lookup_a(domain):
            if ip in cloudflare_ip_ranges:
                ip_to_domains.setdefault(ip, []).append(domain)

    # Anycast IPs serve thousands of domains
    # Static IPs serve 1-3 (apex, www, maybe a subdomain)
    return {
        ip: domains
        for ip, domains in ip_to_domains.items()
        if len(domains) <= 3
    }

Enter fullscreen mode Exit fullscreen mode

Additional tell: Static IPs tend to be allocated in sequential blocks. If a single domain has two A records where only the third octet differs, and both are rare in your frequency map, that’s a strong Static IP signal.


Signal #8: Secondary DNS

One of the cleanest Enterprise signals and the easiest to detect.

Standard Cloudflare customers let Cloudflare host their DNS entirely – nameservers become ns1.cloudflare.com and ns2.cloudflare.com. Secondary DNS is a different model: the customer keeps their own primary DNS infrastructure and adds Cloudflare as a secondary authoritative server, receiving zone transfers via AXFR/IXFR as a resilient backup.

The NS records tell the story immediately. A Secondary DNS customer has both their own nameservers and Cloudflare’s secondary ones listed together:

ns1.company.com
ns2.company.com
ns0227.secondary.cloudflare.com
ns0022.secondary.cloudflare.com

Enter fullscreen mode Exit fullscreen mode

The *.secondary.cloudflare.com pattern only ever appears for this product. The four-digit number is a per-customer or per-zone identifier.

def has_cloudflare_secondary_dns(domain):
    ns_records = dns_lookup_ns(domain)
    return any("secondary.cloudflare.com" in ns for ns in ns_records)

Enter fullscreen mode Exit fullscreen mode

Per Cloudflare’s DNS feature matrix, Secondary DNS requires Enterprise plus the Foundation DNS add-on specifically – it’s not included in a standard Enterprise contract. That makes it a stronger indicator than most Enterprise features. Organizations running Secondary DNS have made a deliberate investment in DNS as critical infrastructure.

The IRS has it configured. Government agencies, central banks, and large financial institutions are the profile to expect when scanning for this.


Signal #9: Magic Transit (BGP)

Every other signal on this list works by inspecting a single domain. This one works differently – you’re looking at public BGP routing tables.

Magic Transit lets Enterprise customers route their own IP space through Cloudflare’s network. The customer brings IP prefixes they own (or lease), and Cloudflare announces those prefixes to the internet from AS13335. All traffic destined for those IPs flows through Cloudflare’s scrubbing infrastructure before reaching the customer’s network.

The detection approach: pull every prefix currently announced by AS13335, then WHOIS each one. Prefixes registered to non-Cloudflare organizations are Magic Transit customers.

Browse it manually first to validate the concept:

https://bgp.he.net/AS13335#_prefixes

For programmatic detection, RIPE stat is the most reliable data source:

import requests

def get_as13335_prefixes():
    r = requests.get(
        "https://stat.ripe.net/data/announced-prefixes/data.json?resource=AS13335"
    )
    # Skip IPv6 -- Magic Transit customers are almost exclusively IPv4
    return [p for p in r.json()["data"]["prefixes"]
            if ":" not in p["prefix"]]

NOISE_PATTERNS = ["ip-ripe", "ip manager", "-mnt", "private customer"]
CLOUDFLARE_HANDLES = ["CLOUD14", "CLOUDF"]
NOISE_HANDLES = ["ripe", "arin", "apnic", "afrinic", "lacnic"]

def find_magic_transit_customers(prefixes):
    customers = []
    for p in prefixes:
        ip = p["prefix"].split("/")[0]
        org = whois_org(ip)  # ARIN RDAP with redirect following
        if not org or is_noise(org["name"], org["handle"]):
            continue
        customers.append({
            "prefix":  p["prefix"],
            "name":    org["name"],
            "bgpview": f"https://bgpview.io/prefix/{p['prefix']}",
        })
    return customers

Enter fullscreen mode Exit fullscreen mode

Running this against the full AS13335 prefix list surfaces names like these:

Prefix Organization
23.227.37.0/24 Shopify, Inc.
199.68.19.0/24 VISA International Service Association
131.167.255.0/24 Battelle Memorial Institute
161.248.134.0/24 Canadian Association of Blue Cross Plans
203.15.65.0/24 University of Sydney
103.77.7.0/24 FUJIFILM Data Management Solutions
351.0/24 Genetec
2109 Yardi Systems, Inc.

Three things to filter out:

ISPs and carriers use Magic Transit for their own DDoS protection – it’s actually one of Cloudflare’s largest use cases by traffic volume. Skip anything whose org name or netname contains ISP, TELECOM, CARRIER, or DATACENTER, or anything that has its own ASN with a large prefix count. Legitimate enterprise Magic Transit customers typically have one or two prefixes total and no BGP presence of their own.

WHOIS placeholders – entries showing as IP-RIPE, IP Manager, or handles ending in -MNT are administrative placeholders or IP broker records, not end customers.

IP leasing – some customers bring leased IP space rather than IPs they own outright. The WHOIS points to the leasing company (IPXO is common). The tell is mnt-lower: IPXO-MNT in the RIPE record.

After filtering, what remains is unambiguously Enterprise-tier. Magic Transit requires a dedicated sales engagement, a minimum committed bandwidth, and a manual BGP peering session with Cloudflare’s network team. You don’t stumble into it.


Watch Out For

Platform contamination. Hosting platforms like Kinsta run all customer sites through Cloudflare Enterprise by default. The tenant didn’t configure it, may not know it’s there, and isn’t a Cloudflare customer in any meaningful sense. This is part of why stacking paid signals matters – a Kinsta-hosted blog won’t have a custom error page or an OV cert or Cloudflare Access configured.

Scale carefully. Probing endpoints with WAF-triggering patterns (SQLi strings, common exploit paths) across thousands of domains will get your scanner blocked fast. Everything in this list can be detected with benign requests – non-existent paths, standard User-Agents, no exotic payloads.


Summary

Signal Plan Method
IP / NS check Free DNS lookup
Dashboard SSO TXT Free (high friction) DNS TXT lookup
Email Routing Free MX record lookup
Bot cookies (__cf_bm, _cfuvid) Pro+ Passive HTTP
Custom error pages Pro+ ($25/mo) HTTP probe + body parse
Email Security (Area 1) Enterprise MX record lookup
Cloudflare Access Free tier (strong proxy) HTTP redirect check
OV/EV certificate Business+ ($200/mo) TLS cert inspection
Static IPs Enterprise Aggregate DNS map
Secondary DNS Enterprise + Foundation DNS NS record lookup
Magic Transit Enterprise BGP + WHOIS

None of these signals is definitive in isolation. Stack them and you get a surprisingly clear picture of where a company actually sits on the Cloudflare tier ladder – all from public data, no credentials required.


Spotted a signal I missed? Drop it in the comments.