Have I Been Pwned (HIBP) is the internet's largest database of breached credentials. Over 14 billion compromised accounts indexed. And part of their API is completely free.
The Wake-Up Call
A SaaS company discovered their users were reusing breached passwords. Not because they were hacked — because they checked. They integrated HIBP's password API into their registration flow. 23% of new passwords had already been exposed in data breaches.
They added a simple warning: "This password appeared in a known data breach." Password reuse dropped by 80%.
What's Free vs Paid
| Feature | Cost | What You Get |
|---|---|---|
| Password check | Free | Check if a password hash exists in breaches |
| Breach list | Free | Get all known breaches and their details |
| Email check | $3.50/mo | Check if specific emails were breached |
The password API is the most useful — and it's 100% free.
Check If a Password Has Been Breached
HIBP uses a clever k-anonymity model. You send only the first 5 characters of the SHA-1 hash. Your actual password never leaves your machine.
\`python
import hashlib
import requests
def check_password(password):
"""Check if a password appears in known data breaches."""
# Hash the password
sha1 = hashlib.sha1(password.encode("utf-8")).hexdigest().upper()
prefix = sha1[:5]
suffix = sha1[5:]
# Send only the prefix (k-anonymity)
response = requests.get(
f"https://api.pwnedpasswords.com/range/{prefix}"
)
# Check if our suffix appears in the results
for line in response.text.splitlines():
hash_suffix, count = line.split(":")
if hash_suffix == suffix:
return int(count)
return 0
Test common passwords
passwords = ["password123", "hunter2", "correcthorsebatterystaple"]
for pwd in passwords:
count = check_password(pwd)
if count > 0:
print(f"⚠ '{pwd}' found in {count:,} breaches!")
else:
print(f"✓ '{pwd}' not found in any known breach")
`\
Output:
\
⚠ 'password123' found in 246,099 breaches!
⚠ 'hunter2' found in 17,043 breaches!
✓ 'correcthorsebatterystaple' not found in any known breach
\\
Get All Known Breaches
\`python
def get_all_breaches():
"""List all known data breaches."""
response = requests.get("https://haveibeenpwned.com/api/v3/breaches")
breaches = response.json()
print(f"Total known breaches: {len(breaches)}")
# Sort by number of accounts
breaches.sort(key=lambda b: b["PwnCount"], reverse=True)
print("\nTop 10 largest breaches:")
for b in breaches[:10]:
name = b["Name"]
count = b["PwnCount"]
date = b["BreachDate"]
types = ", ".join(b["DataClasses"][:3])
print(f" {name}: {count:,} accounts ({date}) — {types}")
get_all_breaches()
`\
Password Strength Checker
Combine HIBP with basic rules for a proper password validator:
\`python
import re
def validate_password(password):
"""Comprehensive password validation with breach checking."""
issues = []
# Length check
if len(password) < 12:
issues.append("Too short (minimum 12 characters)")
# Complexity
if not re.search(r"[A-Z]", password):
issues.append("No uppercase letters")
if not re.search(r"[a-z]", password):
issues.append("No lowercase letters")
if not re.search(r"\d", password):
issues.append("No numbers")
# Breach check (most important!)
breach_count = check_password(password)
if breach_count > 0:
issues.append(f"Found in {breach_count:,} data breaches!")
if issues:
print(f"❌ Password rejected:")
for issue in issues:
print(f" └─ {issue}")
return False
else:
print(f"✓ Password looks good!")
return True
validate_password("MyStr0ngP@ssw0rd2026!")
`\
Integration Ideas
- Registration forms — warn users about breached passwords before they sign up
- Security audits — check employee passwords against breach databases
- CI/CD — reject hardcoded passwords that appear in breaches
- Password managers — flag stored credentials that need rotation
Rate Limits
The password API has no authentication and no hard rate limit. HIBP asks for reasonable use — they suggest adding a hibp-api-key\ header for attribution, but it's not required for the password endpoint.
Building security tools? More free API tutorials on my GitHub.
Top comments (0)