Skip to content
Inkstand

Security and data handling

Where the data sits, what leaves it, who can read it, and what the sub-processor list contains. Written to be pasted into an assessment.

Where it sits

One database instance, in Stockholm. The only content that leaves it is content a person pressed a button to send.

Deck generation, brand-guideline reading, AI compliance review and claim research each leave on a press. Carousels, brand kits, uploaded images and governance records never do.

The site itself is a static bundle on a CDN. It holds no customer data, sets no analytics cookie and loads no third-party script.

Your browser talks straight to one managed platform in Stockholm, inside the European Economic Area, with no application server of ours in between. Exactly one path leaves that boundary: the AI features, and only when a person presses one. It ends at a model provider that may sit outside the EEA.

your browser

The editor, the checker, the export

TLS, straight to the platform — no application server of ours in between

european economic area

Stockholm

  • Database
  • Authentication
  • File storage

one region · no second region to move to

the AI features, and only when a person presses one

a model provider

May sit outside the EEA

What is not here

No advertising network, session recorder, heatmap or browser autocapture runs on the site or in the product. Product telemetry, when enabled, is bounded and sent server-to-server; it does not add an analytics cookie or a third-party browser script.

Sign-in is a one-time link, or a Google or Microsoft Entra account, so no password is stored, reused or available to leak. Neither provider grants membership: that still comes from an invite redeemed against the address.

Who can read what

Isolation is asserted against a real database, in a rolled-back transaction, assuming the same role and identity claims the API assumes. A button hidden from a viewer is a courtesy; the policy is the control.

Administrator status cannot be granted from inside the product. It is seeded out of band, so privilege escalation is a deliberate act at the database.

A limited seat has no account-wide reach: it sees only the brands it holds a named grant on. A viewer reads and cannot comment or sign off — the policies refuse both.

Every table carries its own row-level policy, and every one of those policies asks the same shared membership function whether the caller holds a seat in the account that owns the row. The answer decides the result: rows in your own account are returned, and rows in any other account are returned as nothing at all rather than as an error.

every table carries a policy · among them

  • accounts
  • workspaces
  • projects
  • carousels
  • assets
  • templates
  • release records
  • generation audits
  • review links
  • brand grants

One shared membership function

asked by every policy above · keyed to your seat

returned

Rows in your own account

The seat you hold, and nothing inferred from the screen you asked from.

nothing at all

Rows in any other account

Not an error, and not a partial answer. Empty, on every table above.

Keys, headers and uploads

The browser bundle carries only the public key. The keys that bypass row-level policies, and the model-provider key, exist only in server-side functions.

Strict-Transport-Security preloaded, two-year max-age, with includeSubDomains; X-Content-Type-Options: nosniff; X-Frame-Options: DENY; Referrer-Policy: strict-origin-when-cross-origin; and a Permissions-Policy denying camera, microphone, geolocation and interest-cohort.

Uploads are allow-listed image types, 8 MB on images and 3 MB on fonts, into a private bucket, served through signed URLs that expire in an hour.

Brand import fetches a URL you give it, server-side, so it is treated as an attack surface. Non-HTTP schemes, private and link-local addresses, intranet names, unbounded bodies and redirect chains are refused.

What cannot be rewritten

Release records, generation audits and the ledger of overridden findings can be read and inserted, never deleted — for anyone, including the account owner, including us. They can be updated in exactly one way: a person’s name replaced with an erasure token, after that person has been erased, with every other column of the row unchanged and checked to be unchanged. That exception exists so a right-to-erasure request can be honoured without destroying the record.

4 of the 9 rule kinds are settled in code and call nothing. The other 5 need judgement — either because no pattern reaches them at all, or because a pattern finds the thing to check and cannot grade it — and every release record states whether that review ran. A rule the reviewer did not reach is recorded as such and never counted as passed. See what a result establishes.

Leaving

Content is kept until you delete it. Deleting an account cascades to its brands; a brand to its campaigns, posts, assets and generation records. Release records survive by design — their purpose is to evidence what was published.

Artwork exports as PNG and PDF, the compliance report as JSON. Nothing you make is held in a format only we can read.

The short answers

Sub-processors
The managed database and object-storage platform, the CDN, the model router and the transactional mail sender. No more than 16 runtime packages; two features were written in-house to keep a name off this list.
Training on your content
No.
Encryption
TLS in transit. Encryption at rest is provided by the managed platform; we operate no disks of our own.
Backups
Run by the managed database platform under our plan. Ask and you get the plan’s actual figures.
Penetration testing
None commissioned, and none scheduled. No independent test, no report to share.
Automated testing before release
more than 3,000 automated tests on the compliance and rendering logic, plus more than 230 isolation assertions run against a real database. Both run before anything ships. Neither is a substitute for the row above.
Data residency
Stockholm.
Session handling
Held in the browser and refreshed automatically. Removal takes effect in the database the moment membership ends, not at next sign-in.
Invites
32 random bytes, single use, fourteen-day expiry, bound to the invited address.