A Python command-line tool that queries the Have I Been Pwned v3 API to identify all breached email addresses associated with a given domain. Results can be printed to the terminal or exported as JSON or CSV for downstream reporting and analysis.
- Looks up all breached email addresses for a target domain in a single API call
- Reconstructs full email addresses from the alias-only format returned by HIBP
- Enriches each breach with metadata: breach date, record count, exposed data classes, sensitivity flag, and verification status
- Exports results as JSON or CSV with format auto-detection from file extension
- Respects HIBP rate limits with a configurable delay between requests
- Handles HTTP 429 responses automatically using the
retry-afterheader - Caches breach detail lookups to avoid redundant API calls
- Loads API key from
.envviapython-dotenv— no hardcoded credentials
- Python 3.8+
- A paid HIBP API key — the
/breacheddomain/endpoint is not available on the free tier. The PWNED 1 plan (~$3.50/mo) is the minimum required tier.
Install dependencies:
pip install requests python-dotenv-
Clone or download
hibp_domain_scan.pyinto your project directory. -
Create a
.envfile in the same directory:
HIBP_API_KEY=your_paid_key_here
- Add
.envto your.gitignoreto avoid committing credentials:
.env
python hibp_domain_scan.py <domain> [options]# Print results to terminal only
python hibp_domain_scan.py example.com
# Save as JSON (format auto-detected from extension)
python hibp_domain_scan.py example.com --output results.json
# Save as CSV (format auto-detected from extension)
python hibp_domain_scan.py example.com --output results.csv
# Override format detection with explicit flag
python hibp_domain_scan.py example.com --output results.txt --format csv
# Pass API key inline (overrides .env)
python hibp_domain_scan.py example.com --api-key YOUR_KEY_HERE
# Skip breach detail lookups for a faster run
python hibp_domain_scan.py example.com --no-enrich
# Combine flags
python hibp_domain_scan.py example.com --no-enrich --output results.csv| Argument | Short | Description |
|---|---|---|
domain |
Target domain to scan (e.g. example.com) |
|
--output PATH |
-o |
File path for saved results. Format auto-detected from .json / .csv extension. |
--format {json,csv} |
-f |
Explicitly set output format. Overrides extension auto-detection. |
--api-key KEY |
-k |
HIBP API key. Overrides .env / environment variable. |
--no-enrich |
Skip per-breach detail lookups. Faster, but output contains breach names only. |
============================================================
HIBP Domain Scan Results
Domain : example.com
Scan time : 2025-08-14 18:42 UTC
Emails found: 3
Unique breaches: 5
============================================================
alice@example.com
↳ Adobe breach date: 2013-10-04 records: 152,445,165
↳ LinkedIn breach date: 2012-05-05 records: 164,611,595
bob@example.com
↳ RockYou breach date: 2009-12-04 records: 32,603,388
{
"domain": "example.com",
"scan_date": "2025-08-14T18:42:00Z",
"total_breached_emails": 3,
"results": [
{
"email": "alice@example.com",
"breaches": [
{
"Name": "Adobe",
"BreachDate": "2013-10-04",
"PwnCount": 152445165,
"DataClasses": ["Email addresses", "Password hints", "Passwords", "Usernames"]
}
]
}
]
}One row per email–breach pair. Columns:
| Column | Description |
|---|---|
email |
Full reconstructed email address |
breach_name |
HIBP internal breach identifier |
breach_title |
Human-readable breach name |
breach_date |
Date the breach occurred |
pwn_count |
Number of accounts exposed in the breach |
data_classes |
Comma-separated list of exposed data types |
is_sensitive |
Whether HIBP marks the breach as sensitive |
is_verified |
Whether the breach has been verified by HIBP |
domain |
The scanned domain |
The script resolves the API key in the following order (first match wins):
--api-key/-kCLI flagHIBP_API_KEYenvironment variableHIBP_API_KEYin.envfile (loaded viapython-dotenv)
HIBP enforces rate limits on the breach detail endpoint. This script applies a 1.5-second delay between each detail lookup by default (REQUEST_DELAY constant). If a 429 Too Many Requests response is received, the script reads the retry-after header and waits accordingly before retrying.
Use --no-enrich to skip detail lookups entirely if speed is a priority and breach metadata is not needed.
- Third-party vendor risk assessments — identify credential exposure risk for vendor domains before onboarding
- Internal exposure monitoring — scan your organization's domain periodically as part of a threat intelligence program
- Incident response triage — quickly enumerate affected accounts following a reported breach
- HIPAA / SOC 2 evidence — document proactive credential monitoring as a detective control
- Security awareness input — identify users with repeated breach history for targeted training
- The
/breacheddomain/endpoint requires a paid HIBP API key. Free-tier keys will return403 Forbidden. - HIBP data reflects breaches that have been ingested and published by the HIBP service. It does not represent real-time or complete coverage of all credential exposures.
- Results cover only email addresses associated with the exact domain searched. Subdomains and alternate domains must be queried separately.
- REST API integration with authentication header management
python-dotenvfor secure credential handling- CLI design with
argparse(positional args, flags, short aliases, choices) - Response caching to minimize redundant API calls
- Rate limit handling including retry-after parsing
- Dual-format file output (JSON and CSV) with extension-based auto-detection
- GRC-aligned tool design for third-party risk and credential exposure monitoring
MIT — see LICENSE for details.
Author: Aaron Dutton