Skip to content

Threat Model

A threat model is only useful if it names the attacker and admits where the defense ends. This page does both. It is written for security-conscious builders and for auditors who need to map controls to risks.

The whole model rests on one structural fact, established in Zero Single-Sig: after genesis, no single key controls anything on chain. Most of the mitigations below are consequences of that single property.


%%{init: {'flowchart':{'htmlLabels':true,'curve':'basis'}}}%%
flowchart TB
    subgraph Untrusted["Untrusted — outside the boundary"]
      Attacker["External attacker"]
      Device["Stolen builder device"]
      Quantum["Future quantum adversary"]
    end

    subgraph SemiTrusted["Partially trusted — assumed-faulty by BFT"]
      V1["Validator 1"]
      V2["Validator 2"]
      V3["Validator N"]
      App["Customer smart-app code"]
    end

    subgraph Enforced["Structurally enforced — no single party controls"]
      Quorum["Signing threshold t<br/>at least a strict majority"]
      Rules["Public rules on HCS"]
      Chain["Native chain multisig"]
    end

    Attacker --> SemiTrusted
    Device --> SemiTrusted
    App --> Rules
    V1 & V2 & V3 --> Quorum
    Quorum --> Chain
    Rules --> Quorum
    Quantum -.->|harvest-now,<br/>decrypt-later| Enforced

The design assumption is Byzantine: up to ⌊(N−1)/3⌋ validators may be malicious or compromised at any time, and the system must remain safe. Validators and customer smart-app code are treated as partially trusted — never given authority a quorum doesn’t ratify.


