Pricing P2P Encrypted Chat Desktop App Browser Extension
Upload a file

Security Architecture Whitepaper

v1.2 — Feb 2026

Published by FileShot.io — Security ModelOpen-source crypto library

Abstract. FileShot.io is a browser-based file sharing service built on a zero-knowledge architecture. Files are encrypted client-side using AES-256-GCM before leaving the browser. Decryption keys are never transmitted to or stored on FileShot servers. This document describes the cryptographic primitives, key management strategies, streaming encryption protocol, data flows, server-side architecture, and threat model underpinning the service.

Contents

  1. Design goals & threat model
  2. Cryptographic primitives
  3. Key management: link-key mode vs. password mode
  4. Streaming chunked encryption protocol
  5. Upload & download data flows
  6. Server-side architecture & what the server sees
  7. Data residency & infrastructure
  8. Transport security
  9. Threat model & mitigations
  10. Known limitations
  11. Independent verification

1. Design goals & threat model

FileShot is designed primarily to protect file confidentiality: the contents of a file should be inaccessible to anyone who does not hold the decryption key, including the file-sharing infrastructure itself.

Primary goals

  • Zero-knowledge storage: the server stores only ciphertext. No decryption key ever reaches the server.
  • Client-side encryption: all cryptographic operations (key generation, encryption, decryption) happen inside the user's browser using the Web Crypto API.
  • Standards-based primitives: use only well-reviewed, hardware-accelerated cryptographic algorithms available in window.crypto.subtle.
  • Key isolation via URL fragment: keys encoded in the #fragment portion of URLs are not sent in HTTP requests and therefore do not appear in server logs.
  • Forward secrecy per file: each file uses a unique, randomly generated symmetric key (link-key mode) or a freshly derived key with a unique random salt (password mode).

Threat model — protected against

  • Server-side database compromise (attacker obtains stored blobs — gets only ciphertext)
  • Server-side log inspection (keys are never in HTTP request paths or headers)
  • Passive network interception (HTTPS + key-in-fragment prevents plaintext exposure)
  • Server operator curiosity (design prevents even infrastructure staff from accessing file contents)

Threat model — not designed to protect against

  • Endpoint compromise (malware on uploader's or downloader's device)
  • Browser extension attacks that intercept Web Crypto API calls
  • Sharing a link & passphrase with an unauthorized party
  • Side-channel attacks against the browser's Web Crypto implementation

2. Cryptographic primitives

All operations use the W3C Web Crypto API (window.crypto.subtle) — the same API used by password managers, banking apps, and enterprise security products in modern browsers. No third-party cryptographic libraries are used for symmetric encryption.

Property Value Notes
Cipher AES-GCM Authenticated encryption — integrity & confidentiality in one pass
Key length 256 bits AES-256; brute-force infeasible with current and projected computing
IV (nonce) 96 bits (12 bytes) GCM standard; generated fresh per chunk via crypto.getRandomValues
GCM auth tag 128 bits (16 bytes) Mandatory — decryption fails if ciphertext is tampered with
KDF (password mode) Argon2id memory: 64 MB · iterations: 2 · parallelism: 1 · 32-byte salt
KDF salt 128 bits (16 bytes) Generated via crypto.getRandomValues per upload; stored with ciphertext
RNG source crypto.getRandomValues / crypto.subtle.generateKey OS-seeded CSPRNG; not Math.random()
Key encoding Base64URL (RFC 4648 §5) URL-safe, no padding; embedded in #fragment as #k=<key>

3. Key management: link-key mode vs. password mode

FileShot supports two zero-knowledge encryption modes, which differ in how the decryption key is managed.

3.1 Link-key mode (default)

In link-key mode, a random 256-bit AES-GCM key is generated entirely inside the browser using crypto.subtle.generateKey. The key is never set by the user and never derived from a password.

  1. Browser calls crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, true, ["encrypt","decrypt"])
  2. Key is exported as raw bytes and encoded as base64url
  3. File is encrypted with this key (see —4§4 for streaming protocol)
  4. Encrypted file is uploaded to the server; key is never sent
  5. Share link is constructed as https://fileshot.io/d/<fileId>#k=<base64url-key>
  6. The #fragment is processed entirely by the recipient's browser — it is never included in HTTP requests to the server

