Security and user privacy are foundational pillars of BMI Stellar. This document defines the scope of our security commitments, how to report vulnerabilities, and the privacy/cryptographic architecture that protects user data.
- Supported Versions
- Reporting a Vulnerability
- Expected Response Timeline
- Scope
- Privacy Boundary
- Security Architecture
- Cryptographic Details
We actively maintain and provide security patches for the following versions:
| Version | Supported | Notes |
|---|---|---|
main branch |
Yes | Continuous rolling updates |
| Latest Release | Yes | Primary target for immediate security hotfixes |
| Older Releases | No | Please upgrade to the latest stable release |
We deeply appreciate responsible disclosure and take all reports seriously.
- Use the GitHub Security Advisories feature to report issues privately.
- Provide detailed steps to reproduce the vulnerability.
- Include environment details: browser, OS, Node/Bun version.
- If applicable, describe the potential impact (data exposure, privilege escalation, etc.).
Warning
Please do not disclose security vulnerabilities publicly (e.g., via standard GitHub issues, social media, or blog posts) until a patch has been released and users have had reasonable time to update.
For bugs that do not involve security vulnerabilities (e.g., visual glitches, incorrect calculations, accessibility issues), open a standard GitHub Issue.
Our maintenance team is committed to addressing security concerns promptly:
- Initial Acknowledgment: Within 48 hours of report submission.
- Triage & Assessment: Within 72 hours — we will confirm the vulnerability, assess severity, and communicate our planned response.
- Patch Development: Prioritized above all feature development. Critical vulnerabilities (data exposure, auth bypass) target a patch within 7 days. Lower-severity issues are scheduled for the next release.
- Cryptographic implementation flaws in backup encryption/decryption
- Cross-site scripting (XSS) or injection vulnerabilities
- Data leakage or unintended data transmission
- Authentication or authorization bypasses
- Service worker or PWA security issues
- Dependency vulnerabilities in production code
- Denial-of-service attacks against the Vercel-hosted demo
- Social engineering attacks
- Issues in development-only tools (DebugPanel, dev diagnostics)
- Theoretical vulnerabilities without a practical exploit
- Issues in third-party services (Vercel, GitHub) outside our control
BMI Stellar is local-first. BMI inputs, BMI history, goals, body-composition values, encrypted verifier data, and backup contents are stored and processed in the browser.
The hosted production demo may load Vercel Analytics and Speed Insights for aggregate product/performance telemetry. Those integrations must never receive BMI values, history records, passphrases, encryption keys, backup payloads, or decrypted import contents.
Users can explicitly export or share data:
- PNG share cards contain only the visible result information rendered into the image.
- Unencrypted exports are portable history backups and should be treated like sensitive personal files by the user.
- Encrypted exports protect backup contents with passphrase-derived encryption before download.
BMI Stellar is engineered with a strict Local-First, Zero-Trust model:
- Data Locality: Health metrics are computed and stored on the user's device. There is no account system and no app backend that stores BMI data.
- Export Encryption: Encrypted backups use AES-256-GCM authenticated encryption before download. Unencrypted export remains available for portability and is intentionally user-controlled.
- Key Derivation: We use Argon2id (the winner of the Password Hashing Competition) to derive encryption keys from user passphrases. The production parameters (64 MiB memory, 3 iterations, parallelism 1) follow OWASP 2023 recommendations and are highly resistant to GPU-based cracking.
- Zero Knowledge: Passphrases are never stored, cached, or transmitted. The passphrase verifier stored in IndexedDB is an AES-GCM ciphertext of a known plaintext — it can confirm a passphrase is correct but cannot be reversed to recover the passphrase.
- Integrity Verification: Every backup includes a SHA-256 checksum of the ciphertext. Import validates this checksum before attempting decryption, rejecting tampered or corrupted payloads.
Used for all new encryptions. Parameters follow OWASP 2023 recommendations.
| Parameter | Production | Test (CI) |
|---|---|---|
| Memory | 64 MiB (65536 KiB) | 1 MiB (1024 KiB) |
| Iterations | 3 | 1 |
| Parallelism | 1 | 1 |
| Salt length | 16 bytes (128-bit) | 16 bytes |
| Output length | 32 bytes (AES-256 key) | 32 bytes |
Implementation: @noble/hashes/argon2.js — pure JavaScript, no WASM, auditable source, minimal bundle.
Supported for importing backups created with older versions. Not used for new encryptions.
| Parameter | Value |
|---|---|
| Iterations | 600,000 |
| Hash function | SHA-256 |
| Salt length | 16 bytes (128-bit) |
| Field | Value |
|---|---|
| Format identifier | bmi-encrypted-v1 |
| Cipher | AES-256-GCM (authenticated) |
| IV length | 12 bytes (96-bit), random per encryption |
| Auth tag | 16 bytes (128-bit), handled by Web Crypto API |
| Ciphertext checksum | SHA-256, stored in meta.checksum |
| KDF auto-detection | kdf field: 'argon2id' or absent (legacy PBKDF2) |
When encryption is enabled, a known verifier string (BMI_STELLAR_VERIFIER_V1) is encrypted with the user's passphrase and stored in IndexedDB. The verifyPassphrase() function attempts decryption — a wrong passphrase causes AES-GCM auth tag mismatch, returning false. The passphrase itself is never stored anywhere.
Uses @zxcvbn-ts/core with @zxcvbn-ts/language-common dictionary for realistic strength scoring. Falls back to basic length/character-class heuristics if zxcvbn is unavailable.
- Never log passphrases, derived keys, verifier plaintext, decrypted backups, encrypted backup payloads, or raw health history.
- Do not weaken Argon2id/AES-GCM parameters without a security-focused PR and test coverage.
- Do not change the encrypted backup format without a compatibility plan.
- Treat service worker changes as security-sensitive because stale caches and update prompts can affect what users run.
If you identify a flaw in this cryptographic implementation, please report it immediately via the GitHub Security Advisories page.