Claude
Skills
Sign in
โ† Back

haveibeenpwned

Included with Lifetime
$97 forever

HaveIBeenPwned API Documentation - Check if email accounts or passwords have been compromised in data breaches

Backend & APIs

What this skill does


# Have I Been Pwned API Skill

Expert assistance for integrating the Have I Been Pwned (HIBP) API v3 to check for compromised accounts, passwords, and data breaches. This skill provides comprehensive guidance for building security tools, breach notification systems, and password validation features.

## When to Use This Skill

This skill should be triggered when:
- **Checking if emails/accounts appear in data breaches** - "check if this email was pwned"
- **Validating password security** - "check if password is in breach database"
- **Building breach notification systems** - "notify users about compromised accounts"
- **Implementing password validation** - "prevent users from choosing pwned passwords"
- **Querying stealer logs** - "check if credentials were stolen by malware"
- **Integrating HIBP into authentication flows** - "add breach checking to login"
- **Monitoring domains for compromised emails** - "track breaches affecting our domain"
- **Working with the HIBP API** - any questions about authentication, rate limits, or endpoints

## Quick Reference

### 1. Basic Account Breach Check

```python
import requests

def check_account_breaches(email, api_key):
    """Check if an account appears in any breaches"""
    headers = {
        'hibp-api-key': api_key,
        'user-agent': 'MyApp/1.0'
    }

    url = f'https://haveibeenpwned.com/api/v3/breachedaccount/{email}'
    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        return response.json()  # List of breach objects
    elif response.status_code == 404:
        return []  # Account not found in breaches
    else:
        response.raise_for_status()

# Usage
breaches = check_account_breaches('[email protected]', 'your-api-key')
print(f"Found in {len(breaches)} breaches")
```

### 2. Password Breach Check (k-Anonymity)

```python
import hashlib
import requests

def check_password_pwned(password):
    """Check if password appears in breaches using k-anonymity"""
    # Hash password with SHA-1
    sha1_hash = hashlib.sha1(password.encode('utf-8')).hexdigest().upper()
    prefix = sha1_hash[:5]
    suffix = sha1_hash[5:]

    # Query API with first 5 characters only
    url = f'https://api.pwnedpasswords.com/range/{prefix}'
    response = requests.get(url)

    # Parse response for matching suffix
    hashes = (line.split(':') for line in response.text.splitlines())
    for hash_suffix, count in hashes:
        if hash_suffix == suffix:
            return int(count)  # Times password appears in breaches
    return 0  # Password not found

# Usage
count = check_password_pwned('password123')
if count > 0:
    print(f"โš ๏ธ Password found {count} times in breaches!")
```

### 3. Get All Breaches in System

```python
import requests

def get_all_breaches(domain=None):
    """Retrieve all breaches, optionally filtered by domain"""
    url = 'https://haveibeenpwned.com/api/v3/breaches'
    params = {'domain': domain} if domain else {}

    headers = {'user-agent': 'MyApp/1.0'}
    response = requests.get(url, headers=headers, params=params)

    return response.json()

# Usage - no authentication required
breaches = get_all_breaches()
print(f"Total breaches: {len(breaches)}")

# Filter by domain
adobe_breaches = get_all_breaches(domain='adobe.com')
```

### 4. Monitor for New Breaches

```python
import requests
import time

def monitor_latest_breach(check_interval=3600):
    """Poll for new breaches every hour"""
    last_breach_name = None

    while True:
        url = 'https://haveibeenpwned.com/api/v3/latestbreach'
        headers = {'user-agent': 'MyApp/1.0'}
        response = requests.get(url, headers=headers)

        if response.status_code == 200:
            breach = response.json()
            if breach['Name'] != last_breach_name:
                print(f"๐Ÿ†• New breach: {breach['Title']}")
                print(f"   Accounts affected: {breach['PwnCount']:,}")
                last_breach_name = breach['Name']

        time.sleep(check_interval)
```

### 5. Domain-Wide Breach Search

```python
import requests

def search_domain_breaches(domain, api_key):
    """Search for all breached emails in a verified domain"""
    headers = {
        'hibp-api-key': api_key,
        'user-agent': 'MyApp/1.0'
    }

    url = f'https://haveibeenpwned.com/api/v3/breacheddomain/{domain}'
    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        results = response.json()
        # Returns: {"alias1": ["Adobe"], "alias2": ["Adobe", "Gawker"]}
        total_affected = len(results)
        print(f"Found {total_affected} compromised accounts")
        return results
    else:
        response.raise_for_status()
```

### 6. Check Pastes for Account

```python
import requests

def check_pastes(email, api_key):
    """Check if email appears in any pastes"""
    headers = {
        'hibp-api-key': api_key,
        'user-agent': 'MyApp/1.0'
    }

    url = f'https://haveibeenpwned.com/api/v3/pasteaccount/{email}'
    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        pastes = response.json()
        for paste in pastes:
            print(f"{paste['Source']}: {paste['Title']}")
            print(f"  Date: {paste['Date']}")
            print(f"  Emails found: {paste['EmailCount']}")
        return pastes
    elif response.status_code == 404:
        return []  # No pastes found
```

### 7. Enhanced Password Check with Padding

```python
import hashlib
import requests

def check_password_secure(password):
    """Check password with padding to prevent inference attacks"""
    sha1_hash = hashlib.sha1(password.encode('utf-8')).hexdigest().upper()
    prefix = sha1_hash[:5]
    suffix = sha1_hash[5:]

    headers = {'Add-Padding': 'true'}
    url = f'https://api.pwnedpasswords.com/range/{prefix}'
    response = requests.get(url, headers=headers)

    # Parse response, ignore padded entries (count=0)
    for line in response.text.splitlines():
        hash_suffix, count = line.split(':')
        if hash_suffix == suffix and int(count) > 0:
            return int(count)
    return 0
```

### 8. Handle Rate Limiting

```python
import requests
import time

def api_call_with_retry(url, headers, max_retries=3):
    """Make API call with automatic retry on rate limit"""
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)

        if response.status_code == 429:
            # Rate limited - wait and retry
            retry_after = int(response.headers.get('retry-after', 2))
            print(f"Rate limited, waiting {retry_after}s...")
            time.sleep(retry_after)
            continue

        return response

    raise Exception("Max retries exceeded")
```

### 9. Check Subscription Status

```python
import requests

def get_subscription_info(api_key):
    """Retrieve API subscription details and limits"""
    headers = {
        'hibp-api-key': api_key,
        'user-agent': 'MyApp/1.0'
    }

    url = 'https://haveibeenpwned.com/api/v3/subscription/status'
    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        info = response.json()
        print(f"Plan: {info['SubscriptionName']}")
        print(f"Rate limit: {info['Rpm']} requests/minute")
        print(f"Valid until: {info['SubscribedUntil']}")
        return info
```

### 10. Stealer Logs Search

```python
import requests

def check_stealer_logs(email, api_key):
    """Check if credentials appear in info stealer malware logs"""
    headers = {
        'hibp-api-key': api_key,
        'user-agent': 'MyApp/1.0'
    }

    url = f'https://haveibeenpwned.com/api/v3/stealerlogsbyemail/{email}'
    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        domains = response.json()  # List of website domains
        print(f"Credentials found for {len(domains)} websites")
        return domains
    elif response.status_code == 404:
        return []

Related in Backend & APIs