Adversary What they try What stops them Residual risk
Rogue / compromised validator Steal a key share, sign unilaterally, forge a quorum cert, or drive honest peers into co-signing an attacker-chosen message. A single Shamir share is information-theoretically useless below threshold; signing needs t-of-N signature shares; the on-chain native multisig (master key disabled) rejects any sub-quorum signature. The peer co-signing path for cluster-internal signatures is not a general signing oracle: a validator contributes a partial only for messages on a shape allowlist, and the reserved credential-derivation domains (such as the cluster master key-encryption key) are bound to the one entity entitled to sign them — a peer reconstructs the expected digest for the requesting entity and refuses otherwise. A forged PQC quorum cert cannot verify valid either: the customer verifier anchors each signer’s key to the on-chain validator registry — never to the keys the cert itself carries — rejects any duplicate signer, and fails closed when the registry is unreachable (offline verification). Compromise of t validators of one entity’s committee at the same time, where t is that entity’s threshold (always at least a strict majority). Those validators could sign together and skip the rule check. The co-signing gate validates the payload, not the requester: a compromised rightful participant of an entity can still drive that entity’s own ceremony (every validator is such a participant). Closing that needs per-caller request authentication, not payload validation.
Compromised host / pod Read secrets from disk or image, or exfiltrate signing material. Secrets use envelope encryption under a key-encryption-key (KEK) hierarchy, are mounted at runtime and are never baked into images. On-chain signing keys on the live chains are never reconstructed: signing runs the two-round FROST protocol, so a validator only ever holds its own share and nonces. The validator’s envelope decryption service is least-privilege: each calling service is bound to only the secret classes its job needs, and anything else is refused and audited, so a compromised host cannot read deployment secrets and a compromised deployer cannot read tenant BaaS data. A compromised validator exposes its own share, which is useless below threshold. It also exposes the cluster’s master key-encryption key, which validators hold in memory, and with it the internal envelopes sealed under that key. Per-app threshold keys, which would remove this, are built, not yet enabled. Envelope access is bound per service, not yet per app: a compromised host can still read the BaaS envelopes of the apps it legitimately serves.
Stolen builder device / SDK key Authenticate as the builder and drive the platform. Web3 auth is a per-request signature challenge; possession of the device’s wallet key is required. All actions still pass through public rules and a validator quorum. A platform sign-in gate that also requires holding an HSUITE NFT (Face A TokenGate) is built, not yet enabled. A fully stolen, unlocked wallet can authenticate. Mitigation is operational (hardware wallets, key rotation), not cryptographic. The blast radius is bounded by what the rules permit that identity to do — not the whole network.
Authenticated builder crossing tenants Use a valid session to read or mutate another tenant’s subscription — e.g. hand a subscription route a crafted app identifier (a database query-operator object instead of a string) to skip the ownership comparison and match a foreign row. The subscription-ownership guard resolves the target app identifier first and then fails closed: a present-but-malformed value — non-string, operator object, empty, over-length — is a 400, never a deferral. Only a genuinely absent identifier defers to the controller (the create path); a well-formed one is checked against the authenticated wallet’s ownership before the handler runs, and the developer account on the create path is validated the same way. Malformed input therefore never reaches the database as a query operator. The same owner-scoping covers every per-app resource route — consumption, remaining quota, history, ledger, status and category breakdown each check ownership before any read, so a caller who does not own the app gets a 404, never another tenant’s usage or its end-customers’ wallet and session data. Bounded to a builder’s own tenant — ownership is wallet-bound. A builder acting on an app it legitimately owns is not an attack; there is no residual cross-tenant reach through this surface.
Forged / cross-app customer-session claim Present a customer’s X-Customer-Session-Claim for a customer they don’t hold, or replay a customer session issued for one app against a different app, to act with that customer’s scope. Customers authenticate with an opaque session bearer (a 43-character random token minted at login), never a raw identity a caller can simply assert — an unknown or malformed claim fails closed at the session validator. Each claim is bound to the app its session was issued for: a customer session of app A presented against app B is a 403, and only an app-owner may vouch for a customer (any other principal may name only itself). A request carrying a valid customer claim is then scoped to that customer’s own rows — and new apps default to this strict scope rather than tenant-wide access. Bounded to a single customer’s own data within a single app. Attribution and rate-limiting on a vouched call are only as honest as the vouching app-owner; the platform trusts an app to speak for its own customers, by design.
Free-session caller on a management / operator surface Use a self-serve customer session (or no credential) to reach a control-plane or operator route it doesn’t own — configure DNS records or flip DNSSEC on any registered domain, suspend a domain, evict a host from an app’s routing pool, or read the gateway’s detailed status as a live oracle on the host-verification subsystem. Those routes are default-deny cluster-internal: DNS / DNSSEC / suspend on the domains controller and the entire routing controller require the cluster-internal service key, so a tenant bearer token is 401. The routing controller is gated as a whole, so a route added later is internal-only by default, and a repository test fails if a new handler ships without the gate. The operator status view is no longer public; only liveness (health / ready / live) stays public. Upstream framework fingerprints (Server, X-Powered-By) are stripped at the edge, and the public metrics endpoint is a minimised status-page projection. Liveness probes and the gateway→gateway cluster-health peer probe stay public by design. The peer probe’s confidentiality is handled by minimisation — it carries only what the aggregator reads — not by auth, because clusters deliberately share no internal service key.
Compromised bootstrap seed / network MITM Hand the SDK a discovery response quoting real validator nodeIds next to an attacker-controlled gatewayUrl, or downgrade the connection to plaintext, to steer a customer onto a rogue gateway. Cluster discovery’s trustAnchor is a gate, not advice: a cluster is used only if every claimed nodeId is on-chain and each on-chain record binds the advertised gatewayUrl origin — the gateway is bound, not merely a node id. An empty or unreadable registry fails closed (TrustAnchorError); degrading to the unverified seed list requires an explicit, non-production onFailure: 'passthrough'. The SDK refuses a plaintext gatewayUrl from the registry (InsecureClusterRegistryError) and never advertises cleartext; HSTS is emitted unconditionally behind the TLS-terminating edge. Every registry reader — SDK discovery, validator peer admission and the cluster messaging layer’s admission check alike — admits an entry only when it carries an Ed25519 signature by its independently pinned key: unsigned, altered or replayed rows admit nobody, a signed leave outranks a replayed re-join, and absent pins fail closed. Without trustAnchor set, the trust model is that of a plain HTTPS call to a public endpoint. The anchor is only as strong as the on-chain registry being populated — a caller must either populate it or accept the HTTPS-only model.
Quantum adversary Break Ed25519 / ECDSA / secp256k1 with Shor’s algorithm, or harvest signatures now to forge later. Validators sign platform records with FIPS 204 ML-DSA-87 quorum certificates (Post-Quantum) — a lattice signature with no known quantum attack — and seal internal secrets with FIPS 203 ML-KEM. Certificates are minted today for only a few internal record types, and a missing certificate is logged rather than rejected. On-chain bytes stay on the chain’s native curve (Ed25519 on Hedera and XRPL) until each chain adopts native PQC verification, so on-chain signatures are not yet quantum-safe.
Malicious smart-app Trigger unauthorized transactions, escalate privilege, bypass policy from app code — or use a sandboxed function’s outbound fetch to reach cluster-internal services (SSRF). Every signing request is checked by each validator against the public, mandatory Rules Engine before it contributes a signature share; the quorum signs only what the rules allow. App code running in the BaaS functions sandbox cannot pivot to the internal network either: every outbound fetch passes an SSRF guard that refuses in-cluster address spellings (cluster service names, the cloud metadata address, and private, loopback and link-local ranges) and then pins the socket to the exact addresses it vetted — so a rebinding DNS answer cannot re-point the connection after the check clears. A per-app egress allow-list limits it further to the app’s own host and its approved hosts. A smart-app can do anything its own published rules permit — so the security of a tenant is the security of its rule set. Rules are public on HCS, so misconfiguration is auditable, not hidden. Its sandboxed outbound calls are confined to genuinely public destinations — never the cluster’s own services.
Supply-chain / CI attacker Inject a backdoor via build pipeline or dependency. Release images are built by the automated release pipeline and ship obfuscated and license-encrypted. Platform security properties are covered by tests that run on every pull request. The build pipeline has known gaps, and it is not by itself a guarantee of build integrity.

