The 50-Line Cryptographic Sieve: Inside nodebb-plugin-pwned-passwords
How a minimalist forum plugin uses k-Anonymity and a controversial fail-open architecture to verify passwords without ever transmitting them.

I no longer think the accounts I banned were alts of a spammer setting up a voting ring, I think they were all compromised in a breach and a spammer with a credential-stuffing script hit us. It's even possible the entire process was automated.
- The plugin implements k-Anonymity by sending only the first five characters of a SHA-1 hash to the Have I Been Pwned API.
- A strict 2500ms timeout and try-catch block enforce a fail-open strategy that prioritizes forum availability over absolute security blocking.
- Modern NIST guidelines favor checking passwords against known breach databases rather than enforcing complex character requirements.
- The lightweight API approach contrasts sharply with privacy-maximalist architectures that require downloading entire 100GB breach databases locally.
The k-Anonymity Illusion
Most developers assume that checking a password against a breached database requires sending the password, or its full hash, to a third party. This assumption is fundamentally incorrect. The nodebb-plugin-pwned-passwords repository demonstrates how to execute this verification without compromising privacy, using a surprisingly simple implementation of k-Anonymity.
The mechanism relies on a cryptographic sleight of hand. When a user registers or changes their password, the plugin generates a SHA-1 hash of the plaintext string. It then truncates this hash, transmitting only the first five characters as a prefix to the Have I Been Pwned (HIBP) API. The external service returns a list of all known compromised password hashes that share those exact first five characters.
The magic happens entirely on the local server. The plugin takes the remaining 35 characters of the user's hash and scans the returned list. If a match is found, the password is known to be compromised. Because the API never receives the full hash, it cannot mathematically reverse-engineer the user's password. This provides mathematical anonymity in just a few lines of JavaScript.
The Credential Stuffing Epidemic
The shift toward checking breach databases is driven by the reality of modern account takeovers. Complex password rules involving capital letters and symbols have proven ineffective against automated credential stuffing attacks, where attackers use massive datasets of previously exposed username and password combinations to breach unrelated accounts.
This exact scenario recently forced the Lobsters community to implement similar breach checks. Older, inactive accounts were being compromised and used to post spam, highlighting that forum security is only as strong as a user's password hygiene across the broader internet.
The Ethics of Failing Open
In lib/pwned.js, the developer made a specific architectural choice that sparks debate among security professionals. The external API call to HIBP is wrapped in a try-catch block with a strict 2500ms timeout. If the request fails or times out, the function returns false, indicating the password is not pwned.
catch (error) {
winston.warn(`[plugins/pwned-passwords] Failed to check password: ${error}`);
}
return false;
This is a deliberate fail-open strategy. It prioritizes forum availability over strict security enforcement. If the third-party API goes down, users are not locked out of creating accounts or resetting their passwords. It acknowledges that a forum plugin should not create a single point of failure for the entire application's registration flow.
The Two Paths: API vs. Airgap
The lightweight API integration chosen by NodeBB stands in stark contrast to the approach favored by high-privacy platforms. Projects with strict data sovereignty requirements often opt to download the entire HIBP database locally to ensure no network requests are ever made during the authentication process.
| Feature | API (NodeBB Plugin) | Airgap (Local Database) |
|---|---|---|
| Storage Requirement | Minimal (Bytes) | 100GB+ (Full Dataset) |
| Network Latency | Up to 2500ms limit | 0ms (Local execution) |
| Privacy Guarantee | Mathematical k-Anonymity | Absolute Airgap |
| Maintenance Burden | Zero | Background job orchestration |
While the local database method provides ultimate privacy, it introduces significant operational overhead. The NodeBB plugin proves that with clever cryptography, developers can achieve nearly identical security outcomes with a fraction of the infrastructure.