CLI tool
projectdiscovery/cdncheck avatar
projectdiscovery/cdncheck

cdncheck answers one question about an IP: is it behind a CDN, a cloud or a WAF

A utility to detect various technology for a given IP address.

996 stars138 forksGoMIT

At a glance

What is it?
cdncheck is a Go CLI and library from ProjectDiscovery that identifies the CDN, cloud or WAF provider associated with an IP or DNS name, filters the output, and ships as a compiled JSON index generated from a YAML provider list. It is useful for scope mapping and for deciding which probe a host will tolerate.
Who is it for?
cdncheck fits anyone doing reconnaissance who needs to know whether a host is fronted by a CDN, a cloud provider or a WAF before deciding how to interact with it, and it fits Go programs that need the same judgement as a library call. It does not fit anyone who needs to fingerprint the application layer, since a match here is about network ranges and names, not about what software is running on the origin.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The unit of detection is a network range, not a running application

cdncheck is described as a utility to detect various technology for a given IP address, and the project states it is a tool for identifying the technology associated with dns / ip network addresses. That framing matters, because it tells you what a match does and does not mean.

A hit means the address you supplied falls inside a range belonging to a CDN, a cloud provider or a WAF vendor, or that the hostname's CNAME points at one. It does not mean the application behind the address is that vendor's software, and it does not mean the address is safe or unsafe. A machine learning training endpoint and a public marketing site can both sit in the same AWS range.

The practical use is scoping and probing. Before sending traffic at an unfamiliar host, knowing that Cloudflare or Akamai sits in front changes what you should expect for latency, for rate limits, for what a 403 means, and for whether your own source address is even reaching the origin. cdncheck is one of the small number of tools that answers that question in a single command and also fits inside a Go program.

The library entry point is the same judgement expressed as a function. The package is github.com/projectdiscovery/cdncheck, and the client offers separate calls for the CDN, cloud and WAF checks.

The provider index is generated from a YAML file and a scrape step

The mechanism behind the tool is a build step, and understanding it explains both the tool's freshness and its limits.

The list of providers lives in cmd/generate-index/provider.yaml. It contains URLs, ASNs and CIDRs, and a program called generate-index compiles that into a final sources_data.json file, which is committed to the repository alongside sources_data.go. The three input kinds map to three sections of the YAML.

yaml
cdn:
  # asn contains the ASN numbers for providers
  asn:
    leaseweb:
      - AS60626

  # urls contains a list of URLs for CDN providers
  urls:
    cloudfront:
      - https://d7uri8nf7uskq.cloudfront.net/tools/list-cloudfront-ips
    fastly:
      - https://api.fastly.com/public-ip-list

Two things follow from that design. First, the ranges are only as good as the upstream URLs: Cloudflare and others publish their IP lists at a canonical address, and if that address changes shape or stops responding, the index needs regenerating. Second, adding a provider is a pull request against the YAML file, not a code change, which is why the documentation gives a fork, edit, commit, push and pull request procedure for it.

There is a second, less formal source of truth. CNAME and Wappalyzer based additions live in other.go, as two maps at the top of the file, one from CNAME suffix to CDN and one from Wappalyzer technology name to CDN. Adding a value to those maps is described as sufficient, with no generation step involved.

The CLI separates what you want to detect from what you want to hide

The flag surface is organised by intent, which makes cdncheck usable both as a discovery tool and as a filter inside a pipeline. The usage output groups flags under INPUT, DETECTION, MATCHER, FILTER, OUTPUT, CONFIG and UPDATE.

Input takes a list of IP or DNS names to process. Detection narrows the display to one category, so -cdn shows only CDN hits, -cloud only cloud and -waf only WAF. The matcher and filter flags are separate and both take provider lists, and the difference is the direction. Matching keeps only the specified providers, filtering removes them. The documented provider lists are cloudfront, fastly, google and leaseweb for CDN, aws, google and oracle for cloud, and cloudflare, incapsula, sucuri and akamai for WAF.

Output control is thorough. There is a plain text file output, a JSONL output, a verbose mode, a silent mode, a no-color switch, a switch to show the detected technology name, and a version flag. Configuration covers custom resolvers as a file or comma separated list, an exclude flag that drops the detected IP from the output, and a retry count for DNS resolution that must be at least 1 and defaults to 2.

The tool also checks for its own updates, and that behaviour can be turned off with the disable-update-check flag, which matters in environments where an outbound call to a release endpoint is unwanted.

Installing with go install, then checking one host

The installation is a single command, and the documentation states that cdncheck requires go1.19 to install successfully:

sh
go install -v github.com/projectdiscovery/cdncheck/cmd/cdncheck@latest

There is a wrinkle here worth flagging. The go.mod at the repository root declares go 1.25.0, and the current module graph pulls recent versions of the ProjectDiscovery libraries such as retryabledns at 1.0.116 and utils at 0.11.3. The go1.19 statement in the project documentation reflects the minimum language requirement as documented, while the module's own go directive is far newer. If your toolchain is old, the go directive is the binding constraint.

After installation, check the help output to see the flags your build exposes:

sh
cdncheck -h

A first real run passes the hosts to process with the input flag, and the -resp switch shows the technology name rather than only the category. For a scripted pipeline the JSONL output is the one to reach for, since it is the only format that carries structured results for later processing. The flag list in the project documentation gives the exact syntax for both, and the -silent switch is there when you want results only in the output file and nothing on the terminal.

