# projectdiscovery/uncover: One CLI for Shodan, Censys, FOFA and Twelve More Search Engines

> uncover is a Go wrapper that queries internet-wide scan APIs from a single command and prints ip:port by default. It is built for pipelines, not for interactive browsing, and it is useless until you supply API keys.

**projectdiscovery/uncover** — Quickly discover exposed hosts on the internet using multiple search engines.

- Repository: https://github.com/projectdiscovery/uncover
- Stars: 3,070 · Forks: 281
- Language: Go
- License: MIT
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/projectdiscovery-uncover

## What uncover actually replaces in a recon workflow

Attack-surface work usually starts with a query against a scan database: certificates, banners, favicons, exposed services. Each of those databases has its own web console, its own query language and its own result export. uncover collapses the query step into one binary. The README describes it as a Go wrapper using APIs of well known search engines, built with automation in mind so results can be consumed by existing pipeline tools.

The audience is narrow and identifiable. It is for people who already run command-line recon: bug bounty hunters, internal red teams, and engineers who maintain asset inventories. It is not for someone who wants to browse a map of the internet. There is no interface beyond flags and stdout.

The feature list names fifteen engines: Shodan, Censys, FOFA, Hunter, Quake, ZoomEye, Netlas, CriminalIP, PublicWWW, HunterHow, Google, Onyphe, Driftnet, DayDayMap and NerdyData. The flag list in the README enumerates a slightly different set, adding shodan-idb and omitting NerdyData. That discrepancy is worth noticing before you plan around a specific provider.

## How the query fan-out works

The architecture is visible in the repository layout. The top level holds runner/, sources/ and cmd/, plus uncover.go at the root and an examples/ directory with a single main.go. The sources/ package is where per-engine clients live; runner/ is the layer that takes a query, decides which engine handles it, and returns results. The go.mod file confirms the shape of that runner: it depends on projectdiscovery/ratelimit, projectdiscovery/retryablehttp-go, projectdiscovery/goflags and projectdiscovery/gologger, plus the official github.com/censys/censys-sdk-go for one provider.

That dependency set tells you what the tool does at runtime. Requests go out through a retryable HTTP client. A rate limiter sits in front of them. Flags are parsed by goflags, which is why -query accepts repeated values and file paths. Logging goes through gologger.

Results are normalized. The default output field is ip:port, and -f accepts ip, port or host. With -json you get JSONL instead, one object per line. With -raw you get whatever the remote API returned, unnormalized. That last flag is the escape hatch when a provider returns a field the normalizer drops.

A single -query value is sent to the engine selected by -e, which defaults to shodan. If you pass -e with several engines, the same query string goes to each of them. The README does not describe any query translation between engines, so a Shodan-style query sent to FOFA will be rejected by FOFA's API rather than rewritten. The per-engine flags (-shodan, -fofa, -censys and the rest) exist for that reason: they let you attach a different query string to each provider in one invocation.

## Installing uncover and running a first query

The README states that uncover requires go1.21 to install successfully, and gives one command. Note that go.mod declares go 1.25.0, so a toolchain at least that new is the safer assumption when building from source.

```bash
go install -v github.com/projectdiscovery/uncover/cmd/uncover@latest
```

Before anything works you need keys. The default provider configuration path is $CONFIG/uncover/provider-config.yaml, and the README carries a note that API keys are required and must be configured before running uncover. The example file shows the shape: a top-level key per engine, with a YAML list of credentials. Some providers take a single token, others take a pair joined by a colon.

```yaml
shodan:
  - SHODAN_API_KEY_1
  - SHODAN_API_KEY_2
censys:
  - CENSYS_API_TOKEN_1:CENSYS_ORGANIZATION_ID_1
fofa:
  - FOFA_EMAIL_1:FOFA_KEY_1
quake:
  - QUAKE_TOKEN_1
```

The README documents multiple API key input and automatic API key randomization, so listing two keys for one engine is a supported pattern rather than a mistake.

With the config in place, a first query against the default engine looks like this. The -silent flag suppresses everything except results, which is what you want when piping.

```bash
uncover -q 'example query' -silent -limit 10
```

The README gives -q 'example query' as the literal example for the query flag, so substitute your own engine syntax. Expect up to ten lines of ip:port, since -limit defaults to 100 and the output field defaults to ip:port. If you want structured output for a downstream parser, add -j and read JSONL instead.

There is also a shortcut worth knowing about. The -asq flag takes a named query from the bundled projectdiscovery/awesome-search-queries module, which go.mod pins. The README's example is -asq 'jira', which runs a prepared query for exposed Jira instances rather than one you wrote yourself.

```bash
uncover -asq 'jira' -e shodan -silent
```

If you would rather not install Go, the repository ships a Dockerfile that builds the binary in a golang:1.24.1-alpine stage and copies it into an alpine:3.18.2 image with the entrypoint set to uncover. The README does not give a docker run invocation, so you would need to mount your provider-config.yaml into the container yourself.

## Where uncover stops being the right tool

