Mimir

Security model

How Mimir protects you, in one place: who it defends against, the rules that do it, and what's left. The user-facing details are on Tools and safety and Privacy; this page is the overview, for users who want to know and for contributors who must keep these rules when changing the code.

Who it defends against #

It does not defend against someone with your computer account, your server's admin token, or your AI account: those are you.

The rules #

Your things stay in your chats. Email, calendar, meetings and the bots' computer are offered only in a chat with you alone (never a group, where a reply goes to everyone). A chat paired by someone else is a guest's: it gets the guest's own memory and the web, and none of your email, calendar, meetings, saved logins, browser, tool servers or computer. You are whoever paired first on each messaging app.

Outside content changes what's allowed. Once a conversation has read outside content, it's marked, and anything that changes data asks you first, even if its rule says allow. The mark sticks for the rest of the conversation ("Start fresh" ends it). It also carries over:

Reading stays allowed after outside content, except when the read itself would carry your data out. That covers:

What you mark sensitive keeps its data in. In Settings → Sensitive sources you can mark a tool server (your bank's), one of its tools, or a chat's memory as sensitive; servers named like banking or health are suggested, never marked for you. Once a conversation or routine has read from one (a tool call, a memory search, or its memories in the bot's instructions), everything that goes out asks, even if its rule says allow, and the card starts with why ("This run read from bank, which you marked sensitive"):

Like outside content, it never becomes "always", "all like this" or part of a plan, it sticks to the conversation until "Start fresh", and it carries over to tasks handed to other bots. It can only make things stricter.

Some actions always ask. Sending an email and making a bot ask every time, whatever the rules say, as their own kind of approval: never "always", never "all like this". An email is sent only if all of it fits on the card you approve (recipient first), at most 20 a day from a chat, with addresses checked so nothing can add a hidden recipient. A new bot gets at most the tools of the bot that made it, and can't make bots itself.

Private data stays in private chats. Email, calendar and meeting tools exist only in a chat with you alone, never in a group (where the reply goes to everyone) or incognito (where nothing may be kept).

What's learned stays yours to accept. Bots never change your memory's rules, your permissions, tool grants, saved logins, or your routines' schedules on their own. A bot may book a follow-up in the chat ("I'll check back Friday"): a one-off it's told to mention in its reply, always shown in Routines, which asks first after outside content, is marked when made then, and counts toward the routine caps. A memory saved after reading outside content is marked unconfirmed and is kept out of the bots' standing instructions until you confirm it. That quarantine is why saving a new memory after outside content is the one change that doesn't ask; replacing an existing memory does, since it would take a confirmed one out of the instructions. The mark survives every path back in: a new version of the memory, a tidy-up suggestion drawn from such a conversation, or "Accept all" (they come in unconfirmed). The one exception is a lesson that says what you wrote yourself (your messages only, never a file's or a forward's text): a page can't put words in your messages. Only your own words come back as past corrections or skill pitfalls. Files bots keep carry the same mark (written after outside content, or changed outside Mimir, counts as outside content), and the workspace can't be left: no .., no links, size limits.

Approval cards show what will happen.

Saved logins never reach the model. They are typed by name into the browser, only on the sites you listed (the site is read the way the browser reads it), and each use asks. Authenticator codes are worked out by Mimir from a key in the secret store and typed the same way. A sign-in card's login is typed in Mimir's own masked form and goes from there to the page and the secret store, never through a chat, the database or a prompt. Mimir types it over the computer's DevTools in an isolated world, so the page's scripts can't change what it reads. Each field is checked and filled by one script there: it reads location.hostname, refuses unless that's on the card's site, then focuses the field and sets its value (through the input's own value setter, with input and change events, which frameworks like React pick up). There's no gap between the check and the value for a navigation to land in. That was chosen over DevTools' Input.insertText, which types like a keyboard, because insertText is a second call after the check. The cost: those events aren't "trusted", and a rare site that only accepts real key presses reads as failed; take over there. The card and the form show the page's full address, and warn when the bot came there after outside content or on another bot's or a document's words, or when the site looks like one with a saved login or an earlier sign-in (a letter or two apart, the same name under another ending, or the name inside a hyphenated one: lookalike.rs). An address with letters from another alphabet (any xn-- label) is always warned about, shown in punycode, and named after a known site when its plain letters line up with one. Mimir types only into the bot's own browser profile: the computer's record of whose Chromium is on screen is checked before the first field and before each later step, and the bot takes the computer again after waiting for an OK, so a bot that used the computer in the meantime never gets another bot's login (even on the same site). It keeps that login for that bot and that registrable domain only. The card's link holds no server, token or site: the form is behind your Mimir sign-in, uses the card the server has waiting, works once and runs out after 10 minutes. A plain Approve can't complete a sign-in card; only the form can.

Only you talk to your bot. A chat is paired by one person with a one-time code, and only that person's messages and button presses count there. In a group, everyone else is ignored. Shared senders (an anonymous admin, a channel) can't pair. Replies never ping @everyone, @here or roles, and never show link previews (the apps fetch those on their own, so a link could otherwise leak data unclicked).

The server. The admin token is checked before a request's body is read, compared in constant time, and is at least 24 characters. The web UI can't be framed by another site, loads only its own scripts, and nothing is cached. The data folder is owner-only. Chat API tokens (for Shortcuts and the like) each reach one bot's built-in chat and nothing else, are checked before the body is read too, and only their SHA-256 is stored.

The bots' computer runs its browser without Mimir's environment or secrets, with its own home. With docker compose it's a separate container (its own user, no data folder, no published ports, a token on its control channel and its DevTools port), so a browser exploit doesn't land next to your database. In the Docker image, file:// and internal pages and downloads are blocked by policy, and the containers drop all capabilities.

Updates are signed. The desktop app installs an update only if it's signed with Mimir's release key (the public half is built into the app); a tampered download is refused. It never restarts on its own.

Downloads and dependencies are pinned.

Hostile input can't take the app down.

What's left #

For contributors #

Every new way for text to reach a model must either be the person's own words, or mark the conversation (ToolCtx::taint). Every new way for data to leave must be listed in sends_out, so it asks after a sensitive source. Every new action that changes data must go through tools::call. Every new kind of learned artefact must be a proposal that keeps the outside-content mark. Never take a server address, token or scope from a URL or deep link (a link someone sends could point Mimir at their server, as in OpenClaw's CVE-2026-25253): those come from settings the person typed, or from the server they chose. Details, with the code they live in, are in Architecture.