Reclaiming your story

Security and privacy for your Instagram export

Processing a ZIP of your entire Instagram history comes with concrete threats. This is the engineering posture: harden parsing against ZIP bombs/path traversal, XSS/prototype pollution, worker DoS, and the split-key crypto envelope for the opt-in sync tier.

P3 is "who should hold this file and how to verify that claim". This is the concrete threat model and the engineering that answers it: ZIP bombs/path traversal, XSS/prototype pollution, worker DoS, and the sync tier's crypto envelope.

Threat model

Processing untrusted archives requires defense-in-depth: archive extraction, JSON/HTML parsing, string handling, and any optional network paths (which are opt-in only). The design treats every byte in the ZIP as untrusted.

Archive extraction hardening

  • ZIP bombs / resource exhaustion. Archive entries are streamed with size limits and entry count caps; decompression ratio checks prevent zip-bombs. Paths are normalized.
  • Path traversal. Entries are resolved against an extraction root; symlinks/traversal (.., absolute paths) are rejected to prevent writing outside the sandbox.

Parsing hardening

  • Prototype pollution. When merging untrusted objects (e.g. string_map_data), keys like __proto__, constructor, prototype are filtered. Assignments use Object.defineProperty and only known-safe fields are written where applicable (see personal parser).
  • XSS / HTML injection. HTML parsing is used in controlled contexts; any rendered content is escaped/normalized. Text is repaired for mojibake but not executed as code.
  • Malformed inputs. JSON parse errors are caught per file; HTML parsing failures are swallowed safely; unknown shapes are ignored rather than crashing the worker.
  • Resource limits. Large archives are processed incrementally; the parser avoids deep unbounded recursion where practical and caps work per file.

Runtime isolation

  • Web Worker. Parsing runs in a Web Worker to keep the UI responsive and to isolate CPU-heavy work. Worker messages are bounded.
  • DoS in worker/UI. Bounded queues, entry caps and time/size budgets prevent a single pathological file from blocking the app indefinitely.
  • CSP posture. CSP reports are console-only, bounded, deduped and discarded.

Crypto envelope (opt-in sync tier)

For the optional, opt-in profile sync: data is wrapped in a crypto envelope with split-key custody (2-of-4: {A server, B device, C recovery codes, D email escrow}) so no single party has the full key material to decrypt alone. Media is never stored. Messages synced only under explicit opt-in. Retention is instant erase with 30-day grace. This is off by default and requires explicit configuration.

Principle of least trust

Local-first by default. Any networked features are strictly opt-in, gated by configuration, and designed so the archive contents are never uploaded unless the user has explicitly opted into a feature that requires it - and even then, only under the constraints above.

How does the app defend against ZIP bombs?

Extraction uses size/entry caps and decompression ratio checks; traversal is blocked. Processing is bounded and incremental.

What about prototype pollution in archive JSON?

Untrusted keys are filtered (__proto__, constructor, prototype) and controlled assignment paths are used (e.g. Object.defineProperty) in merge points.

Is the sync tier on by default?

No. It is opt-in only, uses split-key custody, never stores media, and requires explicit configuration. Local mode remains the default.

Why run parsing in a Web Worker?

For isolation, responsiveness, and to enforce bounded work against untrusted input.

Sources of truth

  • SECURITY.md - security posture and controls.
  • AGENTS.md - local-first default, claim layer opt-in, CSP report behavior (console-only, bounded, deduped, discarded), no AI/tracker defaults.
  • Sync tier design (profile sync): split-key 2-of-4, no media stored, messages only under explicit opt-in, instant erase + 30-day grace (documented in profile sync plan; this post states the engineering posture).
Security and privacy for your Instagram export — LMKFR Blog