Skip to main content

Version Python Versions

pwnedpasswords is a small Python wrapper and command line utility that lets you check if a passphrase has been pwned using the Pwned Passwords v2 API. All provided password data is k-anonymized before sending to the API, so plaintext passwords never leave your computer.

From https://haveibeenpwned.com/API/v2#PwnedPasswords:

Pwned Passwords are more than half a billion passwords which have previously been exposed in data breaches. The service is detailed in the launch blog post then further expanded on with the release of version 2. The entire data set is both downloadable and searchable online via the Pwned Passwords page.

Installation

pwnedpasswords is available for download through PyPi. You can install it right away using pip.

pip install pwnedpasswords

Usage

import pwnedpasswords

pwnedpasswords.check("testing 123")
# Returns 1

Security Note

No plaintext passwords ever leave your machine using pwnedpasswords.

How does that work? Well, the Pwned Passwords v2 API has a pretty cool k-anonymity implementation.

From https://blog.cloudflare.com/validating-leaked-passwords-with-k-anonymity/:

Formally, a data set can be said to hold the property of k-anonymity, if for every record in a released table, there are k − 1 other records identical to it.

This allows us to only provide the first 5 characters of the SHA-1 hash of the password in question. The API then responds with a list of SHA-1 hash suffixes with that prefix. On average, that list contains 478 results.

People smarter than I am have used math to prove that 5-character prefixes are sufficient to maintain k-anonymity for this database.

In short: your plaintext passwords are protected if you use this library. You won't leak enough data to identity which passwords you're searching for.

Notes

pwnedpasswords automatically checks if your provided input looks like a SHA-1 hash. If it does, it won't do any further processing. If it looks like plain text, it'll automatically hash it before sending it to the Pwned Passwords API.

If you'd like to provide an already-hashed password as input to pwnedpasswords, you don't need to do anything--pwnedpasswords will detect that it looks like a SHA-1 hash and won't hash it again before sending it to the range endpoint.

pwnedpasswords.check("b8dfb080bc33fb564249e34252bf143d88fc018f")

Likewise, if a password looks like a SHA-1 hash (i.e., matches the regex [0-9a-fA-F]{40}) but is actually a user-provided password, set plain_text to True, so that the library knows to hash it before sending it to the API.

pwnedpasswords.check("1231231231231231231231231231231231231231", plain_text=True)

Details

check

This is the preferred method. By default, the check method uses the https://api.pwnedpasswords.com/range/ endpoint, which is k-anonymous.

pwnedpasswords.check("mypassword")
# 250616

If you'd like to force pwnedpasswords to use the search endpoint instead (https://api.pwnedpasswords.com/pwnedpassword/), set the anonymous parameter to False.

pwnedpasswords.check("password", anonymous=False)
# 46628605

You might want to do this if you'd prefer faster response times, and aren't that worried about leaking passwords you're searching for over the network.

If you'd like direct access to the search and range endpoints, you can also call them directly.

range

pwnedpasswords.range("098765")
# outputs a dictionary mapping SHA-1 hash suffixes to frequency counts

Command Line Utility

pwnedpasswords comes bundled with a handy command line utility.

$ pwnedpasswords 123456password
2452
$ python -m pwnedpasswords 123456password
2452

Output is simply the number of entries found in the Pwned Passwords database.

If you'd like to prevent input from appearing in your history, specify the --stdin argument to provide input via stdin (h/t to @tveastman for requesting this).

$ pwnedpasswords --stdin
mypassword
250616

For help, just provide -h as a command-line argument.

$ pwnedpasswords -h
usage: pwnedpasswords [-h] [--verbose] [--plain-text] (--stdin | password)

Checks Pwned Passwords API to see if provided plaintext data was found in a
data breach.

positional arguments:
  password      The password or hashed password to search for.

optional arguments:
  -h, --help    show this help message and exit
  --verbose     Display verbose output.
  --plain-text  Specify that the provided input is plain text, even if it
                looks like a SHA-1 hash.
  --stdin       Read provided input from stdin.

Note

The CLI returns an exit code equal to the base-10 log of the result count, plus 1. If there are no matches in the API, the exit status will be 0. While returning the base-10 log might seem odd, note that most systems require exit status codes to be in the range 0-127, and I wanted the status code to provide some indication for severity. log(N) seemed to be a good tradeoff. The exit status is log(N)+1 since there are plenty of matches in the database with 1 match.

If you'd like to take a look under the hood to make sure things are working as they should, set the --verbose flag.

$ pwnedpasswords 123456password --verbose
INFO:pwnedpasswords.pwnedpasswords:https://api.pwnedpasswords.com/range/5052C
INFO:pwnedpasswords.pwnedpasswords:Entry found
240

Thanks

Special thanks to Troy Hunt for collecting this data and providing this service.

Authors

See also

django-pwnedpasswords-validator, a validator that checks user passwords against the Pwned Passwords API using this library.

License

Apache License, Version 2.0. See LICENSE for details.

Metadata

Release files for pwnedpasswords 3.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pwnedpasswords 3.1.0
File Size Uploaded
pwnedpasswords-3.1.0.tar.gz 16.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pwnedpasswords 3.1.0
File Interpreter ABI Platform
pwnedpasswords-3.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 30.4 kB

Release files / pwnedpasswords-3.1.0.tar.gz

Download URL pwnedpasswords-3.1.0.tar.gz
Size 16.4 kB
Tags Source
SHA-256 checksum
How to use checksums
55beb6116e3ec419ecd0d6835b25af9924a3ddd728eebc0ac60943d056fc34b8
BLAKE2b-256 checksum
How to use checksums
c9c9e5ff71cc6c0b0f18ae4ae74b183c23b0a46c69dff59df210694e6fd8184b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release files / pwnedpasswords-3.1.0-py3-none-any.whl

Download URL pwnedpasswords-3.1.0-py3-none-any.whl
Size 14.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e8fbaece2d74bb03eaebe215fd69b96d05630bae86566518582ef790cbf4a546
BLAKE2b-256 checksum
How to use checksums
e58b29b5b2e384e6b7f7e669ebe30c47eb85dc2744f0a1e38c7067375313b995
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release history Release notifications | RSS feed

This release

3.1.0 This release

2 release files

3.0.0

3 release files

2.0.0

1 release file

1.2.1

1 release file

1.2.0

1 release file

1.1.1

1 release file

1.1.0

1 release file

1.0.9

1 release file

1.0.7

1 release file

1.0.6

1 release file

1.0.5

1 release file

1.0.4

1 release file

1.0.3

1 release file

1.0.2

1 release file

1.0.1

1 release file

1.0.0

1 release file

0.1.13

1 release file

0.1.12

1 release file

0.1.11

1 release file

0.1.10

1 release file

0.1.9

1 release file

0.1.8

1 release file

0.1.7

1 release file

0.1.6

1 release file

0.1.5

1 release file

0.1.4

1 release file

0.1.3

1 release file

0.1.2

1 release file

0.1.1

1 release file

0.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page