08 · Security & threat model

Ballast’s value is precise: it bounds and verifies what an agent can do. This page states plainly what it defends, what it does not, and where each guarantee lives, so a reviewer can trust it for the right reasons.

Diagram 8: Trust boundaries

flowchart TB
    subgraph trusted["TRUSTED"]
        chain["Sui consensus + Move VM<br/>(executes enforce / verify_nautilus)"]
        capobj["BallastCap object<br/>(limits, on-chain, tamper-proof)"]
        encobj["Enclave (BallastEnclave)<br/>(attested key, proven at registration)"]
        awsroot["AWS Nitro attestation root<br/>(cert chain anchor)"]
    end

    subgraph untrusted["UNTRUSTED"]
        prompt["Prompt / model inputs"]
        agentproc["Agent process + its key"]
        agenthost["Agent host"]
        ec2["EC2 enclave host"]
        net["Network"]
    end

    prompt -->|"can hijack intent"| agentproc
    agentproc -->|"builds + signs PTB"| chain
    ec2 -->|"cannot read enclave memory/key"| encobj
    awsroot -.->|"anchors"| encobj

    chain -->|"enforce(): spend/lev/market/expiry/revoke"| capobj
    chain -->|"verify_nautilus(): sig vs attested key"| encobj

    classDef t fill:#0e3142,stroke:#3AA0E0,color:#EAF4FB;
    classDef u fill:#3a1416,stroke:#f0555a,color:#EAF4FB;
    class chain,capobj,encobj,awsroot t;
    class prompt,agentproc,agenthost,ec2,net u;

The guarantee is structural. The agent process is untrusted, yet it cannot exceed the mandate, because the limits and the signature check execute inside the trusted Move VM against tamper-proof objects, not inside the agent.

What Ballast defends

Threat Defense Enforced in
Over-spend spent + amount <= spend_limit capability::enforce (abort 5)
Over-leverage leverage_bps <= max_leverage_bps capability::enforce (abort 4)
Trading a disallowed market allowed_markets.contains(market); market derived from the real pool object capability::enforce (abort 3)
Acting after the mandate ends now <= expiry_ms; owner revoke() sets revoked capability::enforce (abort 2 / 1)
Prompt injection / hijacked agent Limits live in the on-chain object, not the prompt, so a hijacked agent still can’t exceed them capability::enforce
Forged / absent TEE signature Ed25519 check vs the enclave’s on-chain-proven key attestation::verify_nautilus (trading abort 1)
Replayed signature on a different trade Signature is bound to {agent, market, amount, is_bid} (+ timestamp) verify_nautilus payload binding
Using a cap with the wrong identity cap.agent == id(identity) trading (abort 2)
Agent inflating its own reputation record_ok is public(package), so only a real gated trade can move it identity
Partial settlement on a violation assert! aborts the whole PTB atomically Move PTB semantics

A prompt injection is the sharpest case. The attack succeeds at hijacking the agent’s intent and fails at the chain. The over-spend it induces aborts in enforce: the agent was hijacked, the capability wasn’t.

What Ballast does NOT defend

Stated honestly, these are out of scope, either by design or by current status:

Real vs. mocked

The single honest seam in Ballast:

Component Status Detail
Capability enforcement (spend/leverage/market/expiry/revoke) Real proven by on-chain aborts 5/4/3/1
DeepBook Spot fill through the cap Real real execute_trade<SUI,DBUSDC> fills, zero-DEEP
Reputation + TradeExecuted events Real record_ok is package-gated
Nautilus TEE attestation (verify_nautilus, execute_trade_attested) Real enclave key proven on-chain via AWS cert chain + PCRs; attested fill + forged-sig rejection both recorded
AWS Nitro enclave app (enclave/ballast-trader) Real reproducible EIF, ran on Nitro hardware
Legacy attestation::verify(payload, sig) Stub returns true; default mock path only, kept byte-for-byte so the demo can’t regress

Nothing else is mocked. The mock path is opt-in-by-default for convenience; the real path is one provider swap away (see 06 · Quickstart).

Reporting

This is hackathon-stage research software on testnet with a throwaway deployer key. Do not use it with mainnet funds as-is. Issues and review welcome via the repository.

← Back to docs index