Python client library for the Have I Been Pwned API
Project description
Have I Been Pwned - Python Library
A comprehensive, easy-to-use Python library for the Have I Been Pwned API v3. Check if email accounts have been compromised in data breaches, validate password security, and access paste and stealer log data - all through a clean, Pythonic interface.
โจ Features
- ๐ Pwned Passwords: Check passwords using k-Anonymity (no API key needed)
- ๐ง Breach Data: Search breached accounts and get detailed breach information
- ๐ Pastes: Find paste exposures for email addresses
- ๐ฏ Stealer Logs: Access malware-captured credentials (Pwned 5+ subscription)
- ๐ข Domain Search: Search breaches across verified domains
- ๐ก๏ธ Type Safety: Full type hints for better IDE support and code quality
- โก Error Handling: Comprehensive exception hierarchy for robust error management
- ๐ฆ Rate Limiting: Automatic handling of API rate limits
๐ Documentation
- Installation Guide - How to install and configure the library
- Usage Guide - Comprehensive usage examples and API reference
- Contributing Guide - How to contribute to the project
- Development Guide - Development setup and testing
๐ Quick Start
Installation
pip install haveibeenpwned-py
Full installation instructions โ
Simple Example
from haveibeenpwned import HIBP
# Check if an account has been breached (requires API key)
hibp = HIBP(api_key="your-api-key-here")
breaches = hibp.get_account_breaches("test@example.com")
for breach in breaches:
print(f"๐จ {breach.name}: {breach.pwn_count:,} accounts affected")
# Check if a password has been pwned (no API key required!)
hibp_passwords = HIBP()
count = hibp_passwords.is_password_pwned("password123")
if count > 0:
print(f"โ ๏ธ Password found in {count:,} breaches!")
else:
print("โ Password not found in any breaches")
More examples and detailed usage โ
๐ API Endpoints
This library provides complete coverage of all HIBP API v3 endpoints:
Breaches API (7 endpoints)
- โ Check account breaches
- โ Get all breaches
- โ Get single breach details
- โ Get latest breach
- โ Get data classes
- โ Get domain breaches (requires verification)
- โ Get subscribed domains
Pastes API
- โ Get pastes for an account
Stealer Logs API (Pwned 5+ subscription)
- โ Get stealer logs by email
- โ Get stealer logs by website
- โ Get stealer logs by email domain
Subscription API
- โ Get subscription status
Pwned Passwords API (no API key required)
- โ Check password by plaintext
- โ Search by hash prefix (k-Anonymity)
- โ SHA-1 and NTLM hash support
๐ API Key
Most endpoints require an API key from Have I Been Pwned. The Pwned Passwords API does not require authentication.
Get your API key: https://haveibeenpwned.com/API/Key
Test API key for development: 00000000000000000000000000000000
Learn more about API key setup โ
๐๏ธ Project Structure
haveibeenpwned/
โโโ haveibeenpwned/ # Main package
โ โโโ api.py # Main HIBP interface
โ โโโ breach.py # Breach endpoints
โ โโโ client.py # HTTP client
โ โโโ exceptions.py # Custom exceptions
โ โโโ models.py # Data models
โ โโโ passwords.py # Pwned Passwords API
โ โโโ pastes.py # Pastes endpoints
โ โโโ stealer_logs.py # Stealer logs endpoints
โ โโโ subscription.py # Subscription endpoints
โโโ tests/ # Comprehensive test suite
โโโ docs/ # Documentation
โ โโโ INSTALL.md # Installation guide
โ โโโ USAGE.md # Usage guide
โ โโโ CONTRIBUTING.md # Contributing guide
โ โโโ DEVELOPMENT.md # Development guide
โโโ README.md # This file
๐ค Contributing
Contributions are welcome! This project maintains high standards:
- โ Test Coverage: >95% required
- โ Type Hints: Full type annotations
- โ Documentation: Comprehensive docs and examples
- โ Code Quality: Follows PEP 8 and best practices
Read the contributing guide โ
๐งช Testing
# Run all tests
./run_tests.sh all
# Run unit tests only (fast, no API key needed)
./run_tests.sh unit
# Run integration tests (requires HIBP_API_KEY)
export HIBP_API_KEY="your-api-key"
./run_tests.sh live
# Check coverage
./run_tests.sh coverage
๐ Requirements
- Python 3.8 or higher
- requests >= 2.25.0
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Attribution
This library uses the Have I Been Pwned API. When using this library, you must provide clear attribution to Have I Been Pwned as required by their Terms of Service.
The breach and paste data is licensed under Creative Commons Attribution 4.0 International License.
โ ๏ธ Disclaimer
This is an unofficial library and is not affiliated with Troy Hunt or Have I Been Pwned. Use responsibly and in accordance with the HIBP Acceptable Use Policy.
๐ Resources
- Website: Have I Been Pwned
- API Documentation: HIBP API v3
- Get API Key: Purchase API Access
- PyPI Package: haveibeenpwned-py
- GitHub Repository: dynacylabs/haveibeenpwned
Made with โค๏ธ for security and privacy
Usage Examples
Breaches
Check Account Breaches
# Get all breaches for an account
breaches = hibp.get_account_breaches("test@example.com")
# Get full breach details (not truncated)
breaches = hibp.get_account_breaches(
"test@example.com",
truncate_response=False
)
# Filter by domain
breaches = hibp.get_account_breaches(
"test@example.com",
domain="adobe.com"
)
# Exclude unverified breaches
breaches = hibp.get_account_breaches(
"test@example.com",
include_unverified=False
)
Get All Breaches
# Get all breaches in the system
all_breaches = hibp.get_all_breaches()
# Filter by domain
adobe_breaches = hibp.get_all_breaches(domain="adobe.com")
# Get only spam lists
spam_lists = hibp.get_all_breaches(is_spam_list=True)
Get Single Breach
# Get details for a specific breach
breach = hibp.get_breach("Adobe")
print(f"Name: {breach.name}")
print(f"Date: {breach.breach_date}")
print(f"Accounts: {breach.pwn_count}")
print(f"Data classes: {', '.join(breach.data_classes)}")
Get Latest Breach
# Get the most recently added breach
latest = hibp.get_latest_breach()
print(f"Latest breach: {latest.name} added on {latest.added_date}")
Get Data Classes
# Get all data classes
data_classes = hibp.get_data_classes()
print("Available data classes:", data_classes)
Domain Search
# Get breached accounts for your verified domain
domain_breaches = hibp.get_domain_breaches("example.com")
for alias, breach_names in domain_breaches.items():
print(f"{alias}@example.com: {', '.join(breach_names)}")
# Get your subscribed domains
domains = hibp.get_subscribed_domains()
for domain in domains:
print(f"{domain.domain_name}: {domain.pwn_count} breached accounts")
Pastes
# Get pastes for an account
pastes = hibp.get_account_pastes("test@example.com")
for paste in pastes:
print(f"Source: {paste.source}")
print(f"ID: {paste.id}")
print(f"Date: {paste.date}")
print(f"Emails: {paste.email_count}")
Stealer Logs
Requires Pwned 5+ subscription.
# Get stealer log domains for an email
domains = hibp.get_stealer_logs_by_email("test@example.com")
print(f"Credentials captured on: {', '.join(domains)}")
# Get email addresses captured on a website
emails = hibp.get_stealer_logs_by_website("netflix.com")
print(f"Compromised accounts: {', '.join(emails)}")
# Get stealer logs by email domain
logs = hibp.get_stealer_logs_by_email_domain("example.com")
for alias, websites in logs.items():
print(f"{alias}@example.com compromised on: {', '.join(websites)}")
Pwned Passwords
No API key required for Pwned Passwords!
# Simple password check
count = hibp.is_password_pwned("password123")
if count > 0:
print(f"โ ๏ธ Password found {count} times in breaches!")
else:
print("โ Password not found in breaches")
# Use NTLM hash instead of SHA-1
count = hibp.is_password_pwned("password123", use_ntlm=True)
# Add padding for enhanced privacy
count = hibp.is_password_pwned("password123", add_padding=True)
# Search by hash prefix directly
results = hibp.search_password_hashes("21BD1") # First 5 chars of SHA-1 hash
for suffix, count in results.items():
print(f"Hash suffix {suffix}: seen {count} times")
Subscription Status
# Get your subscription details
subscription = hibp.get_subscription_status()
print(f"Plan: {subscription.subscription_name}")
print(f"Rate limit: {subscription.rpm} requests per minute")
print(f"Max domain size: {subscription.domain_search_max_breached_accounts}")
print(f"Includes stealer logs: {subscription.includes_stealer_logs}")
print(f"Valid until: {subscription.subscribed_until}")
Advanced Usage
Using Individual API Modules
You can also access the API modules directly for more control:
from haveibeenpwned import HIBP
hibp = HIBP(api_key="your-api-key")
# Access individual API modules
breaches = hibp.breaches.get_breaches_for_account("test@example.com")
pastes = hibp.pastes.get_pastes_for_account("test@example.com")
status = hibp.subscription.get_status()
count = hibp.passwords.check_password("password123")
Custom User Agent
hibp = HIBP(
api_key="your-api-key",
user_agent="MyApp/1.0 (contact@example.com)"
)
Custom Timeout
hibp = HIBP(
api_key="your-api-key",
timeout=60 # 60 seconds
)
Error Handling
The library provides detailed exceptions for different error scenarios:
from haveibeenpwned import (
HIBP,
NotFoundError,
RateLimitError,
AuthenticationError,
BadRequestError,
ForbiddenError,
ServiceUnavailableError,
HIBPError,
)
hibp = HIBP(api_key="your-api-key")
try:
breaches = hibp.get_account_breaches("test@example.com")
except NotFoundError:
print("Account not found in any breaches")
except RateLimitError as e:
print(f"Rate limit exceeded. Retry after {e.retry_after} seconds")
except AuthenticationError:
print("Invalid API key")
except BadRequestError as e:
print(f"Bad request: {e}")
except ForbiddenError:
print("Access forbidden - check user agent")
except ServiceUnavailableError:
print("Service temporarily unavailable")
except HIBPError as e:
print(f"API error: {e}")
Models
The library provides typed models for API responses:
Breach
breach = hibp.get_breach("Adobe")
# Access breach properties
breach.name # "Adobe"
breach.title # "Adobe"
breach.domain # "adobe.com"
breach.breach_date # "2013-10-04"
breach.added_date # "2013-12-04T00:00:00Z"
breach.modified_date # "2022-05-15T23:52:49Z"
breach.pwn_count # 152445165
breach.description # HTML description
breach.data_classes # ["Email addresses", "Passwords", ...]
breach.is_verified # True
breach.is_sensitive # False
breach.is_retired # False
breach.is_spam_list # False
breach.logo_path # "Adobe.png"
# Convert to dictionary
breach_dict = breach.to_dict()
Paste
paste = pastes[0]
paste.source # "Pastebin"
paste.id # "8Q0BvKD8"
paste.title # "syslog"
paste.date # "2014-03-04T19:14:54Z"
paste.email_count # 139
Subscription
subscription = hibp.get_subscription_status()
subscription.subscription_name # "Pwned 1"
subscription.description # "Up to 10 passwords per minute..."
subscription.subscribed_until # "2024-12-31T23:59:59Z"
subscription.rpm # 10
subscription.domain_search_max_breached_accounts # 100
subscription.includes_stealer_logs # False
Rate Limiting
The API enforces rate limits based on your subscription level. When rate limited:
from haveibeenpwned import RateLimitError
try:
breaches = hibp.get_account_breaches("test@example.com")
except RateLimitError as e:
# Wait for the specified time
import time
time.sleep(e.retry_after)
# Retry the request
breaches = hibp.get_account_breaches("test@example.com")
API Key
Most endpoints require an API key. You can obtain one from: https://haveibeenpwned.com/API/Key
The Pwned Passwords API does not require an API key.
Test API Key
For testing, you can use the test API key 00000000000000000000000000000000 with test accounts:
hibp = HIBP(api_key="00000000000000000000000000000000")
# These test accounts work with the test key
breaches = hibp.get_account_breaches("account-exists@hibp-integration-tests.com")
breaches = hibp.get_account_breaches("spam-list-only@hibp-integration-tests.com")
breaches = hibp.get_account_breaches("stealer-log@hibp-integration-tests.com")
Requirements
- Python 3.8+
- requests >= 2.25.0
License
This project is licensed under the MIT License.
Attribution
This library uses the Have I Been Pwned API. The breach and paste data is licensed under Creative Commons Attribution 4.0 International License. When using this library, you must provide clear attribution to Have I Been Pwned.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Testing
The library includes a comprehensive test suite with both unit tests (mocked) and integration tests (live API).
Running Tests
# Install test dependencies
pip install -r requirements-test.txt
# Run all tests
pytest
# Run only unit tests (no API key needed)
pytest -m unit
# Run only integration tests (requires HIBP_API_KEY)
export HIBP_API_KEY="your-api-key"
pytest -m integration
# Run with coverage
pytest --cov=haveibeenpwned --cov-report=html
Test Coverage
The test suite includes:
- โ Client & HTTP: Request handling, error responses, timeouts
- โ Models: Breach, Paste, Subscription, SubscribedDomain
- โ Breaches API: All 7 endpoints with full parameter testing
- โ Pwned Passwords: SHA-1, NTLM, padding, k-Anonymity
- โ Pastes API: Account paste retrieval
- โ Stealer Logs API: Email, website, and domain searches
- โ Subscription API: Status retrieval
- โ Main Interface: All convenience methods
Target coverage: 90%+
Publishing & Releases
This package uses GitHub Actions for automated publishing to PyPI via Trusted Publishing.
For Maintainers: Making a Release
Once PyPI Trusted Publishing is configured, releases are simple:
# Using the release script (recommended)
./release.sh 1.0.1
# Or manually:
# 1. Update version in setup.py
# 2. Commit: git commit -am "Bump version to 1.0.1"
# 3. Tag: git tag -a v1.0.1 -m "Release 1.0.1"
# 4. Push: git push origin main --tags
# 5. Create GitHub release (triggers auto-publish to PyPI)
The GitHub Actions workflow will automatically:
- โ Build the package
- โ Run tests
- โ
Publish to PyPI (with required approval via the
pypienvironment)
First-Time PyPI Setup
For the initial release, PyPI Trusted Publishing must be configured:
-
Create PyPI account (if needed):
- Go to https://pypi.org/account/register/
- Enable 2FA: https://pypi.org/manage/account/
-
Set up Trusted Publishing:
- Go to https://pypi.org/manage/account/publishing/
- Add a new publisher:
- PyPI Project Name:
haveibeenpwned-py - Owner:
dynacylabs - Repository:
haveibeenpwned - Workflow:
publish.yml - Environment name:
pypi
- PyPI Project Name:
- Click "Add"
-
Configure GitHub Environment Protection:
- Go to your GitHub repo โ Settings โ Environments
- Create environment:
pypi - Add required reviewers (for approval before publishing)
- Save protection rules
-
Make your first release:
./release.sh 1.0.0
Version Numbering
Follow Semantic Versioning:
- MAJOR (1.0.0 โ 2.0.0): Breaking changes
- MINOR (1.0.0 โ 1.1.0): New features, backward compatible
- PATCH (1.0.0 โ 1.0.1): Bug fixes, backward compatible
Release Checklist
Before releasing:
- All tests pass:
./run_tests.sh all - Coverage is >90%:
./run_tests.sh coverage - README.md is up-to-date
- Version number updated in
setup.py - CHANGELOG or release notes prepared
- No uncommitted changes
Target coverage: 90%+
API Reference
Complete Endpoint Coverage
Breaches (7 endpoints)
get_account_breaches(account)- Get all breaches for an accountget_all_breaches()- Get all breaches in the systemget_breach(name)- Get a single breach by nameget_latest_breach()- Get the most recently added breachget_data_classes()- Get all data classesget_domain_breaches(domain)- Get breached emails for a domainget_subscribed_domains()- Get all subscribed domains
Pastes (1 endpoint)
get_account_pastes(account)- Get all pastes for an account
Stealer Logs (3 endpoints)
get_stealer_logs_by_email(email)- Get domains by emailget_stealer_logs_by_website(domain)- Get emails by website domainget_stealer_logs_by_email_domain(domain)- Get aliases by email domain
Subscription (1 endpoint)
get_subscription_status()- Get subscription details
Pwned Passwords (no API key required)
is_password_pwned(password)- Check if password is compromisedsearch_password_hashes(prefix)- Search by hash prefix
API Key
Most endpoints require an API key. You can obtain one from: https://haveibeenpwned.com/API/Key
The Pwned Passwords API does not require an API key.
Test API Key
For testing, you can use the test API key 00000000000000000000000000000000 with test accounts:
hibp = HIBP(api_key="00000000000000000000000000000000")
# These test accounts work with the test key
breaches = hibp.get_account_breaches("account-exists@hibp-integration-tests.com")
breaches = hibp.get_account_breaches("spam-list-only@hibp-integration-tests.com")
breaches = hibp.get_account_breaches("stealer-log@hibp-integration-tests.com")
Rate Limiting
The API enforces rate limits based on your subscription level. When rate limited:
from haveibeenpwned import RateLimitError
try:
breaches = hibp.get_account_breaches("test@example.com")
except RateLimitError as e:
# Wait for the specified time
import time
time.sleep(e.retry_after)
# Retry the request
breaches = hibp.get_account_breaches("test@example.com")
Contributing
Contributions are welcome! Please ensure your contributions meet the following requirements:
Code Quality Standards
- All tests must pass: Run
./run_tests.sh allto verify all tests pass - Code coverage must be >95%: Run
./run_tests.sh coverageto check coverage - Follow existing code style: Match the formatting and patterns used in the codebase
- Add tests for new features: Both unit tests (mocked) and integration tests (live API calls where appropriate)
- Update documentation: Keep README.md and docstrings up to date
Testing Your Changes
Before submitting a pull request:
# Run all tests
./run_tests.sh all
# Check coverage (must be >95%)
./run_tests.sh coverage
# Run unit tests only (fast, no API key needed)
./run_tests.sh unit
# Run live integration tests (requires HIBP_API_KEY)
export HIBP_API_KEY="your-api-key-here"
./run_tests.sh live
Submitting Changes
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-new-feature) - Make your changes with appropriate tests
- Ensure all tests pass and coverage is >95%
- Commit your changes (
git commit -am 'Add new feature') - Push to the branch (
git push origin feature/my-new-feature) - Create a Pull Request
Disclaimer
This is an unofficial library and is not affiliated with Troy Hunt or Have I Been Pwned. Use responsibly and in accordance with the HIBP Acceptable Use Policy.
Resources
Project Structure
hibp/
โโโ hibp/ # Main package
โ โโโ __init__.py # Package exports
โ โโโ api.py # Main HIBP interface
โ โโโ breach.py # Breach endpoints
โ โโโ client.py # HTTP client
โ โโโ exceptions.py # Custom exceptions
โ โโโ models.py # Data models
โ โโโ passwords.py # Pwned Passwords API
โ โโโ pastes.py # Pastes endpoints
โ โโโ stealer_logs.py # Stealer logs endpoints
โ โโโ subscription.py # Subscription endpoints
โโโ tests/ # Test suite
โ โโโ conftest.py
โ โโโ test_api.py
โ โโโ test_breach.py
โ โโโ test_client.py
โ โโโ test_models.py
โ โโโ test_other_endpoints.py
โ โโโ test_passwords.py
โโโ .github/
โ โโโ workflows/
โ โ โโโ tests.yml # Automated testing
โ โ โโโ publish.yml # PyPI publishing
โ โ โโโ security.yml # Security scanning
โ โ โโโ dependency-updates.yml # Dependency monitoring
โ โโโ dependabot.yml # Automated dependency updates
โโโ setup.py # Package setup
โโโ requirements.txt # Dependencies
โโโ release.sh # Automated release script
โโโ run_tests.sh # Test runner
โโโ README.md # This file
Made with โค๏ธ for security and privacy
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file haveibeenpwned_py-1.0.2.tar.gz.
File metadata
- Download URL: haveibeenpwned_py-1.0.2.tar.gz
- Upload date:
- Size: 49.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6756579e7326e13e56988116255b819c5b3d4738f62abe8c0e673b90177dd1f0
|
|
| MD5 |
20a059fbb01f600be8bf3132b956f884
|
|
| BLAKE2b-256 |
322d45141e43cc15dd65cf0325f8abf139c87bfe1d2eac44f464f42bda0f3201
|
Provenance
The following attestation bundles were made for haveibeenpwned_py-1.0.2.tar.gz:
Publisher:
publish.yml on dynacylabs/haveibeenpwned-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
haveibeenpwned_py-1.0.2.tar.gz -
Subject digest:
6756579e7326e13e56988116255b819c5b3d4738f62abe8c0e673b90177dd1f0 - Sigstore transparency entry: 707781269
- Sigstore integration time:
-
Permalink:
dynacylabs/haveibeenpwned-py@106b36901cf06a288f194740f469f0db5ddf8daf -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/dynacylabs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@106b36901cf06a288f194740f469f0db5ddf8daf -
Trigger Event:
release
-
Statement type:
File details
Details for the file haveibeenpwned_py-1.0.2-py3-none-any.whl.
File metadata
- Download URL: haveibeenpwned_py-1.0.2-py3-none-any.whl
- Upload date:
- Size: 35.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc29319bf6c35aa76025cee853f3b958d3efd18e856ddaf0c7b7a8343a241b1f
|
|
| MD5 |
9ed0410e331e638226ca65ccd0c15c53
|
|
| BLAKE2b-256 |
3dc9cf61ed26c74be8a6c7fa5bfe79c387d6bf67825e8e6ced0b8e979a6c9d21
|
Provenance
The following attestation bundles were made for haveibeenpwned_py-1.0.2-py3-none-any.whl:
Publisher:
publish.yml on dynacylabs/haveibeenpwned-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
haveibeenpwned_py-1.0.2-py3-none-any.whl -
Subject digest:
cc29319bf6c35aa76025cee853f3b958d3efd18e856ddaf0c7b7a8343a241b1f - Sigstore transparency entry: 707781273
- Sigstore integration time:
-
Permalink:
dynacylabs/haveibeenpwned-py@106b36901cf06a288f194740f469f0db5ddf8daf -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/dynacylabs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@106b36901cf06a288f194740f469f0db5ddf8daf -
Trigger Event:
release
-
Statement type: