---
title: "Find Origin IPs Behind Cloudflare"
canonical: https://trickest.com/library/cloudflare-origin-ip-finder-waf-bypass
description: "Find the origin server behind Cloudflare or another WAF by resolving subdomains, filtering CDN ranges, and confirming which IP serves the site."
---

# Find Origin IPs Behind Cloudflare

## Overview

A WAF only protects the traffic that goes through it. If the origin server also
answers on its own public IP, every control you bought sits to one side of the
request: the rate limiting, the rules, the bot scoring, all bypassed by connecting
directly. Teams usually believe the origin is unreachable, because the main
hostname resolves to the CDN and nothing about that looks wrong.

This tells you whether that belief holds. Candidates come from sources that never
touch the target: subdomain enumeration, certificate transparency, passive DNS
holding addresses from before the CDN was in front, and the MX and SPF records
that mail infrastructure publishes and a CDN rarely fronts. Everything resolving
into a published CDN range is dropped, and what is left is requested directly
with your domain in the Host header. So you finish with a verdict per address
rather than a list to work through, which is the difference between a lead and a
finding.

It is a standing check for [offensive security](/use-cases/offensive-security)
work, because an origin leaks the day someone adds a DNS record, not the day you
look. Run on a schedule, the value is the diff: an address that answers outside
the CDN this week and did not last week is the alert. For the exhaustive
alternative, Host-header scanning across every cloud range, see
[how origin IPs leak](/blog/cloudflare-bypass-discover-ip-addresses-aws).

## Pipeline

1. Read the target domain.
2. [subfinder](/tools/subfinder) enumerates subdomains, including the mail, dev
   and legacy hosts that usually sit outside the CDN.
3. Candidate hosts are gathered from that list.
4. [dnsx](/tools/dnsx) resolves each one and keeps every A record.
5. The resolved addresses are checked against the published ranges of the major
   CDN providers, leaving the ones that belong to you.
6. Each remaining IP is requested directly with the original Host header, and the
   response is compared against the site served through the CDN.
7. Confirmed origins are ranked by confidence and written to a PDF.

## Inputs

- **Target domain.** The hostname that sits behind the CDN or WAF, with no
  protocol, one per run. The default is `example.com`, which is CDN fronted and
  safe to run against while you read the graph.
- **Credentials.** None. Subdomain enumeration, certificate transparency,
  passive DNS and the DNS record lookups are all token free, so nothing has to be
  provisioned before the first run.
- **CDN ranges.** Not a field you fill in. The published ranges for Cloudflare,
  Fastly and AWS CloudFront are fetched at run time rather than baked into the
  workflow, so a range the provider added last week still filters correctly.

## Outputs

- **Ranked candidate report (PDF).** Every candidate address with its verdict.
  Confirmed origins rank critical, addresses outside all CDN ranges that did not
  confirm rank medium.
- **Per-IP evidence.** The direct-to-IP response behind each verdict: status,
  server header, page title, certificate match and body hash, next to the CDN
  fronted baseline it was scored against.
- **Resolved IP inventory.** Every hostname the run found and the addresses it
  resolved to, including the ones inside CDN ranges. When nothing leaks, the
  inventory is what the run is worth.

## Sample output

Illustrative records; the origin IPs below are placeholders.

The confirmation step is where a candidate becomes a finding. Each address is
requested directly and the response is fingerprinted, so the comparison is
against evidence rather than a guess:

```jsonl
{"scheme":"https","port":443,"status":200,"server":"cloudflare","title":"Example Domain","body_sha256":"ff67a9d7...","cert_valid_for_domain":true,"reachable":true,"kind":"baseline"}
{"scheme":"https","port":443,"status":200,"server":"nginx","title":"Example Domain","body_sha256":"ff67a9d7...","cert_valid_for_domain":true,"reachable":true,"kind":"candidate","ip":"192.0.2.10"}
{"scheme":"https","port":443,"status":200,"server":"nginx","title":"Example Domain","body_sha256":"ff67a9d7...","cert_valid_for_domain":true,"reachable":true,"kind":"candidate","ip":"192.0.2.23"}
{"scheme":"http","port":80,"status":301,"server":"cloudflare","title":"","body_sha256":"","cert_valid_for_domain":false,"reachable":true,"kind":"reject","ip":"104.20.23.154"}
```

[dnsx](/tools/dnsx) keeps the full record detail, including the SOA that names
the DNS provider:

```json
{"host":"dev.example.com","ttl":1800,"soa":[{"name":"example.com","ns":"elliott.ns.cloudflare.com","mailbox":"dns.cloudflare.com"}]}
```

`kind: baseline` is the site as served through the CDN. A candidate is only
reported as an origin when its body hash and certificate match that baseline
while its address sits outside every published CDN range.

## FAQ

### What makes a candidate a confirmed origin rather than a lead?

Two things have to hold. The address has to sit outside every published CDN
range, and a direct request to it carrying your domain in the Host header has to
answer like your site. Certificate, page title, favicon hash, body hash and
server header are scored together, and only a candidate that clears the threshold
is reported as confirmed. The rest stay candidates with their evidence attached.

### Why does the body hash comparison matter?

Any host will answer on 443. Comparing a hash of the response body against the
CDN fronted baseline is what separates the server that actually serves your site
from a shared host, a default virtual host, or a parking page that happens to be
reachable. Without that comparison you have an open port and a guess.

### Does the target see this run?

The enumeration half does not, because subdomains, certificate transparency,
passive DNS and DNS records all come from third-party sources. The confirmation
step does, because it has to connect to each candidate address. Expect those
requests in the origin's own logs even though the CDN never sees them.

### What do you do once an origin is confirmed?

Change the address, then restrict the new one so it only accepts connections from
the CDN's published ranges. Changing it matters because the old address stays in
passive DNS history and certificate logs for years. Re-run afterwards: if the
address no longer confirms, the fix held.

### Do you need an API key for any of the sources?

No. Every source the enumeration reads is public and unauthenticated, and the CDN
ranges are published by the providers themselves, so a run needs nothing beyond
the domain.

## Related workflows

- [Subdomain Enumeration](/library/full-subdomain-enumeration). Reach for this
  one first when you do not have the complete hostname list yet, because origin
  finding is only as good as the names you feed it.
- [ASN-Wide Vulnerability Scan](/library/asn-vulnerability-scanner). Reach for this
  one once the origin is confirmed and the question moves to what is wrong with
  that host and everything sitting beside it in the netblock.
- [Passive Port & CVE Scan (Shodan)](/library/shodan-threat-intelligence). Reach for
  this one when you want the origin's service banners without any probe of your
  own reaching it.

---
_Markdown source of https://trickest.com/library/cloudflare-origin-ip-finder-waf-bypass._