Key isolation: Because the key lives exclusively in the URL fragment, it does not appear in server access logs, proxy logs, CDN logs, or Referer headers (browsers strip fragments before sending Referer). The server has no cryptographic material to decrypt the file.

3.2 Password mode

In password mode, the user sets a passphrase. The encryption key is derived from that passphrase — it is never stored anywhere, not even in the URL fragment.

  1. User enters a passphrase in the browser
  2. A 256-bit random salt is generated: crypto.getRandomValues(new Uint8Array(32))
  3. Argon2id (memory: 64 MB, iterations: 2, parallelism: 1) derives a 256-bit AES-GCM key from passphrase + salt
  4. File is encrypted with the derived key; salt is stored with (but separate from) the ciphertext
  5. The passphrase is never sent to the server; neither is the derived key
  6. Recipients enter the passphrase; the browser re-derives the identical key from passphrase + stored salt

Password strength matters. Argon2id with 64 MB memory cost makes offline dictionary attacks extremely expensive even on GPU/ASIC hardware, but does not make weak passphrases strong. Use a passphrase of at least 12 characters drawn from a large character set.

3.3 Password + server-side access gate (dual protection)

When password protection is enabled, FileShot also stores a bcrypt hash of the password server-side. This adds a server-side gate: the server refuses to serve the encrypted blob unless the downloader first proves knowledge of the password (without the server learning the password). This is in addition to — and not a replacement for — the client-side Argon2id encryption. Even if someone bypasses the server gate, they still need the password to decrypt the file.

4. Streaming chunked encryption protocol

FileShot uses a custom streaming container format (FSZK) to support large file encryption without loading the entire file into memory. Standard large-file transfers use a streaming pipeline.

Container format (magic: FSZK, version 1)

  • 4-byte magic: FSZK (ASCII)
  • 1-byte version: 0x01
  • 4-byte uint32 header length (little-endian)
  • Variable-length JSON header (metadata: original filename, MIME type, salt, chunk size, total chunks)
  • Concatenated encrypted chunks

Per-chunk encryption

  • Default chunk size: 512 KB
  • Each chunk is encrypted independently with AES-256-GCM
  • Each chunk receives a unique 96-bit IV generated via crypto.getRandomValues
  • IV is prepended to the encrypted chunk bytes (IV | ciphertext | auth-tag)
  • Auth tag is 128 bits — any bit-flip in any chunk is detected and decryption is aborted

Why unique IVs per chunk matter: AES-GCM is an authenticated cipher, but reusing an IV with the same key is catastrophic — it exposes the plaintext and invalidates authentication. By generating a fresh random IV for every chunk of every file, FileShot eliminates IV-reuse risk even across millions of uploads.

5. Upload & download data flows

Upload flow (link-key mode)

  1. User selects file(s) in browser
  2. Browser generates 256-bit AES-GCM key via crypto.subtle.generateKey
  3. File is chunked (512 KB chunks) and encrypted in a streaming pipeline — never fully loaded into memory
  4. Encrypted container (FSZK) is uploaded to api.fileshot.io over HTTPS
  5. Server stores the encrypted blob and returns a unique file identifier
  6. Browser constructs share URL: https://fileshot.io/d/<id>#k=<base64url-key>
  7. Key is displayed only in the browser — never logged, transmitted, or stored on the server

Download flow

  1. Recipient opens the share URL; browser extracts key from #fragment (never sent to server)
  2. Browser fetches the encrypted blob from api.fileshot.io
  3. Browser decrypts chunk-by-chunk, verifying the GCM auth tag on each chunk
  4. Decrypted plaintext is streamed to disk — server at no point handles plaintext

6. Server-side architecture & what the server sees

The FileShot backend is a Node.js API (api.fileshot.io). The following table summarizes exactly what the server has access to for zero-knowledge uploads:

