The thing your AI app is doing with your API key right now
Open the settings panel of almost any AI product you pay for. Find the field where you pasted your model-provider key. Now ask yourself what happens after you click Save.
In the overwhelming majority of cases, the answer is: the key travels to the vendor's backend over TLS, gets written to a row in a managed database, and is "encrypted at rest" using a key management service that the same application has IAM permission to call. The application then decrypts the key on every inference request, attaches it to an outbound HTTP call to the model provider, and proxies the response back to you.
This is not security. This is indirection. The application can decrypt the key whenever it wants, which means anyone who owns the application can decrypt the key whenever they want. "Encrypted at rest" is a compliance phrase, not a threat model. If the process that serves your requests can read the plaintext, then a foothold inside that process can read the plaintext too.
This post is the argument for why Bring-Your-Own-Key isn't a power-user feature. It's the only defensible default for a desktop AI tool, and it's the one Session is built around.
Blast radius: the thing nobody puts on the marketing page
Centralized key storage is a blast-radius problem disguised as a convenience feature. When a SaaS provider gets breached, and the base rate here is "when," not "if", the attacker doesn't walk away with one user's credentials. They walk away with a rotating dump of every paying customer's keys to every model provider the product integrates with.
The follow-on damage is worse than the initial breach for three reasons:
- Detection lag. The user doesn't see the breach. They see, three weeks later, an unusual line item on their model-provider invoice. The median time-to-discovery for stolen API keys, in the public incidents I've tracked, is measured in weeks, not hours.
- Capability laundering. Stolen keys get used to spin up token-burning workloads, usually crypto-adjacent, sometimes worse, and the bill lands on the legitimate user. The model providers' abuse teams are good but not instant.
- Lateral access. A model-provider key with the right permissions can read your fine-tuned models, your stored files, and your assistant configurations. The key isn't just a meter; it's a handle on your account.
The vendor whose database got popped will write a postmortem about rotation procedures and improved IAM scoping. None of that retroactively unbills your account.
Why "encrypted at rest" is the wrong question
The phrase "encrypted at rest" describes a property of the storage layer. It does not describe a property of the running application. Every centralized-key architecture has the same shape:
request -> app server -> KMS.decrypt(user_key) -> outbound call to model provider
The middle step is where the attacker lives. Once you have code execution in the app server, through a dependency compromise, an SSRF, a leaked CI token, an insider, you have kms:Decrypt on every key in the database, because the app server needs that permission to function. KMS is a control plane for who can ask for decryption; it is not a control plane for what the application does with the plaintext after decryption.
This is why I find audit checkboxes around "keys are encrypted with AES-256" almost actively misleading. They describe the disk. They do not describe the runtime. The runtime is what the attacker compromises.
BYOK done right: the OS keychain is the trust boundary
The defensible alternative is to never put the key on the vendor's servers at all. Every modern operating system already ships with a hardened secret store designed for exactly this:
- macOS has the Keychain, gated by the Secure Enclave on Apple Silicon and bound to the user's login session.
- Windows has the Credential Manager, with DPAPI tying secrets to the user account and machine.
- Linux has libsecret, fronted by GNOME Keyring or KWallet, with optional integration to a TPM.
These are not perfect, but they are dramatically better than a row in someone else's database, for one structural reason: the blast radius is one machine. Compromising one user's keychain requires code execution on that user's box. Compromising a SaaS keystore requires code execution on one server and yields every user at once. Those are not the same threat.
BYOK done right means the desktop app reads the key from the OS keychain at the moment a request is built, attaches it to the outbound HTTPS call, and discards the plaintext from memory as soon as the request completes. The vendor's backend is never in the path. The vendor's database has nothing to leak, because nothing was ever written to it.
How Session implements this
Concretely, in Session: a thin native module reads from the OS keychain when the desktop app constructs an inference request. The request flows directly from the desktop app to the model provider's endpoint. The Session backend is not on the path.
The backend is in the loop for exactly three things:
- Account state, your Session subscription, your team membership, your settings sync.
- Cross-device sync, encrypted-at-the-client conversation history, with keys derived from your Session passphrase, not from anything we hold.
- Billing for Session itself, payment processor metadata, not model-provider metadata.
Inference traffic, your prompts, your completions, your tool calls, never touches our servers. That's not a policy. It's an architecture. Policies can be violated by a rogue employee or a compromised deploy; an architecture where the data isn't routed through our network can't be.
This is also why, when we say "no telemetry on prompts," it's not a promise we're asking you to trust. We literally cannot see your prompts. They went to the model provider. The receipts are on the provider's side. For more on how this fits the broader picture, see the local-first piece on Ollama.
The honest counter-arguments
"What about team plans and centralized billing?"
Fair. Some organizations genuinely want one bill, one key, one admin. The right answer here is an org-controlled keyring, a key vault the customer's IT team owns, integrated into the desktop app, not a SaaS-controlled one where the vendor holds the master. The distinction matters: in the org-controlled model, a vendor breach yields nothing useful, because the vendor doesn't have the keys.
"What about web-only apps?"
Web apps fundamentally cannot do BYOK well. The browser has no equivalent of the OS keychain that the page can use without round-tripping through a server. This is a structural limit of the web as a platform for high-trust tools. It's not a flaw in BYOK; it's a reason to take the desktop seriously again.
"Isn't this just shifting the problem to the user?"
Yes. And that's the point. The user's blast radius is one machine. The SaaS's blast radius is every customer simultaneously. Distributing risk to endpoints that already have hardened secret storage, and where compromise is local rather than global, is exactly the right shift.
Where BYOK doesn't fit, honestly
I don't think BYOK is universal. There are real cases where it's the wrong choice:
- Regulated industries with central key-vaulting mandates. Some compliance regimes require keys to live in an enterprise KMS with audit logs the org controls. BYOK on individual machines fights that requirement.
- Devices without OS keychains. Kiosks, some Linux server contexts, ephemeral cloud workstations. The keychain assumption isn't free.
- Centralized rotation requirements. If an org needs to rotate every employee's model-provider key in 60 seconds in response to an incident, distributing keys to N laptops complicates that. An org-controlled keyring helps, but it's more engineering than a single SaaS DB row.
These are real. They are also a much smaller share of the AI tooling market than the marketing copy of centralized vendors suggests.
The lens to evaluate any AI app you use
For the next ten years of AI tooling, my claim is simple: any product that asks for your model-provider API key and stores it server-side is the wrong default. Not because the team is malicious, but because the architecture concentrates risk in a place the user doesn't control and can't audit.
The questions to ask any AI app:
- Where does my key live when I'm not using the app?
- Does the vendor's backend ever see my prompts in plaintext?
- If the vendor's database got dumped tomorrow, what would the attacker have?
If the answers are "your machine," "no," and "nothing," you're looking at a local-first tool that takes its own threat model seriously. If they're "our database," "yes, but encrypted," and "every customer's keys," you're looking at a liability that hasn't realized it's a liability yet.
Session is built on the first set of answers, and we don't intend to drift toward the second.