Trust centre
Last updated 13 August 2026
Last updated 13 August 2026
Mirra puts a screen on a wall in somebody’s home or office, and often a camera and a microphone with it. That deserves a straight answer about how it is built rather than a page of badges.
Everything below describes what the software and the infrastructure actually do today. Where a control is partial, it says where it stops. What we do not have yet is the most useful section on this page, and it is deliberately not at the bottom.
Where it runs
Mirra runs on Amazon Web Services in eu-west-2 (London). The console and its APIs run on AWS App Runner; the socket relay that connects screens runs on ECS; the screen application is static files behind CloudFront. Customer data lives in one PostgreSQL database on Amazon RDS and in three S3 buckets.
- The database is not publicly reachable. It has no public address and is reached only from inside the private network.
- Storage is encrypted at rest — the RDS volume with AWS-managed keys, and every S3 bucket with SSE-AES256 by default.
- All three buckets have public access fully blocked at the account and bucket level — one holds photographs, one the wall-display application, one the inbound email used to invite a screen to a meeting. Nothing is served from a bucket directly.
- Photographs are read back through the application at an unguessable address. That address is not itself behind a sign-in, and it answers any origin, so that a wall display can put a photo in a plain image tag — see what we do not have yet, where this is set out properly.
- Automated database backups are retained for seven days, with point-in-time recovery inside that window.
- Everything that crosses the internet is HTTPS, and the console sends
Strict-Transport-Securitywith a one-year max-age. TLS terminates at the AWS edge, as it normally does — the last hop from there to the container runs inside AWS’s private network rather than under its own certificate.
How credentials are stored
Three different kinds of secret, deliberately handled three different ways.
- Your password is hashed with bcrypt (cost 10). It is never stored reversibly and never appears in an export.
- API keys are stored as SHA-256 hashes and compared in constant time. The key itself is shown once, when it is created; we cannot show it to you again, and neither can anyone who reaches the database. A fast hash is right here and wrong for a password — an API key is 32 bytes of randomness rather than something a person chose.
- Integration credentials — the Home Assistant token, Hive password, Spotify refresh token, Govee and Twinview keys — are encrypted with AES-256-GCM before they are written. A Home Assistant long-lived token controls somebody’s house; it must not sit in a database as readable text.
The encryption key is held in AWS Systems Manager Parameter Store and injected at run time. It is not in the database, not in the container image, and not in the source repository — so a copy of the database is not enough to read those credentials. Every other production secret is held the same way, including the database URL, the session signing key and the Stripe keys.
Three things about that are worth saying rather than leaving you to assume. Not every credential-shaped value is encrypted: webhook bearer tokens, the secret a screen uses to re-authenticate, and pairing codes are stored as they are. There is no key rotation — the key can be replaced, but nothing re-encrypts what was written under the old one. And credentials written before this encryption existed remain readable until they are next saved. It is one key for the whole service, held by AWS’s parameter store rather than by a hardware module.
Getting in
- Sessions are httpOnly, SameSite=Lax cookies, marked Secure in production, so page JavaScript cannot read them and another site cannot send them.
- Rate limits on the endpoints worth attacking, with real numbers: ten sign-in attempts per account per fifteen minutes, forty per source address over the same window (separate, so one shared address cannot lock a household out of its own account), five registrations an hour, twenty pairing attempts per ten minutes.
- Two levels of access: full, and a menus-only account for café and hospitality staff which is refused every page and every API route outside the menu section. Routes state the access they need in a line of code, so a route that has not made a claim fails closed.
- Single sign-on (OIDC) on Enterprise, against your own identity provider.
- An audit log of account-level changes — who did it, when, and what changed — written for every significant action and kept for a year by default. It records changes rather than reads, and it is not yet surfaced in the console: today you get it by asking us or by taking a data export.
What never leaves your building
Some of this is a privacy decision and some of it is simply how the product is built, but the effect is the same: the most sensitive things Mirra touches are never uploaded.
- Face recognition runs on the screen. It is optional, it is off unless you turn it on, and no image is uploaded for it. The portal is told a name, never a picture.
- Home Assistant is reached from the screen, not from us. Your Home Assistant server is on your own network and stays there — the screen talks to it directly over your LAN. The same is true of WLED controllers. It is why switching a light from the portal needs a screen to be online, and why the plan tells you so when none is.
- The microphone is not open. The assistant listens after it is summoned, not before.
The assistant
The assistant is optional, metered, and can be left switched off entirely. When it is used, the conversation is sent to Anthropic’s Claude via Amazon Bedrock (model eu.anthropic.claude-sonnet-4-6), through an EU inference profile, under our own AWS account and inside Europe. It does not go to a third-party AI vendor’s own API, and under AWS’s terms Bedrock does not use what is sent through it to train models.
What is sent is the conversation and the context needed to answer it — which can include household names, calendar entries, tasks and the state of connected devices. Transcripts are kept so you can read back what was said, and deleted after 90 days by default; you can shorten that or turn retention off. If the assistant searches the web, the query goes to Tavily; that happens only when a question actually needs it.
Who else sees your data
Every sub-processor below is either core to running the service or switched on by you. The optional ones send nothing until you connect them.
| Who | What reaches them | When |
|---|---|---|
| Amazon Web Services (eu-west-2) | Hosting, database, file storage, backups — everything | Always |
| AWS Bedrock (Anthropic Claude, EU) | Assistant conversations and the context needed to answer them | When the assistant is used |
| Stripe | Billing details. Card numbers go to Stripe directly and never reach us | Paid plans |
| Calendar access, via OAuth you grant and can revoke | If you connect a Google calendar | |
| Microsoft | Calendar and meeting-room access, via OAuth you grant | If you connect Microsoft 365 |
| Spotify | Playback state and control | If you connect Spotify |
| Govee | Light names and commands, through Govee’s cloud | If you connect Govee |
| Hive (British Gas) | Heating and hot-water state and commands | If you connect Hive |
| Twinview | Your own project’s tickets and issues, read back to the board widgets | If you connect Twinview |
| Tavily | The search query only | When the assistant searches the web |
| Open-Meteo | A location, for the forecast. No account data | Weather widgets |
There is no analytics or advertising tag anywhere in the product, signed in or signed out. Fonts are served from our own domain rather than fetched from Google, so loading a page does not tell anyone else that you did.
Your data, and getting it back
- Export — one file, on demand, without asking anyone: the household record, sign-ins, people, screens, scenes, schedule, albums, tasks, reminders, assistant transcripts, presence history, integrations, keys, webhooks, menus and the activity log. Password hashes, encrypted tokens and API key hashes are reported as existing but not handed back. Photograph bytes are listed with links rather than embedded. Floor plans are not currently in the file.
- Retention you set — assistant transcripts 90 days by default, presence history 30 days, the audit log a year. Each can be shortened, lengthened or switched off.
- Closing the account deletes it — screens, scenes, schedules, photographs, floor plans and the drawings imported into them, transcripts, presence, integrations, keys and the audit trail, with the stored files removed from storage rather than merely unlinked. What survives is what we are obliged to keep: records of payments already made.
The privacy policy sets all of this out in more detail, including the legal bases and the parts the software does not yet do.
What we do not have yet
Mirra is a young product built by a small team. These are the things a security reviewer will ask for and we do not have. They are here so you find them from us rather than from an assessment.
- No SOC 2 report and no ISO 27001 certificate. IThese are in progress. If your procurement requires one, contact us for progress.
- No multi-factor authentication on Mirra sign-in. If you need it today, use single sign-on on Enterprise and enforce MFA at your identity provider.
- No uptime commitment. We do not offer an SLA and there is no public status page.
- Mirra sends no email. Not for password resets, not for security alerts, not for invoices. It is a deliberate simplicity today rather than a feature we removed, but it has consequences you should know about: there is no password reset or account recovery flow — a forgotten password needs us. The one mailbox in the system is inbound only, for inviting a screen to a meeting..
- Tenant separation is enforced in application code, not by database row-level security. Every query is scoped by household through shared helpers, and access checks fail closed.
- Photograph and menu-image bytes are not behind a sign-in. They are addressed by an unguessable identifier so a wall display can render them in a plain image tag, and the bucket behind them is private — but anyone holding the address can fetch the image. Treat a photo URL as a secret.
- Cross-site request protection rests on the session cookie’s SameSite setting and on the API accepting only JSON bodies.
- API keys carry no scopes and no expiry.A key is full access to what that household’s API exposes, until you revoke it.
- A paired screen’s token is long-lived and cannot be rotated individually. Deleting the screen is the way to end its access, and the relay may hold an existing connection until the token expires.
- No checks on URLs the product is asked to fetch. Where you give Mirra an address — a Home Assistant server, a WLED controller, a webhook target — it is fetched as given, with no blocking of private or internal addresses.
- Mirra does not have an AWS account to itself.It shares one with other projects from the same team, in that account’s default network rather than an isolated one. Nothing crosses between them in software.
- Deleting is not always instant erasure. A deleted photograph can survive in bucket versioning, and anything deleted stays in database backups until they age out after seven days.
Reporting something
If you believe you have found a vulnerability, email security@twinassistant.com. Tell us what you found and how to reproduce it. We will acknowledge within two working days and tell you what we intend to do and roughly when.
We will not take legal action against anybody who reports a genuine problem in good faith, gives us reasonable time to fix it, and does not access, alter or delete other data while looking. Please do not run automated scanners against the live service — tell us instead and we will arrange a way to test.
For anything else — privacy requests, data questions, procurement paperwork — support reaches a person.