Data Server access? Notes
File contents (plaintext) ✗ Never File is encrypted before upload; server stores only ciphertext
Decryption key ✗ Never Key is in URL fragment (not in HTTP requests) or never leaves the browser (password mode)
User passphrase ✗ Never Only a bcrypt hash is stored server-side for access gating
Encrypted blob (ciphertext) ✓ Yes Required for storage and delivery
Original filename ✓ Yes Stored in encrypted container header (also encrypted)
Argon2id salt ✓ Yes Public by design — salt is not secret; it prevents rainbow-table attacks
File size, expiry, download count ✓ Yes Operational metadata required for quotas and access controls
Uploader IP (security logs) ⚠ Limited Security event logs only; not linked to file contents; see Privacy Policy

7. Data residency & infrastructure

FileShot's primary storage and compute infrastructure is located in the United States. Files and metadata are stored on servers operated and controlled exclusively by FileShot.io — no third-party cloud storage providers (such as AWS S3 or Google Cloud Storage) handle your file data.

Infrastructure components

  • File storage: FileShot-operated servers, United States
  • CDN & DDoS protection: Cloudflare — global edge network; Cloudflare receives only encrypted ciphertext in transit
  • TLS termination: at Cloudflare edge (TLS 1.2 minimum; TLS 1.3 preferred); traffic between Cloudflare and origin is also encrypted
  • Payment processing: Stripe — no card data touches FileShot servers

Data retention

  • Files are automatically deleted at the expiration time set by the uploader (minimum 1 hour, default 180 days)
  • Free accounts: files deleted after expiry with no recovery
  • Pro accounts: configurable expiry including never-expire
  • On-demand deletion: uploaders with accounts can delete files immediately from their dashboard

EU users: FileShot does not currently offer EU data residency. If your organization requires data to remain within the European Economic Area, this service may not meet your compliance requirements without additional contractual arrangements. Contact us at admin@fileshot.io to discuss your requirements.

8. Transport security

  • HTTPS everywhere: all FileShot properties enforce HTTPS; HTTP requests are redirected
  • HSTS: Strict-Transport-Security: max-age=31536000; includeSubDomains prevents protocol downgrade attacks
  • TLS version: TLS 1.2 minimum; TLS 1.3 preferred
  • HPKP: not used (deprecated across browsers)
  • Certificate authority: Cloudflare-issued certificates, renewed automatically
  • Mixed-content protection: the application makes no HTTP requests to load resources

9. Threat model & mitigations

Attack vector Mitigation
Database breach (files)Attacker obtains only ciphertext. No key → no decryption.
Server-side log inspectionKey is in URL fragment — never included in HTTP requests; not in access logs.
Brute-force on password modeArgon2id — memory-hard 64 MB per attempt; bcrypt server gate (rate-limited); unique 32-byte salt per file.
Passive network sniffingAll traffic over TLS 1.2+. Fragment stripped by browser before request.
CDN / proxy log inspectionFragment is never transmitted in HTTP requests — not available to Cloudflare.
Ciphertext tamperingAES-GCM 128-bit auth tag. Any modification causes decryption to fail and throw.
Link guessing / enumerationFile IDs are high-entropy tokens. Rate limiting on API endpoints.
XSS via preview / filenameActive content treated conservatively; CSP headers enforced; filenames escaped.

10. Known limitations

  • No content-based malware scanning: all uploads are zero-knowledge encrypted, meaning the server only receives ciphertext. Content-based AV scanning cannot inspect encrypted blobs. Abuse prevention relies on file-type enforcement, metadata analysis, and behavioral signals.
  • Fragment security depends on recipient behavior: if a recipient pastes the full URL (including fragment) into a chat, email, or document, the key is exposed to whatever reads that message.
  • Post-quantum considerations: AES-256-GCM is considered quantum-resistant for symmetric encryption (Grover's algorithm halves key strength to 128 effective bits, still secure). Argon2id is not post-quantum, but key derivation is symmetric — the primary exposure would be harvest-now-decrypt-later scenarios, which are mitigated by unique salts and short file expiry.
  • Browser supply-chain trust: if the FileShot web application is compromised (e.g., via a malicious JavaScript injection), client-side encryption could be bypassed. This risk is common to all browser-based cryptographic applications and is not unique to FileShot.
  • No formal audit has been conducted (as of this document's publication date). The crypto library is open-source for independent review.

11. Independent verification

FileShot's zero-knowledge encryption library is open source and independently verifiable:

Try FileShot Security Model Responsible Disclosure View crypto source