A Docker path exists as well. The Dockerfile in the repository root is based on alpine:latest, installs bind-tools and ca-certificates, copies the platform-specific binary to /usr/local/bin/ and sets the entrypoint to cdncheck, so the container is invoked with the same flags.

If you would rather call the judgement from Go, the library example shows the pattern, with a client, a parsed IP and a check per category.

go
func main() {
	client := cdncheck.New()
	ip := net.ParseIP("173.245.48.12")

	// checks if an IP is contained in the cdn denylist
	matched, val, err := client.CheckCDN(ip)
	if err != nil {
		panic(err)
	}

	if matched {
		fmt.Printf("%v is a %v\n", ip, val)
	} else {
		fmt.Printf("%v is not a CDN\n", ip)
	}

Each check returns whether the address matched, the value that matched, and an error, so a caller can treat a detection failure differently from a clean miss rather than assuming the absence of a match means the address is not behind a CDN.

Detection quality depends on an index that goes stale

The main failure mode is silent under-detection, and it is structural rather than a bug.

cdncheck resolves DNS and then matches the resulting address against a compiled range list. If the resolver returns an address that is not in the list, for instance because the provider publishes ranges you are not carrying, or because you are looking at a region-specific anycast range that was added after the index was generated, the tool reports no detection. There is no error, no warning that the index is old, and no way to tell a genuine miss from a stale index.

The -retry flag exists because DNS resolution can be flaky, with a default of 2 retries for resolution failures, and the -r flag lets you point at your own resolvers, which matters behind split-horizon DNS. Neither of those addresses staleness, though. The only cure is regenerating the index, which is a maintainer task driven by the upstream provider URLs in provider.yaml.

A second limitation is the nature of the match. CNAME-based detection only fires if you give the tool a name and it can resolve it, and the CNAME map in other.go is a hand-maintained list, so coverage of hostname-based providers depends on what someone remembered to add. Wappalyzer-based detection reads technology fingerprints, which is a different signal from the range matching and is limited to whatever the map contains.

For a tool whose value is precisely telling you what is in front of a host, a false negative is worse than no answer, because a no answer reads as a finding. Treat an empty result as weak evidence.

A Go module with a library surface, tests and a Docker image

The repository is a small Go module with the structure you would expect from ProjectDiscovery tooling. At the top level there are cdncheck.go, types.go, other.go, sources_data.go and sources_data.json, with cmd/ holding the CLI and the generate-index program, internal/ for the internals, generate/ for the index generation, integration_tests/ and examples/, including a simple.go example. A Makefile defines build, test, functional, integration and tidy targets, where the functional target runs a shell script in cmd/functional-test and the integration target runs one in integration_tests.

The dependency list shows how the tool works. mapcidr handles the range matching, retryabledns and miekg/dns handle resolution, and the gaissmai/bart package is a prefix tree for efficient set lookups, which is the right structure for testing an address against thousands of CIDRs. The ipinfo/go client is present for the ASN side of the detection, and publicsuffix-go and goquery relate to the Wappalyzer and domain handling. The ProjectDiscovery utilities libraries supply the flag parsing and logging, with goflags for the CLI and gologger for output.

The test files sit next to the code they cover, with cdncheck_test.go and other_test.go at the root, and the module pulls stretchr/testify for assertions. The release pipeline uses .goreleaser.yaml, and the container image is built from the binary that the release process produces, which is why the Dockerfile copies $TARGETPLATFORM/cdncheck rather than compiling anything.

The licence is MIT, which is the permissive choice with no copyleft obligations for a tool you embed in a scanning pipeline or a Go program.

Editorial conclusion

cdncheck fits anyone doing reconnaissance who needs to know whether a host is fronted by a CDN, a cloud provider or a WAF before deciding how to interact with it, and it fits Go programs that need the same judgement as a library call. It does not fit anyone who needs to fingerprint the application layer, since a match here is about network ranges and names, not about what software is running on the origin. Before adopting it, read the provider list in cmd/generate-index/provider.yaml to see whether the vendors you care about are covered, and note that the source of truth for IP ranges is a set of upstream URLs that change over time, so a stale index silently under-detects.

Frequently asked questions

What does cdncheck detect?

cdncheck identifies the technology associated with DNS or IP addresses, covering CDN, cloud and WAF providers. Detection is based on the address falling inside a provider's published ranges, on ASN data, and on CNAME and Wappalyzer based mapping.

How do I install cdncheck?

Run `go install -v github.com/projectdiscovery/cdncheck/cmd/cdncheck@latest`. The project documentation states that go1.19 is required, though the module's go.mod declares go 1.25.0, and a Dockerfile is also provided for container use.

How do I add a new CDN or WAF provider?

Add the provider's URLs, ASNs or CIDRs to cmd/generate-index/provider.yaml and open a pull request, since that file is compiled into sources_data.json by the generate-index program. CNAME and Wappalyzer based additions are made instead in other.go by adding values to the cdnCnameDomains and cdnWappalyzerTechnologies maps.

Can I use cdncheck as a Go library?

Yes. Import github.com/projectdiscovery/cdncheck, create a client with cdncheck.New(), and call client.CheckCDN, client.CheckCloud or client.CheckWAF with a parsed IP. Each call returns whether the address matched, the matched value and an error.

Official sources

  1. License: MIT
  2. projectdiscovery/cdncheck on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/projectdiscovery-cdncheck.svg)](https://hysenlabs.com/projects/projectdiscovery-cdncheck)

Was this useful?