Skip to content

Security: mmmpym/flashpaper

Security

SECURITY.md

Security Policy & Limitations

Supported Versions

Version Supported
main ✅
< main ❌

We actively maintain and support the latest code on the main branch. Security updates and patches are applied directly to main.

Reporting a Vulnerability

If you discover a security vulnerability or potential privacy exposure in Flashpaper, please report it to us privately rather than creating a public issue or discussion.

  • Email: flashpaper@nxtconsultinggroup.com
  • Response Target: We aim to acknowledge receipt of all vulnerability reports within 72 hours and provide a resolution or mitigation timeline as quickly as possible.
  • Scope: Please include steps to reproduce, relevant HTTP request/response payloads, and proof-of-concept code where applicable.

Known Limitations

Flashpaper is designed with extreme privacy and zero-database volatile RAM storage in mind. However, operating within standard Node.js and web environments introduces inherent technical limitations that users and self-hosters should understand:

1. Agent API Endpoints (/api/agent/*)

While the web browser UI uses true zero-knowledge client-side encryption (where the AES-256 decryption key is contained strictly in the browser location hash fragment #key and never transmitted to the server), the AI Agent endpoints (POST /api/agent/vault) perform encryption server-side. Plaintext submitted via agent REST or MCP tools is processed briefly in server memory before being converted to ciphertext. It is ephemeral and stored strictly in volatile RAM, but it is not zero-knowledge with respect to the server process.

2. Best-Effort Memory Zeroing

Flashpaper executes explicit buffer zeroing routines (buf.fill(0)) whenever a secret is revealed, manually burned, or expired by its TTL. However, standard V8 JavaScript garbage collection and memory allocation abstractions mean full plaintext erasure from the engine heap cannot be strictly guaranteed at the operating system or hardware level.

3. Webhook SSRF Guard

The destruction notification webhook engine includes SSRF protections that validate targeted URLs against hostnames and private IP ranges. The current guard validates hostnames directly prior to dispatch rather than performing authoritative DNS resolution mapping. Self-hosters accepting untrusted webhook destinations should ensure network-level egress filtering if deploying in multi-tenant environments.

4. Single Instance Exactly-Once Burn Semantics

Flashpaper relies on an in-memory V8 Map data structure to store secrets without a database. To ensure strict, race-condition-free, exactly-once burn semantics and prevent double-reveal attacks, Flashpaper must be deployed as a single server process or single container instance (min-instances=1, max-instances=1). Distributing across multiple instances without sticky routing or a shared memory cluster would prevent unified state checks.

5. Browser Extensions & Client Environment

The decryption key lives in the URL fragment (#) and is processed by in-page JavaScript. Any browser extension with page access can read location.hash or the decrypted DOM, and a compromised client device defeats client-side encryption entirely. Flashpaper cannot protect secrets on an untrusted browser or machine.

6. Supply Chain

All cryptography uses the browser's native Web Crypto API — no third-party cryptographic libraries. However, the application does ship UI dependencies (React, i18next, etc.); a compromised upstream package could in principle tamper with the page. Mitigations: minimal dependency surface, open source code for auditing, and self-hosting from a pinned, reviewed commit.

7. Transport & Metadata

A burn link sent over a messaging channel is only as safe as that channel until the secret is claimed: whoever sees the full link first can claim (and thereby burn) the secret — the 404-on-second-claim serves as tamper evidence, not prevention. Split delivery (sending the vault ID and the key over two different channels) mitigates this. The application retains no accounts and no content beyond burn/expiry, but hosting infrastructure (e.g. Cloud Run) keeps standard request logs at the platform level.

8. Passphrase Mode (KDF v2)

An optional passphrase is layered on top of the random 256-bit URL-fragment key (PBKDF2-SHA256, 100k iterations, XOR-combined with the fragment key) — it is an additional factor, never a replacement. Both the link and the passphrase are required to decrypt. Vaults created before 2026-07-29 used a weaker scheme in which the passphrase-derived key replaced the fragment key; those vaults expired within 24 hours of the fix.

9. Destructive Actions Require Proof of Key Possession

/reveal, /burn, and /failed-passphrase require a SHA-256 digest of the fragment key (computed client-side; the key itself is never sent). Knowing only a vault ID cannot consume views, trigger the passphrase lockout, or burn a secret. The digest is not invertible and is only known to parties who already hold the link.

10. Rate-Limit Source Address

Client addresses for rate limiting are read from X-Forwarded-For only when a trusted proxy is known to be in front (Cloud Run's K_SERVICE, or TRUST_PROXY_HEADER=true), and then only the right-most entry the platform appended. Directly exposed containers use the socket address, so a spoofed header cannot reset a bucket. Self-hosters placing Flashpaper behind their own proxy should set TRUST_PROXY_HEADER=true.

11. Agent API Keys

When AGENT_API_KEYS is unset (the default), no X-Api-Key is accepted — requests fall back to anonymous per-IP limits. Arbitrary keys are never honoured as a higher quota.


Acknowledgements

Findings 5–11 above were prompted by an external review from MtlSnk, disclosed privately via the contact address in this file. Reviews of this kind are welcome and credited.

There aren't any published security advisories