The hardest constraint is the one stated plainly: API keys are required. There is no unauthenticated mode, no free tier baked in, and no local index. Every result you see was paid for, either in a subscription or in query credits, by the account whose key you configured. If you do not already have access to at least one of these engines, uncover gives you nothing to run.

Rate limits are the second constraint, and they are two-sided. uncover has its own -rl and -rlm flags to cap requests per second and per minute, with -timeout defaulting to 30 seconds and -retry defaulting to 2. Those flags govern how fast uncover talks to a provider. They do not raise the provider's own ceiling. A Shodan or Censys plan sets its own quota, and uncover cannot negotiate around it.

Query syntax is the third. Because there is no translation layer, the tool is only as good as your familiarity with each engine's query language. Someone fluent in Shodan filters will find that fluency does not transfer to FOFA or Quake.

Finally, results are not verified. uncover returns what the API said, and the README does not claim any liveness check. A host indexed months ago may be gone. Treat the output as candidates for a follow-up scan, not as confirmed assets. There is also no documented deduplication across engines, so querying three providers with overlapping coverage will produce overlapping lines.

## uncover against the engines it wraps, and against a full scanner

The obvious alternative is not another wrapper but the providers themselves. Shodan, Censys and FOFA all ship web consoles and their own CLIs or SDKs. Using them directly gives you the full query builder, saved searches, and every field the API returns, including the ones uncover's normalizer drops unless you pass -raw. What you lose is uniformity: three consoles, three output formats, three sets of credentials to manage by hand. uncover's value is exactly that uniformity, and if you only ever query one engine, that value is close to zero.

A different comparison is against scanners such as the project's own ecosystem tools that probe hosts directly. Those confirm what is live right now; uncover tells you what a third party indexed, which may be older but often covers hosts you would never find by scanning a range you guessed. The two are complementary in a pipeline, and the README's framing of stdin/stdout support is aimed at exactly that chaining.

Within the wrapper category, the distinguishing choice here is breadth over depth. Fifteen engines under one flag set is a lot of surface area, and the mismatch between the README's feature list and its own flag list suggests the edges of that surface are not perfectly groomed. A narrower wrapper covering two engines you actually pay for would be less to maintain.

## Licence, releases and the cost of keeping it current

uncover is MIT licensed, with the licence text in LICENSE.md at the repository root. MIT is permissive: you can use, modify and redistribute it, including in commercial internal tooling. The practical implication is not about the wrapper but about the data. uncover's licence says nothing about the terms of the APIs it calls, and each provider has its own agreement governing how query results may be stored, reshared or used to contact hosts. Read those separately; the MIT grant covers the Go code only.

On maintenance, the last push to the default branch was on 2026-08-31, which is recent. Releases are less frequent than commits: v1.2.1 on 2026-05-20, v1.2.0 on 2025-11-27, and v1.1.0 on 2025-06-20. The cadence suggests a tool that is stable rather than rapidly changing, which cuts both ways for upgrade cost.

The upgrade risk sits in the provider clients, not in uncover's own flags. Each engine can change its API, its authentication scheme or its response shape without warning, and a wrapper has to follow. The pinned censys-sdk-go version in go.mod is one concrete place where an upstream change would force a dependency bump. If you build from source rather than installing a release binary, you inherit that churn. Pinning to a tagged release is the lower-effort path.

Running it from Docker adds a second maintenance surface: the image is built on alpine:3.18.2, and the base image will need refreshing on its own schedule independent of uncover's releases.

## Conclusion

Adopt uncover if you already hold API keys for at least one supported engine and you want its results as stdin/stdout lines inside an existing recon pipeline. Skip it if you have no keys, if you need a graphical console, or if you expect a free data source: the README states that API keys are required and must be configured before running uncover, and the default engine is shodan. Verify first that your provider-config.yaml parses, that the keys you paste actually carry query quota, and that your chosen engine accepts the query syntax you intend to send, because the README does not translate one engine's syntax into another's.

## FAQ

### How do I install projectdiscovery/uncover?

The README gives a single Go command: go install -v github.com/projectdiscovery/uncover/cmd/uncover@latest, and states that uncover requires go1.21 to install successfully. The repository also includes a Dockerfile that builds the binary and sets uncover as the entrypoint.

### What is projectdiscovery/uncover?

The README describes it as a Go wrapper using the APIs of well known search engines to quickly discover exposed hosts on the internet, built with automation in mind so results can be used with existing pipeline tools.

### How do I use projectdiscovery/uncover?

Configure API keys in $CONFIG/uncover/provider-config.yaml, then run a query with the -q flag and select an engine with -e, which defaults to shodan. Output defaults to ip:port, and -j switches it to JSONL.

## Sources

- [Issues](https://github.com/projectdiscovery/uncover/issues)
- [License: MIT](https://github.com/projectdiscovery/uncover/blob/main/LICENSE)
- [projectdiscovery/uncover on GitHub](https://github.com/projectdiscovery/uncover)
- [README](https://github.com/projectdiscovery/uncover/blob/main/README.md)
- [Releases](https://github.com/projectdiscovery/uncover/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/projectdiscovery-uncover
