moxzi
Docs / Concepts / Trust model

Trust modelalpha

What does each of the four front ends require you to trust?

The trust model is the list of parties who could change your result without you noticing. It is different for each of the four front ends, and only one of them is trustless.

The constraint that shapes all four: there are no certificates off-chain. A certificate is a subnet threshold signature, and there is no subnet in moxzid or in a browser tab. Faking one would be strictly worse than omitting it, because client code would verify the forgery and believe it. So ic0.data_certificate_present reports 0, and @dfinity/agent's Actor — which polls for a certificate — is unsupported. The generated idlFactory path is the supported surface, and the argument bytes it produces are the real encoder's.

The four front ends#

moxzi CLImoxzidmoxzi-webOn-chain builder
Runs whereyour machineone serverone browser taban IC subnet
You must trustyour machine and the compiler binarythe server operatorthe page originsubnet consensus and the deployed module
Authnone — local processone shared bearer tokennone — same-origin JSIC caller principal, per-job owner checks
Instruction meteringwasmtime fuelwasmtime fuelopt-in instrumentation (meter: true) — V8 has no fuel, so the module counts its ownthe replica
Preemptionfuel exhaustionfuel exhaustionworker termination, wall-clockthe replica
Certificatesnononoyes
Who can read your sourceyouthe operatorthe pagethe canister's operators, unless you build from a mops tag
Trustlessnononoyes

The CLI trusts your machine#

moxzi build runs compiler.wasm under wasmtime in your own process. Anything on your machine that can modify that file, the linker, or the CLI binary can change your artifact, and nothing in the design prevents it. What the CLI does give you is a name for what it used: every build prints a provenance line naming the compiler by SHA-256, and moxzi info reports the loaded compiler and linker with their hashes. Compare those against the release notes; that comparison is the only integrity check available locally.

--remote changes the picture: the compile happens on-chain and the CLI downloads the artifact, so the local machine is reduced to a transport — but the link still happens against your local linker unless you use the on-chain linker, so check what your build actually did.

moxzid trusts the operator#

moxzid is an actor host, not a sandbox for you against its operator. The operator can read every actor's state, replace its code, and read every message.

PropertyDetail
Autha single shared bearer token (--auth-token / MOXZID_TOKEN), constant-time compared, on every endpoint except /health, /health/ready and /version
User modelnone. One token, all powers. This is stated as alpha scope rather than half-implemented as RBAC
TLSnot in the binary. Terminate it in a reverse proxy
Dangerous surfacePOST /install/<name> runs arbitrary wasm. That is why moxzid refuses to bind a non-loopback address without a token unless you pass --insecure
Scalesingle-node. One process, one queue per actor, round-robin fairness. More moxzids do not coordinate
Inspectorthe dashboard at / is static and open; every data call it makes still needs the token

Rate limits, IP allowlists and origin restrictions are deliberately absent from the binary and belong in the proxy. If you are exposing moxzid, the token is the entire access control system — treat it accordingly.

The browser trusts the page#

Actors in a tab run inside the page's own JavaScript context. Any script the page loads can call them, read their state, and rewrite their storage; IndexedDB persistence is origin-scoped and no more private than the origin is. There is no boundary between your actor and the page — the page is the host.

Two consequences that are easy to get wrong:

Outcalls need cross-origin isolation (Cross-Origin-Opener-Policy: same-origin, Cross-Origin-Embedder-Policy: require-corp) because the sync-to-async bridge uses SharedArrayBuffer. Requesting deadlineMs or http without worker: true fails at start rather than half-working.

The on-chain builder is the trustless one#

This is the front end the rest exist to be compared against. An artifact whose bytes were produced by a canister, from sources anyone can hash, by a compiler anyone can audit, is evidence — and it is evidence precisely because the local build reproduces it byte for byte.

What you still trust, stated plainly:

You trustBecause
The subnet's consensusIt executes the canister. This is the IC's own trust model, not moxzi's.
The deployed module hash, not the canister idA canister with controllers can be upgraded. Verify the compiler and linker SHA-256s published in the release notes against the deployment before treating a build as attested.
The operator setsyncOperators() copies the controller list into the operator set, and a fresh deployment is locked until it runs. Operators arm payment and can steer jobs.

And what the operator can see: uploaded source sits in the canister's VFS and is readable by operators until removed or evicted. This is disclosed rather than mitigated. Builds from registered mops tags upload nothing — the canister materialises content-addressed blobs it already holds — so closed-source projects should prefer tag builds. Tags are not taken on trust either: useTags accepts only tags that passed verifyTagAgainstMops, and fails closed when no registry is configured, because content-addressing proves a client did not lie about content while only mops can say the content is really that package version.

Between customers, the isolation is real and tested: every job method checks owner-or-operator, and refusals are silent (null/0/false) so probing job ids teaches nothing. test/pic-js/test/job-auth.test.ts pins it. Uploads are quota-bounded at 64 MiB per caller and 1 GiB total.

On money: escrow is pulled before compute, settlement charges 3× measured actual and refunds the rest, startEscrowed refuses up front what the deployment cannot afford to finish, and a customer who walks away can be settled by abandonSettlement. A fresh deployment with payment unconfigured compiles for free and says so.

Things you cannot do#

Not possibleWhy
Verify a certified query off-chainNo subnet, no threshold key. Certified-data patterns need the real IC.
Use @dfinity/agent's Actor against moxzid or a tabIt polls for a certificate. Use the generated idlFactory.
Enforce an instruction limit in a browser for freeV8 has no fuel, so the module has to be instrumented to count its own instructions. meter: true does that and enforces a real limit; it costs about a fifth in size and half again in speed. Unmetered, the only lever is a wall-clock worker deadline.
Get per-user isolation from moxzidOne shared token; no user model in the alpha.
Hide source from an on-chain build operator by uploading itThe VFS is canister state. Build from a mops tag, or accept the disclosure.
Treat a canister id as an attestationVerify the deployed module hash. An upgradeable canister is only as trustworthy as its controllers.

Next#

On this pageThe four front endsThe CLI trusts your machinemoxzid trusts the operatorThe browser trusts the pageThe on-chain builder is the trustless oneThings you cannot doNext