Data, credentials, and trust boundaries
Know what stays local and what does not.
IdeaForge is a static browser application with no account, sync service, analytics, or application backend. Sessions stay in browser storage. Model context and optional audio go directly to the provider you choose. Exports and backups leave only when you explicitly create, copy, download, or share them.
Data map
| Data | Where IdeaForge keeps it | When it leaves | How to remove it |
|---|---|---|---|
|
Sessions Opening statement, questions, answers, draft text, coverage, facts, tags, status, and synthesis |
Plain structured records in this origin's IndexedDB. | Relevant context is sent to the selected model provider for each generated question; the wrap-up sends the material needed to synthesise the final document. Export, copy, share, and backup create user-controlled copies. | Delete an idea in the library, or clear this site's browser data. Deleting an exported file is a separate operating-system action. |
| Inference and transcription keys |
One AES-GCM encrypted credential payload in IndexedDB, with a
non-extractable wrapping CryptoKey stored beside it.
|
Attached only to requests for the selected inference or transcription provider. Keys are excluded from session backups and Markdown exports. | Use Forget my key, clear site data, and revoke the key at the provider when compromise or reuse is a concern. |
| Server address and model choices | In the encrypted credential payload, per provider, although these values are not secret. | Used to address a loopback model server, and to name which model each request asks for. They are sent only to the provider already selected. | Forget my key clears the whole saved keyring. |
| Device preferences | Plain localStorage. This includes the hands-free finish word and whether hands-free mode was enabled. | Not sent by IdeaForge as interview data. | Change the setting, or clear this site's browser data. |
| Recorded audio | Held temporarily in browser memory when record-and-transcribe is used; it is not added to the session database. | Sent directly to the selected Groq or OpenAI transcription endpoint. With browser recognition, processing behaviour is controlled by the browser. | The app releases the recording after transcription. Provider-side retention is governed by that provider's account and policy. |
| Static application shell | Same-origin JavaScript, CSS, icons, manifest, and HTML in Cache Storage for installation and offline use. | Cache entries are public application files, not sessions, keys, provider requests, or responses. | Browser site-data controls can remove the service worker and Cache Storage. A new cache version also removes the previous IdeaForge shell cache. |
| Backups and exports | Files or clipboard/share-sheet content outside browser storage after you create them. | A backup contains all active and archived sessions. A Markdown export contains one idea's generated document and transcript. Neither contains API keys. | Delete or secure the resulting file or shared copy wherever it was sent. |
Network boundary
Model and transcription traffic travels from the browser to the configured provider;
it does not transit an IdeaForge server. Hosted inference is allowlisted to Anthropic,
OpenAI, Groq, and OpenRouter. Local inference is allowed only on
localhost and 127.0.0.1, on any port. A typed arbitrary
remote model URL is rejected before a request is made.
The current application HTML also loads its stylesheet and font files from Google Fonts. Those asset requests do not contain an IdeaForge API key or interview payload. There are no remote scripts, analytics libraries, or package dependencies. The guide pages use only the repository's local stylesheet and system fonts.
Provider requests use credentials: "omit", so browser cookies are not
included. The provider still receives the API credential and the prompt or audio
required to perform the selected operation. Provider logging, retention, training,
abuse monitoring, and account controls are outside IdeaForge's control; evaluate
them before submitting sensitive material.
What credential encryption protects
On first save, IdeaForge generates a 256-bit AES-GCM key with Web Crypto. The key is
marked non-extractable and stored as a CryptoKey in IndexedDB. The
credential keyring is serialised, encrypted with a fresh IV, and stored as
ciphertext. The raw API key is not written to disk as plaintext.
A non-extractable key can be used for encryption and decryption by this origin, but Web Crypto will not export its raw bytes. This improves the result of device theft, profile-directory inspection, or a copied disk: the credential payload is not a readable API key file.
MDN documents
storing CryptoKey objects in IndexedDB
and the meaning of the
extractable property.
What it cannot protect
A malicious script already running as the IdeaForge origin could call the same decryption and request functions as the legitimate app. Browser-side encryption cannot make a secret unavailable to code that must legitimately use it. It also does not protect an unlocked browser from a person who can operate the page, a compromised browser or operating system, or the provider account after a key is sent.
The controls that address that risk are structural:
- The application has no runtime package dependencies, no third-party scripts, and no build pipeline that injects code into the browser bundle.
-
Its Content Security Policy defaults to denying resources, allows scripts and
workers only from the app's own origin, and tightly limits
connect-srcto known providers and loopback. - Images are restricted to the app origin and data URLs, and HTML form submission is disabled.
- Custom model addresses are loopback-only, so a free-text field cannot silently create a new remote exfiltration destination.
- The service worker ignores cross-origin requests and every non-GET request, so provider calls carrying credentials never enter Cache Storage.
The browser behaviour behind these controls is documented by MDN's
Content Security Policy guide
and
connect-src reference.
What the offline cache contains
The service worker pre-caches the application shell and uses stale-while-revalidate for same-origin GET requests. This lets a previously loaded app open without a network connection. When no model is reachable, the interview can continue with built-in questions and records that degraded source in the session.
- Only same-origin GET requests are considered for caching.
- Provider and transcription requests are cross-origin POSTs and are ignored.
- The public guide is explicitly excluded from the app-shell fetch handler.
-
A navigation can fall back to cached
index.html; a missing non-page resource returns an offline response rather than a provider-shaped success. - Cache names are versioned. Activating a new shell removes older IdeaForge caches together, reducing mixed-version module graphs.
Cache Storage is separate from IndexedDB. Removing a stale app-shell cache need not delete sessions, while clearing all site data normally removes both. Back up before using broad browser reset controls. MDN's service-worker guide explains the underlying lifecycle.
Session retention, deletion, and recovery
Sessions are stored only on the current browser profile and origin. There is no cloud copy to restore after site data is cleared, the profile is reset, or the browser evicts storage. IdeaForge requests persistent storage when an interview starts or a backup is imported, but the browser makes the final decision.
- Install the app when practical; browsers often give installed applications more durable storage treatment.
- Use Back up ideas before moving devices or clearing site data.
- Treat the JSON backup as sensitive. It excludes keys and preferences, but contains the full interview library in plaintext.
- Treat every Markdown download, clipboard copy, and share-sheet destination as a new copy outside IdeaForge's control.
- Avoid editing the same idea in two tabs. There is no multi-tab reconciliation; the last saved version wins.
IndexedDB's persistence model is described in MDN's IndexedDB reference. For backup and library operation, see Ideas library.
Safe key practice
- Create a separate, scoped key for IdeaForge rather than using a broad personal or production credential.
- Prefer an expiry, usage cap, project boundary, or provider-side budget limit where the provider offers one.
- Never paste a key into a shared Claude artifact. Inside a Claude viewer, select Claude (this viewer), which needs no key.
- On a borrowed or shared device, use Forget my key before leaving, then revoke the credential at the provider if another person may have used it.
- Never include an API key, session backup, or sensitive transcript in a public bug report. Revoke first if a key has been exposed.
Report a security problem privately
Use GitHub private vulnerability reporting for anything that can exfiltrate a stored key, execute script in the page, alter what is sent to a provider, or cross an origin's storage boundary. Include the browser, exact origin, impact, and reproduction steps, but never include a live credential.
Implementation references
IndexedDB stores and persistence are defined in
src/store/db.js.
Credential encryption, migration, masking, and deletion are in
src/store/secrets.js.
Session persistence is in
src/store/sessions.js,
and key-free backup serialisation is in
src/core/backup.js.
The application CSP and outbound host list are in
index.html.
Cache scope and exclusions are in
sw.js.
The repository's maintained threat model and disclosure route are in
SECURITY.md.