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.

6 min read • View on GitHub • More from plutoniummod

An industrial pipe system with a smaller bypass channel routing fluid around a broken, leaking main pressure gauge.
The fail-open architecture ensures user registration continues even if the external security API goes offline.

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.

@pushcx, MEMBER · lobsters/lobsters #1478
Key Takeaways

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 prefix/suffix verification flow ensures the full hash never leaves the local server.

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.

Hedcut portrait of pushcx

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

A split composition showing a postal worker checking the first three digits of a zip code on the left, and a forklift dumping a massive library of heavy ledgers onto a single desk on the right.
The k-Anonymity API approach sends a tiny fragment of data, whereas the airgapped approach requires downloading the entire database.

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.

FeatureAPI (NodeBB Plugin)Airgap (Local Database)
Storage RequirementMinimal (Bytes)100GB+ (Full Dataset)
Network LatencyUp to 2500ms limit0ms (Local execution)
Privacy GuaranteeMathematical k-AnonymityAbsolute Airgap
Maintenance BurdenZeroBackground 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.