Attack-and-defense walkthrough: a rogue validator tries to spend

Section titled “Attack-and-defense walkthrough: a rogue validator tries to spend”
%%{init: {'sequence':{'showSequenceNumbers':false}}}%%
sequenceDiagram
    autonumber
    participant Rogue as Rogue validator
    participant Peers as Honest peers (quorum)
    participant Rules as Rules Engine (HCS)
    participant Chain as Blockchain ledger
    Rogue->>Rogue: holds exactly ONE key share
    Note over Rogue: A single share is below threshold — useless on its own.
    Rogue->>Peers: request signature shares for an unauthorized transfer
    Peers->>Rules: does the public rule set permit this?
    Rules-->>Peers: NO — rejected
    Peers-->>Rogue: refuse to contribute signature shares
    Rogue->>Chain: attempt to submit a single-sig / sub-quorum transaction
    Chain->>Chain: verify signatures against the native multisig threshold
    Chain-->>Rogue: rejected — master key disabled, quorum not met
    Note over Rogue,Chain: No on-chain authority leaked. Attacker gained nothing.

The rogue validator fails at two independent gates: honest peers refuse a rule-violating request, and even if they didn’t, the chain’s own native multisig rejects any signature below the quorum threshold. Neither gate depends on Smart Engines being trusted.


Honesty is part of the model. Smart Engines does not claim:


  • TSS / MPC — the cryptography behind the rogue-validator row above.
  • Post-Quantum — the quantum-adversary defense, and what it covers today.
  • Zero Single-Sig — why there is no master key to steal.
  • Token Gating — the access-control boundary for builders and customers.
  • Glossary — BFT, Shamir share, quorum, multisig defined.