Discover domains, subdomains, and IP ranges (CIDRs) owned by any organization using certificate transparency, RIR registries, passive DNS, and 24 extensible plugins.
Pius is an open-source attack surface discovery tool written in Go. Given a company name, it maps the complete external attack surface: domains, subdomains, and IP ranges (CIDRs). Pius queries certificate transparency logs, all five regional Internet registries (ARIN, RIPE, APNIC, AFRINIC, LACNIC), passive DNS databases, WHOIS/RDAP, BGP tables, and more through 24 discovery plugins.
Built for penetration testers, bug bounty hunters, and security teams who need reliable, repeatable asset discovery. Unlike ad-hoc reconnaissance scripts, Pius is production-grade: concurrent plugin execution, a three-phase discovery pipeline, multi-tier caching, confidence scoring for ambiguous results, graceful degradation, and passive-first OSINT defaults.
- Why Pius: How It Compares to Amass and Subfinder
- Features
- Quick Start
- Plugins
- How It Works: Three-Phase Discovery Pipeline
- Architecture
- Usage
- Configuration
- FAQ
- Troubleshooting
- Contributing
- Security
- License
Pius fills the gap between subdomain enumeration tools (like subfinder) and full attack surface management platforms. If you need both domain and CIDR discovery from a single tool with confidence scoring and a phased pipeline, Pius is purpose-built for that workflow.
| Feature | Pius | amass | subfinder |
|---|---|---|---|
| Language | Go | Go | Go |
| Single binary | Yes | Yes | Yes |
| RIR CIDR discovery | Yes (all 5 RIRs) | Partial | No |
| Phase pipeline | Yes (handle → CIDR) | No | No |
| Confidence scoring | Yes | No | No |
| Passive mode default | Yes | Yes | Yes |
| Cache layer | Yes (24h) | No | No |
- Penetration testing. Map an organization's external attack surface before an engagement.
- Bug bounty reconnaissance. Discover in-scope domains and IP ranges from an organization name.
- Attack surface management. Continuously monitor for new assets with passive-first defaults.
- Red team operations. Identify subsidiary and affiliated infrastructure through corporate registries (GLEIF, SEC EDGAR, Wikidata).
| Feature | Description |
|---|---|
| 24 Discovery Plugins | 15 domain plugins + 9 CIDR plugins covering certificate transparency, passive DNS, WHOIS, RDAP, RPSL, BGP tables, favicon hashing, and subdomain permutation |
| All 5 RIRs | ARIN (North America), RIPE (Europe/Middle East), APNIC (Asia-Pacific), AFRINIC (Africa), LACNIC (Latin America) |
| Three-Phase Pipeline | Phase 0 runs independently, Phase 1 discovers RIR org handles, Phase 2 resolves handles to CIDRs; late-stage plugins enrich results using discovered assets |
| Confidence Scoring | Ambiguous name-to-asset mappings are scored and flagged for review rather than silently dropped |
| Multi-Tier Cache | API responses cached 24h as JSON; RPSL databases cached 24h as decompressed local files |
| Passive Mode Default | Only OSINT sources queried by default; active plugins (DNS brute-force, zone transfer) opt-in |
| Flexible Output | Terminal table, JSON array, and NDJSON (newline-delimited) formats |
| Single Binary | Go-based tool compiles to one portable executable with no runtime dependencies |
Requires Go 1.25.0 or later.
go install github.com/praetorian-inc/pius/cmd/pius@latestOr build from source:
git clone https://github.com/praetorian-inc/pius.git
cd pius
go build -o pius ./cmd/pius# Discover domains and CIDRs for an organization (passive mode)
pius run --org "Acme Corp"
# Add a domain hint to unlock more plugins
pius run --org "Acme Corp" --domain acme.com
# Include active plugins (DNS brute-force, zone transfer)
pius run --org "Acme Corp" --domain acme.com --mode all[domain] acme.com (crt-sh)
[domain] api.acme.com (crt-sh)
[domain] staging.acme.com (passive-dns)
[domain] acme.com (reverse-whois) ⚠ needs-review [confidence:0.42]
[cidr] 203.0.113.0/24 (arin)
[cidr] 198.51.100.0/22 (ripe)
pius listAll domain plugins run in Phase 0 (independent, concurrent). They emit discovered domain names.
| Plugin | Data Source | Auth Required | Mode | Notes |
|---|---|---|---|---|
crt-sh |
Certificate Transparency logs | None | Passive | Deduplicates wildcard entries |
apollo |
Apollo.io enrichment API | APOLLO_API_KEY |
Passive | Caches results 24h; 0.85 confidence for domain queries |
github-org |
GitHub organization search | GITHUB_TOKEN (optional) |
Passive | Confidence-scored; 0.65 threshold to emit |
gleif |
GLEIF LEI corporate registry | None | Passive | Discovers parent/subsidiary domains |
passive-dns |
SecurityTrails passive DNS | SECURITYTRAILS_API_KEY |
Passive | Historical subdomain records |
reverse-whois |
ViewDNS reverse WHOIS | VIEWDNS_API_KEY |
Passive | 0.75 confidence; registrant email matching |
dns-brute |
Local DNS resolver | None | Active | 50 concurrent goroutines; embedded wordlist |
dns-zone-transfer |
DNS AXFR | None | Active | Extracts A, AAAA, CNAME, MX, SRV records |
doh-enum |
DNS-over-HTTPS resolvers | AWS credentials (optional) | Active | 50 concurrent workers; round-robin endpoint rotation; optional API Gateway deployment for IP diversity |
favicon-hash |
Shodan + FOFA favicon search | SHODAN_API_KEY, FOFA_API_KEY (optional) |
Active | MurmurHash3 of favicon; discovers origin IPs behind CDNs |
dns-permutation |
Discovered subdomains (Phase 0) | None | Active | Phase 3; altdns-style permutations; wildcard filtering |
google-dorks |
Google Knowledge Graph | None | Passive | Carousel scraping for subsidiary companies |
reverse-ip |
PTR records, HackerTarget, ViewDNS | VIEWDNS_API_KEY (optional) |
Passive | Phase 3; consumes CIDRs from Phase 2 |
wikidata |
Wikidata SPARQL | None | Passive | P749/P355/P127 corporate relationships; 24h cache |
censys-org |
Censys Platform API v3 | CENSYS_API_TOKEN, CENSYS_ORG_ID |
Active | Searches host/cert data by org; emits domains + CIDRs; requires Starter+ plan; caches 24h |
CIDR discovery uses a multi-phase pipeline: Phase 0 discovers CIDRs directly, Phase 1 discovers RIR organization handles, and Phase 2 resolves handles to CIDR blocks.
| Plugin | Phase | Data Source | Protocol | RIR Coverage |
|---|---|---|---|---|
asn-bgp |
0 (independent) | RIPE RIS BGP tables | HTTP REST | Global (announced prefixes) |
shodan |
0 (independent) | Shodan net: search | HTTP REST | Global (requires SHODAN_API_KEY) |
whois |
1 (handle discovery) | All 5 RIRs | HTTP REST | ARIN, RIPE, APNIC, AFRINIC, LACNIC |
edgar |
1 (handle discovery) | SEC EDGAR filings | HTTP REST | Global public companies |
arin |
2 (resolution) | ARIN RDAP | RDAP (RFC 7483) | North America |
ripe |
2 (resolution) | RIPE RDAP | RDAP (RFC 7483) | Europe, Middle East, Central Asia |
lacnic |
2 (resolution) | LACNIC RDAP | RDAP (RFC 7483) | Latin America & Caribbean |
apnic |
2 (resolution) | APNIC RPSL database | Cached gzip file | Asia-Pacific |
afrinic |
2 (resolution) | AFRINIC RPSL database | Cached gzip file | Africa |
Pius uses a three-phase concurrent pipeline to discover organizational assets:
pius run --org "Acme Corp" --domain acme.com
│
▼
Plugin Registry
(init() auto-registration)
│
┌──────────┴─────────────────────────────┐
│ Phase 0 (concurrent, independent) │
│ crt-sh apollo github-org gleif │
│ passive-dns reverse-whois │
│ dns-brute* dns-zone-transfer* │
│ doh-enum* favicon-hash* │
│ asn-bgp │
└──────────┬─────────────────────────────┘
│ Emits domains + CIDRs directly
┌──────────┴─────────────────────────────┐
│ Phase 1 (concurrent) │
│ whois edgar │
└──────────┬─────────────────────────────┘
│ Emits RIR org handles
▼
enrichWithHandles()
Input.Meta["arin_handles"] = "ACME-1"
Input.Meta["ripe_handles"] = "ORG-ACME-RIPE"
│
┌──────────┴─────────────────────────────┐
│ Phase 2 (concurrent) │
│ arin ripe apnic afrinic lacnic │
└──────────┬─────────────────────────────┘
│ Emits CIDR blocks
▼
enrichWithAssets()
Input.Meta["cidrs"] = [...]
Input.Meta["discovered_domains"] = [...]
│
┌──────────┴─────────────────────────────┐
│ Late-stage (concurrent, asset consumers)│
│ dns-permutation* reverse-ip │
└──────────┬─────────────────────────────┘
│ Emits additional domains
▼
filterOutput()
(strips internal handle findings)
│
▼
Domains + CIDRs
* active mode only
- Phase 0 (Independent): Domain and CIDR plugins with no cross-plugin dependencies run concurrently from the start
- Phase 1 (Handle Discovery):
whoisqueries all 5 RIRs for organization handles.edgarpattern-matches SEC filings - Handle Enrichment: Discovered handles are grouped by registry and injected into the pipeline input
- Phase 2 (Handle Resolution): RDAP plugins (ARIN, RIPE, LACNIC) fetch CIDR blocks per handle. RPSL plugins (APNIC, AFRINIC) parse locally-cached registry databases
- Asset Enrichment: Discovered CIDRs and domains are injected into the pipeline input for late-stage consumers
- Late-Stage Enrichment:
dns-permutationgenerates altdns-style subdomain variants from discovered domains.reverse-ipperforms PTR lookups on discovered CIDRs - Output Filtering: Internal
cidr-handlefindings are removed. Only domains and CIDRs reach the user
cmd/pius/ CLI entrypoint (Cobra-based)
pkg/
cache/ Two-tier caching: API responses (JSON) + RPSL databases (gzip)
cidr/ IP range → CIDR conversion and /24 subnet splitting
client/ Shared HTTP client with retries and 10 MB response limit
plugins/ Plugin interface, registry, confidence scoring
all/ Blank imports to trigger all plugin init() registrations
cidrs/ CIDR discovery plugin implementations
domains/ Domain discovery plugin implementations
runner/ Pipeline orchestration, mode filtering, output formatting
- Three-phase pipeline separates RIR handle discovery (Phase 1) from CIDR resolution (Phase 2), enabling accurate multi-RIR lookups
- Plugin-style registration using Go
init()functions. New plugins require zero changes to the runner - Confidence scoring for ambiguous name-matching plugins (GitHub org search, reverse WHOIS, Apollo) distinguishes high-confidence results from ones that need human review
- Two-tier caching optimizes for different data profiles: small API responses as JSON (apollo, github-org) and large RPSL registry dumps as decompressed local files (APNIC, AFRINIC)
- Graceful degradation throughout. Plugin errors are logged but never fail the pipeline; partial results are always returned
# Passive discovery (default) is safe for continuous monitoring
pius run --org "Acme Corp"
# Add domain hint to unlock crt-sh, dns-brute, passive-dns, zone-transfer
pius run --org "Acme Corp" --domain acme.com
# Add ASN hint to directly query BGP tables
pius run --org "Acme Corp" --asn AS12345
# All hints combined
pius run --org "Acme Corp" --domain acme.com --asn AS12345# Passive CIDR discovery via all 5 RIRs
pius run --org "Acme Corp" --mode passive --plugins whois,arin,ripe,apnic,afrinic,lacnic
# Direct BGP lookup from ASN (no handle resolution needed)
pius run --org "Acme Corp" --asn AS12345 --plugins asn-bgp# Basic DoH enumeration with embedded wordlist (Cloudflare, Google, AdGuard resolvers)
pius run --domain acme.com --mode active --plugins doh-enum
# Use a custom wordlist
pius run --domain acme.com --mode active --plugins doh-enum --doh-wordlist /path/to/wordlist.txt
# Use custom DoH servers
pius run --domain acme.com --mode active --plugins doh-enum \
--doh-servers "https://dns.google.com/dns-query,https://cloudflare-dns.com/dns-query"
# Deploy API Gateways across 8 AWS regions for IP rotation (requires AWS credentials)
pius run --domain acme.com --mode active --plugins doh-enum \
--doh-servers "https://dns.google.com/dns-query,https://cloudflare-dns.com/dns-query" \
--doh-deploy-gateways
# Use pre-existing API Gateway URLs
pius run --domain acme.com --mode active --plugins doh-enum \
--doh-gateways "https://abc123.execute-api.us-east-1.amazonaws.com/pius"# Terminal table (default) - human-readable
pius run --org "Acme Corp"
# JSON array - structured output for parsing
pius run --org "Acme Corp" --output json
# NDJSON - one object per line, ideal for streaming/piping
pius run --org "Acme Corp" --output ndjson
# Pipe NDJSON to jq for filtering
pius run --org "Acme Corp" --output ndjson | jq 'select(.type == "cidr")'# Run only specific plugins
pius run --org "Acme Corp" --plugins crt-sh,apollo,arin
# Disable specific plugins (run everything else)
pius run --org "Acme Corp" --disable edgar,dns-brute
# Active mode - includes DNS brute-force and zone transfer
pius run --org "Acme Corp" --domain acme.com --mode active
# All modes - passive + active combined
pius run --org "Acme Corp" --domain acme.com --mode all
# Adjust concurrency (default: 5)
pius run --org "Acme Corp" --concurrency 10Plugins that require API keys check for them in Accepts() before running. If the environment variable is missing, the plugin is silently skipped.
| Variable | Plugin | Required | Notes |
|---|---|---|---|
APOLLO_API_KEY |
apollo |
Yes | Apollo.io API key |
GITHUB_TOKEN |
github-org |
No | Raises rate limit from 60 to 5000 req/hr |
SECURITYTRAILS_API_KEY |
passive-dns |
Yes | SecurityTrails API key |
VIEWDNS_API_KEY |
reverse-whois |
Yes | ViewDNS.info API key |
SHODAN_API_KEY |
favicon-hash |
Yes | Shodan API key |
FOFA_API_KEY |
favicon-hash |
No | FOFA API key; enables additional scanner |
VIEWDNS_API_KEY |
reverse-ip |
No | ViewDNS.info API key; enables additional reverse IP source |
CENSYS_API_TOKEN |
censys-org |
Yes | Censys Platform API Personal Access Token (Starter+ plan) |
CENSYS_ORG_ID |
censys-org |
Yes | Censys workspace organization UUID |
| AWS credentials | doh-enum |
No | Required only when using --doh-deploy-gateways |
Pius caches data under ~/.pius/cache/ automatically. No configuration is needed.
| Cache Type | Used By | TTL | Format |
|---|---|---|---|
| API response cache | apollo, github-org, censys-org |
24 hours | JSON per key |
| RPSL registry database | apnic, afrinic |
24 hours | Decompressed gzip |
To clear the cache:
rm -rf ~/.pius/cache/Usage:
pius run [flags]
pius list
run flags:
-o, --org string Organization name to search (required)
-d, --domain string Known domain hint (optional)
--asn string Known ASN hint, e.g. AS12345 (optional)
--plugins string Comma-separated plugin whitelist (default: all)
--disable string Comma-separated plugin blacklist
--concurrency int Max concurrent plugins (default: 5)
-f, --output string Output format: terminal, json, ndjson (default: terminal)
--mode string Plugin mode: passive, active, all (default: passive)
--doh-wordlist string Path to subdomain wordlist for DoH enumeration
--doh-servers string Comma-separated DoH server URLs
--doh-gateways string Comma-separated AWS API Gateway URLs for DoH
--doh-deploy-gateways Auto-deploy AWS API Gateways for IP rotation
Exit Codes:
| Code | Meaning |
|---|---|
| 0 | Success, discovery completed |
| 1 | Runtime error |
All passive plugins that accept the provided input run by default. Passive plugins with API key requirements (apollo, passive-dns, reverse-whois) are silently skipped if their environment variable is not set. Active plugins (dns-brute, dns-zone-transfer, doh-enum, favicon-hash) only run with --mode active or --mode all.
Phase 0 plugins (domain plugins + asn-bgp) run immediately and concurrently. Phase 1 plugins (whois, edgar) discover RIR organization handles from the company name. The runner then injects those handles into the input as metadata, and Phase 2 plugins (arin, ripe, apnic, afrinic, lacnic) resolve each handle to CIDR blocks. This separation enables accurate multi-RIR coverage while keeping plugins loosely coupled.
Some plugins use confidence scoring to rank ambiguous matches. For example, github-org scores organization candidates based on name similarity and domain matching. Findings with confidence between 0.35 and 0.65 are emitted with a needs-review flag rather than being silently discarded. Findings below 0.35 are dropped as noise.
- Create a Go file in
pkg/plugins/domains/orpkg/plugins/cidrs/ - Implement the
plugins.Plugininterface (7 methods:Name,Description,Category,Phase,Mode,Accepts,Run) - Register in an
init()function:func init() { plugins.Register("my-plugin", func() plugins.Plugin { return &MyPlugin{client: client.New()} }) }
- Import the package in
pkg/plugins/all/all.go
See existing plugins like crt_sh.go or arin.go for reference implementations.
Yes. The following plugins require no authentication and run with only --org:
crt-sh(needs--domain)gleifwhoisedgararin,ripe,apnic,afrinic,lacnicasn-bgp(needs--asn)github-org(optionalGITHUB_TOKEN)wikidatagoogle-dorks
Active plugins (dns-brute, dns-zone-transfer, doh-enum) also require no auth but must be enabled with --mode active. Note: doh-enum uses an embedded wordlist by default; AWS credentials are only needed for --doh-deploy-gateways. The favicon-hash plugin requires SHODAN_API_KEY.
RDAP plugins (arin, ripe, lacnic) make live HTTP queries to each registry's RDAP API. One request is made per handle. RPSL plugins (apnic, afrinic) download the full registry database as a gzip file once per day and parse it locally. RPSL offers lower latency after the initial download; RDAP offers fresher data.
Cause: Phase 1 plugins found no RIR handles, or handles returned no CIDRs.
Solutions:
- Try alternate spellings of the organization name:
--org "Acme Corporation"vs--org "Acme Corp" - Check if
whoisoredgarran: run with--plugins whoisto isolate - Verify the organization has RIR allocations (some orgs use cloud provider space)
Cause: Missing domain hint, or API keys not set.
Solutions:
- Add
--domainto unlock crt-sh and DNS plugins - Set
APOLLO_API_KEY,SECURITYTRAILS_API_KEY, orVIEWDNS_API_KEYfor those plugins - Run
pius listto confirm which plugins are registered
Cause: RPSL database cache is within its 24-hour TTL.
Solution:
rm ~/.pius/cache/*.rpsl
pius run --org "Acme Corp"Cause: GITHUB_TOKEN not set; unauthenticated requests limited to 60/hr.
Solution:
export GITHUB_TOKEN="ghp_..."
pius run --org "Acme Corp"Cause: Multiple RDAP requests per handle across multiple registries.
Solution: Reduce concurrency or restrict to specific registries:
# Only query ARIN (faster if org is US-based)
pius run --org "Acme Corp" --plugins whois,arinWe welcome contributions. To add a new plugin:
- Create the plugin file in the appropriate package (
domains/orcidrs/) - Implement the
Plugininterface - 7 methods required - Register via
init()and add a blank import topkg/plugins/all/all.go - Write unit tests covering
Accepts(),Run(), error paths, and caching (if applicable) - Follow existing error handling conventions:
- Transient failures → return
(nil, nil)(graceful degradation) - Parse errors → return wrapped error with context
- Log warnings with
slog.Warn()for partial failures
- Transient failures → return
# Run all tests
go test ./...
# Run specific package tests
go test ./pkg/plugins/domains/... -v
# Build binary
go build -o pius ./cmd/pius
# Install to $GOPATH/bin
go install ./cmd/piusPius is designed for authorized security testing and asset discovery only.
- Pius sends DNS queries and API requests for the organization you specify. You must always ensure you have authorization
- Active plugins (
dns-brute,dns-zone-transfer) generate network traffic to target nameservers - Never run against organizations you don't own or have explicit permission to assess
Report security issues via GitHub Issues.
Apache 2.0 - Praetorian Security, Inc.
Built by Praetorian. Offensive security experts specializing in attack surface management, penetration testing, and security engineering.
