
A user-friendly consumer privacy audit tool that scans for and provides active recommendations on how to better protect your digital identity.
You are viewing version 2, the working demo
Version 2- Demo Version (Working)
HTML | CSS | Javascript | Node.js | Express | Passport.js | MongoDB
Features
Role
Solo UX Engineer
The Why
I designed a privacy-conscious data breach lookup experience to explore how a web application could interface with the Have I Been Pwned (HIBP) API while minimizing the exposure and retention of sensitive user information.
Because the HIBP API requires a paid subscription for the k-anonymity range endpoint I planned to use, the portfolio version of this project uses mock data rather than making live API requests. This allows visitors to interact with the experience and understand the intended functionality without requiring a production API subscription or handling real user email addresses.
The case study documents the planned production architecture, including the API integration, privacy model, rate limiting, and optional caching strategy.
The Concept
The experience allows a user to enter an email address and receive a summary of data breaches associated with it.
The primary technical challenge wasn't simply displaying breach results. It was designing the experience so that an eventual production implementation could minimize the amount of personally identifiable information being transmitted, stored, and logged.
The planned implementation uses HIBP's k-anonymity API rather than its direct email lookup endpoint.
With k-anonymity, the user's complete email address would not be sent to HIBP. Instead, the backend would calculate a SHA-1 hash of the normalized email address and send only the first six characters of that hash to HIBP.
HIBP would return a range of matching hash suffixes. My backend would then compare the user's complete hash against those results and return only the matching breach information.
This means the application could determine whether an email address appeared in known breaches without sending the email address itself to HIBP.
Why Mock Data?
The live HIBP integration is intentionally not enabled in the portfolio version.
The k-anonymity range API is part of HIBP's paid API offering, so I chose not to build the portfolio experience around a live paid API subscription.
Instead, the interactive prototype uses mock breach data that represents the type of response the production application would receive.
This approach allows visitors to:
Enter an example email address.
Experience the intended lookup flow.
See how breach information would be presented.
Explore the application's states and interactions.
Understand the planned backend architecture.
Read about the privacy and security considerations without the portfolio site processing real breach lookups.
The mock implementation is therefore a representation of the intended product behavior, not a live connection to HIBP.
Planned Technical Architecture
The production architecture would separate the frontend from the HIBP integration. I would host the Express backend on Railway and keep the HIBP API key in a server-side environment variable. The frontend would never have access to the API key. This is important because putting an authenticated API key into browser-side JavaScript would expose the key to anyone using the application.

Architecture Diagram in Excalidraw
Privacy by Design
Privacy was a significant consideration in the planned architecture.
The backend would temporarily receive the email address because it needs the address to calculate its hash, but the application would avoid unnecessarily persisting it.
The email address would not be intentionally written to application logs, and it would not be stored as a raw value in the database.
I would also avoid placing the email address in a URL, using a POST request instead: POST /api/check with the email address contained in the request body. This reduces unnecessary exposure through URLs, browser history, analytics, and server access logs.
Filtering HIBP's Response
The k-anonymity API returns multiple results for a requested hash prefix.
Most of those results belong to other email addresses that happen to share the same six-character SHA-1 prefix.
The backend therefore has an important responsibility: it must identify the suffix corresponding to the user's complete hash and immediately discard the other results. I would not store the complete range response in a database because those non-matching results relate to other addresses and are unnecessary for the user's request.
Planned Caching
Caching is intentionally not part of the initial prototype.
If caching were introduced in a production implementation, I would use Supabase to store the relevant breach result rather than the complete HIBP range response.
The cache would never contain the raw email address.
Instead, I would generate a privacy-preserving cache key using an HMAC:
HMAC-SHA256( secret cache key, normalized email )
The secret would remain on the backend as an environment variable. A conceptual cache record could look like:
cache_key
result
created_at
expires_at
This would allow the application to determine whether it already has a recent result without maintaining a database of users' email addresses.
A short cache lifetime could also reduce unnecessary API requests while keeping the cached information relatively ephemeral.
Rate Limiting
The planned backend would also implement application-level rate limiting.
For an initial implementation, I would use a simple per-IP limit, such as approximately 10 requests per minute.
If a visitor exceeds the limit, the API would return a 429 Too Many Requests response rather than continuing to send requests to HIBP. This provides a basic layer of protection against abuse and helps prevent unnecessary consumption of the application's HIBP API quota.
The backend would also handle HIBP's own rate limits and respect the Retry-After response when applicable. For the initial version, an in-memory rate limiter would be sufficient. If the application eventually scaled across multiple backend instances, I would consider using Redis so that rate-limit state could be shared between instances.
Security Considerations
The planned production implementation would keep the following principles in place:
HIBP API credentials remain server-side.
Email addresses are not intentionally logged.
Raw email addresses are not stored in the database.
HIBP receives only the six-character hash prefix.
Non-matching HIBP results are immediately discarded.
User requests are rate limited.
API errors do not expose internal implementation details.
Secrets are stored as environment variables rather than committed to source control.
HTTPS is used for communication between the client and backend.
The portfolio version intentionally separates the interactive experience from the production API architecture.
Portfolio prototype
Frontend —> Mock data —> Breach results
The mock implementation allows visitors to interact with the product without a paid HIBP API subscription.
Planned production implementation
Frontend ➡️ Express / Railway ➡️ SHA-1 + k-anonymity ➡️ HIBP API ➡️ Local suffix matching ➡️ Filtered breach results
This distinction is important: the portfolio experience demonstrates the product and interaction design, while the case study documents how I would approach the real backend integration.
This project pushed me to think beyond simply consuming an API. The most interesting part was understanding how the API's data model affects the application's architecture. HIBP's k-anonymity approach changes where the privacy-sensitive processing needs to happen: the backend has to calculate the user's complete hash and perform the final match locally rather than simply forwarding an email address to a third-party service.
It also reinforced the importance of treating API credentials, logging, caching, and rate limiting as part of the product architecture rather than as afterthoughts.
Even though the demo implementation uses mock data, the project gave me an opportunity to design and document a realistic path from an interactive prototype to a privacy-conscious production implementation.
