DEV Community

Alex Spinov
Alex Spinov

Posted on

Have I Been Pwned Has a Free API — Check If Any Email Was in a Data Breach

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
Enter fullscreen mode Exit fullscreen mode

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}")
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)