Security and model delivery

What protects a model between our storage and your users’ devices, what a project key can and cannot do, and which guarantees stop at the edge of hardware you do not control.

Delivery

Authorization happens on the server

When your app prepares a model, the SDK asks our API which artifact this device should run. That request is authenticated with your project key, and the server checks entitlement, account standing, runtime compatibility and delivery quota before it authorizes anything.

Those checks are not repeated hints for the SDK to enforce — they are the decision. The SDK has no local flag that grants access to a model, so modifying the SDK, or calling the engine directly, does not produce an entitlement. A client that believes it is entitled still receives a refusal from the server.

Practical consequence

You do not need to protect your app binary in order to protect your entitlements. Treat the project key as an identifier that will be extracted from any shipped app, because it will be.

Delivery

Download authorization is short-lived and narrow

A successful resolve returns a download authorization that is scoped to one artifact and expires shortly after it is issued. It is not a session, not a bearer token for the catalogue, and not reusable for a different model, version or platform.

Quota is enforced again when the bytes are served, not only when the authorization is minted, so an authorization that is replayed within its window still counts against the same ceiling.

Delivery

Models are encrypted in transit and at rest

Artifacts are stored encrypted and travel encrypted, using authenticated encryption — the decryption step verifies the artifact was produced by us and has not been altered. Decryption material is issued per download alongside the authorization, and is never embedded in your app or in the engine.

This is in addition to HTTPS, not instead of it. An artifact that leaks from a cache, a proxy or a backup is ciphertext.

Delivery

Integrity is verified before install

Every artifact carries two hashes: one for the bytes on the wire and one for the decrypted model. The first is checked before decryption, so a truncated or corrupted download is reported as a transfer problem rather than mistaken for a bad key. The second is checked after decryption, before the model is installed.

A model that fails either check is discarded, not installed. Your app sees a preparation failure and the previously installed model — if any — stays in place.

Credentials

Project keys, rotation and revocation

A project key identifies a project. It cannot administer your organization, publish models, create entitlements, read another project’s models, or change billing. Its blast radius is deliberately limited to the thing it needs to do: ask for models the project is already entitled to.

Keys are shown once, at creation. We store a hash, so we cannot redisplay a key later — if you lose one, rotate it. Rotation lets you issue a replacement and revoke the old key separately, so you can ship an update before turning the previous key off.

Revoking a key stops it authenticating immediately. Download authorizations already issued to that key remain usable until they expire, which is a short window and not an indefinite one.

What revocation does not do

Revoking a key does not remove models already installed on end-user devices. Those bytes are on hardware you and we do not control, and they keep working. Revocation controls future delivery, not past installs.

Runtime

Inference is local and works offline

Once a model is installed, inference runs entirely on the device. There is no per-inference call to our servers, no license heartbeat, and no requirement to be online to use a model you already have. An app that has prepared its models keeps working on a plane.

The network is used to resolve, download and install models, and to report usage that billing is based on. None of that happens per inference.

Runtime

Your users’ data stays on the device

Images, video frames, documents and recognized text are processed locally by the engine. They are not uploaded to CactusBrain, and we have no way to read them. This is a property of running inference on-device rather than a policy commitment we could quietly change.

What we do see is operational: which project asked for which model, when, and how many bytes were delivered. That is what makes usage and quota work.

Honest limits

What this does not protect against

We would rather state the boundaries than let you plan around guarantees that do not exist.

  • The SDK can be reverse engineered. Release builds are optimized and stripped, which raises the cost, but anyone determined can inspect a binary they possess. We do not treat that as a security boundary, which is why authorization lives on the server.
  • A model on a device can eventually be extracted. The engine must see plaintext weights in memory in order to run them. Encryption at rest raises the cost of casually copying a model file; it cannot defeat the owner of the hardware.
  • An extracted model cannot be remotely disabled. Once weights have been taken off a device, we cannot cryptographically force that copy to stop executing on hardware an attacker controls. Anyone claiming otherwise about on-device inference is describing a network-dependent product.
  • An embedded project key will be found. We assume this and design for it: keys are attributable, rate-limited, quota-bound and revocable, so a stolen key is a containable incident rather than an open-ended one.
Contact

Reporting a vulnerability

If you believe you have found a security issue, email [email protected] rather than opening a public issue. Include what you did, what you observed, and what you expected. We would rather hear about a boundary that does not hold than read about it later.

Please give us a chance to ship a fix before publishing details, and do not run tests that degrade service for other customers or touch data that is not yours. We do not currently run a paid bounty programme, and we would rather say so than imply one.

See also error handling for how delivery refusals surface in your app, and offline behaviour for what runs without a network.