- Python 69.1%
- C++ 30.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| scripts | ||
| tests | ||
| .gitignore | ||
| compose.prefix.yml | ||
| README.md | ||
Pwned Password Index
Pwned is a private, read-only service for checking whether a SHA-1 password hash appears in a set of leaked-password records. A caller sends a five-character hexadecimal hash prefix and receives the matching compressed range. The caller checks the remaining 35 characters locally.
The service never receives a password or complete hash. It is designed for use by trusted applications on a private network, not as a public endpoint.
Interface
Health
GET /health
Returns 200 with {"ok":true} when the process is ready.
Prefix range
GET /range/5BAA6
The path must contain exactly five hexadecimal characters. A successful response uses content type application/vnd.hanasand.pwned-prefix and contains a binary PWNPRF01 or PWNPRF02 envelope. It includes the source catalog and one or more pre-compressed index blocks. Clients decompress the block and compare the full hash suffix locally. The service does not count or remove duplicate records from a response.
Invalid requests return 400. An unreadable, malformed, or over-budget index range returns 503. Responses include Cache-Control: no-store and X-Content-Type-Options: nosniff.
The envelope layout and validation rules are implemented in scripts/serve-compact-index.py and scripts/compact_index.py. The API is intentionally small; it does not accept passwords, full hashes, arbitrary file paths, or general search expressions.
Privacy and limits
The five-character prefix is visible to the service and to systems that can observe its private-network traffic. It narrows the candidate set but does not make password recovery impossible in every threat model. The complete hash remains with the caller, which checks the returned range locally.
This protocol provides prefix-based disclosure, not private set intersection. Keep the service on a trusted network, avoid logging request paths, and describe the prefix disclosure accurately to users. The HTTP listener has no authentication of its own; network access controls are part of the deployment boundary.
Run locally
The index files are generated and maintained separately; they are not included in this source checkout. With the index files available at the configured paths and the external hanasand_hanasandnet Docker network present, start the service from this directory:
docker compose -f compose.prefix.yml up -d
curl -fsS http://127.0.0.1:8099/health
curl -sS -D - -o /tmp/pwned-range.bin http://127.0.0.1:8099/range/5BAA6
Compose binds port 8099 to host loopback and attaches the service to the private application network. The container runs read-only with dropped Linux capabilities, no privilege escalation, bounded memory and CPU, and read-only index mounts. Its stable network/container name is pwned.
The standard command serves compact-inventory/master.pwnidx plus the disjoint source overlay at compact-inventory/deduplicated/sources.pwnidx. These large data files must exist before the service starts. See scripts/compact-inventory.md for their format, verification, and maintenance procedures.
Data and operations
The compact index stores SHA-1 hashes in prefix-addressable blocks. The primary index and source overlay preserve source-file catalogs so responses can report the record's source. Input data is converted and verified before it is served; the runtime opens indexes read-only and does not modify them.
Check /health, container health, and service logs when diagnosing an outage. A successful range request depends on the requested block being valid and within the configured response and expansion limits. Large ranges require more transfer time than small ranges: the service returns the full compressed prefix bucket so callers can perform the suffix check without sending the complete hash.
Repository map
scripts/serve-compact-index.py: private HTTP service.scripts/compact_index.py: compact index reader and format checks.scripts/compact-inventory.md: data format, verification, and maintenance.compose.prefix.yml: container and network configuration.
The repository contains service code and inventory tooling. The production index data is stored and managed separately from Git.