Passchek
A privacy-first CLI tool for checking whether a password has appeared in known data breaches using Troy Hunt's Pwned Passwords API and the k-anonymity model.
Passchek securely checks passwords against the Have I Been Pwned Pwned Passwords API without ever sending the full password, or even the full SHA-1 hash, over the network.
The project is intentionally designed so that users can quickly audit the full source code themselves. Since real passwords and user trust are involved, the implementation follows strict engineering principles:
Design Principles
-
Conciseness The code stays as short as possible while preserving readability. No unnecessary layers, abstractions, or dead code.
-
Clarity A novice Python developer should be able to understand the whole program in under a minute. The structure is intentionally simple, PEP 8 compliant, and self-explanatory.
-
Leanness Every function, import, and constant must justify its existence. Anything non-essential is removed.
-
Embeddability The core breach-check logic is trivially reusable as a small importable function for CI/CD, scripts, web backends, or other automation.
-
Professional suitability The codebase follows production-grade engineering expectations: clear control flow, minimal side effects, strong typing, predictable behavior, robust error handling, and idiomatic Python.
-
Security Password exposure risk is minimized through hidden prompt input, reduced plaintext copies, no logging, no unnecessary I/O, local suffix matching, and careful hashing flow.
-
Independence Passchek uses only the Python standard library and targets Python 3.9+.
-
Speed Response parsing uses early exits, minimal allocations, efficient iteration, and reduced memory copies for the fastest possible standard-library implementation.
These principles make it easy for users to personally verify that the application behaves safely.
Features
- Secure password breach checks using the k-anonymity protocol
- Check single or multiple passwords
- Read passwords from stdin and shell pipes
- Numeric-only output for scripting
- SHA-1 prefix/suffix output without network access
- Fast early-exit response parsing
- Python 3.9 through 3.14 support
- Modern PyPI package installation
- Zero third-party runtime dependencies
How It Works
-
Hash the password with SHA-1
-
Split the hash into:
- first 5 characters as prefix
- remaining 35 characters as suffix
-
Send only the prefix to the API
-
Compare suffixes locally
-
Return the breach count
The full password never leaves the local machine.
Installation
From PyPI
python3 -m pip install --upgrade passchek
Or for the current user only:
python3 -m pip install --user passchek
Verify installation
passchek --version
Expected output:
Passchek v0.2.3
From source
git clone https://github.com/edyatl/passchek.git
cd passchek
python3 -m pip install .
Note: pip search is no longer supported by PyPI. Use pip show passchek or passchek --version instead.
Usage
Usage:
passchek [options] [PASSWORD ...]
Arguments:
PASSWORD One or more passwords to check.
If omitted, Passchek reads from prompt or stdin.
Options:
-h, --help Show help and exit
-n, --num-only Output only breach count numbers
-p, --pipe Read passwords from stdin / shell pipe
-s, --sha1 Print SHA-1 hash as prefix/suffix and exit
-v, --version Show Passchek version
Examples
Interactive prompt
$ passchek
Enter password:
This password has appeared 3912816 times in data breaches.
Numeric output only
$ passchek -n
Enter password:
3912816
SHA-1 tuple mode
$ passchek -s
Enter password:
('B1B37', '73A05C0ED0176787A4F1574FF0075F7521E')
Multiple passwords
$ passchek -n qwerty ytrewq qazwsx random_password
3912816
33338
505344
0
Pipe mode
$ cat passwords.txt | passchek -np
21
8
0
0
457
Security Notes
The safest way to use Passchek is interactive prompt mode:
passchek
This avoids shell history leakage and keeps input hidden.
Avoid passing real passwords as command-line arguments:
passchek my-secret-password
Shell history may store plaintext values.
Prefer:
- interactive prompt
- stdin pipe
- secret injection from secure automation environments
Windows
Install Python 3.9+ from:
https://www.python.org/downloads/windows/
Then install:
py -m pip install passchek
Run:
passchek
Changelog
v0.2.3 (2026-04-10)
A major refactoring and modernization release focused on maintainability, packaging, typing, and Python 3.14 readiness.
Added
- Python 3.9+ built-in generics support
- package-style versioning via
passchek._version.__version__ - improved MANIFEST and PyPI packaging flow
- better CLI version and help formatting
- comprehensive type hints in source and tests
- linter, formatter, and pre-commit configuration
Changed
- refactored
main()into smaller focused units - replaced legacy URL helpers with
_APIconstant and f-strings - optimized response parsing with
splitlines()andpartition() - early exit on first suffix match
- modernized packaging from
setup.pytopyproject.toml - improved SHA-1 handling with
usedforsecurity=True
Fixed
- corrected password whitespace stripping
- improved pipe newline handling
- better empty-password test behavior
- more robust urllib error handling
- consistent non-zero CLI exit codes
Contributing
Contributions are welcome.
Areas especially appreciated:
- security review
- performance review
- code simplification
- packaging improvements
- test coverage
Repository:
https://github.com/edyatl/passchek
Acknowledgements
Thanks to Troy Hunt for the Pwned Passwords API.
Thanks to James Ridgway for the original shell-script inspiration.
Author
Yevgeny Dyatlov
GitHub: https://github.com/edyatl
License
MIT License
Copyright (c) 2020-2026 Yevgeny Dyatlov
See LICENSE for details.
Release files for passchek 0.2.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| passchek-0.2.3.tar.gz | 155.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| passchek-0.2.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 164.1 kB
Release files / passchek-0.2.3.tar.gz
| Download URL | passchek-0.2.3.tar.gz |
|---|---|
| Size | 155.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f12e9ef3ccd6843d8c9967d6f5dde567e7e59b8bb95ebc8772beb4bf431390b2
|
|
BLAKE2b-256 checksum How to use checksums |
de9f3f2b02bb7910d610975d70898467efe2c60fa3dc8416cf489c16713b56e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 10, 2026.
Transparency logRelease files / passchek-0.2.3-py3-none-any.whl
| Download URL | passchek-0.2.3-py3-none-any.whl |
|---|---|
| Size | 8.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d0fc71292f4acb425e1c4dcfce7c876650599c60da3c6be1b24160cc55dc63fb
|
|
BLAKE2b-256 checksum How to use checksums |
a61983f9c9f971feaf20ad292a3473b0a24660bda28607e60c569248ae9a8eb9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 10, 2026.
Transparency log