Security← Architecture
Docs

Security

The threat model for Plinth, what Seal does and does not protect against, the wallet permission model, and the deployment trust model.

Threat model

AdversaryGoalMitigation
Public observerRead sensitive fields of a submissionSeal field level encryption, key release gated to allowlist wallets
Form owner gone rogueEdit or fabricate a submissionSubmission objects are owned by the submitter, the form owner has no write authority
Form vendor (Plinth itself)Hold data hostageAll blobs live on Walrus mainnet, the Move package is immutable except via the upgrade cap held by the owner address, frontends are interchangeable
Walrus storage nodeTamper with blob bytesWalrus erasure coding plus blob ID hash check on every read
Seal key serverLeak data key without policy approvalThreshold key sharing across multiple key servers, policy enforced on every session key request
Compromised admin walletMass exfiltrate sensitive fieldsOwner can rotate the admin allowlist via AdminCap, the affected admin wallet can be removed in one transaction

What Seal protects

  • Confidentiality of fields marked encrypted: true against any party not on the form admin allowlist.
  • Confidentiality of those fields against the Plinth frontend, the Walrus storage layer, and any third party indexer.

What Seal does not protect

  • Confidentiality of fields marked encrypted: false. These are written in cleartext to a Walrus blob and are publicly readable by anyone who knows the form ID.
  • Confidentiality of metadata. The submission existence, the submitter address, the submission timestamp, and the form ID are visible onchain by design.
  • Compromise of an admin wallet private key. If an admin wallet is exfiltrated, every submission that wallet can decrypt is exposed until the wallet is removed from the allowlist.

Wallet permission model

Plinth uses three capabilities expressed as Sui objects.

OwnerCap

Held by the form owner. Confers the right to:

  • Retire a form.
  • Transfer ownership to a different wallet.
  • Update the schema blob ID or schema version.

The OwnerCap is the highest privilege. It should be stored in the safest wallet available to the form owner. For mainnet deployments of Plinth itself, the OwnerCap for the registry is transferred to the operator owner address at the end of the deploy script.

AdminCap

Held by every wallet on the admin allowlist. Confers the right to:

  • Decrypt sensitive fields via Seal.
  • Annotate submissions in the index with notes, priority, and status.

AdminCap does not confer the right to delete or edit submission blobs. It is read plus annotate, never destructive.

UpgradeCap

Sui standard package upgrade capability. Held by the operator owner address. A package upgrade is a Sui transaction signed by the holder. This is the only path to change Plinth Move logic after publish.

Deployment trust model

Plinth ships with a three wallet deploy pattern.

Wallet A. Operator owner

Held entirely by the operator. Receives OwnerCap, AdminCap for the registry, UpgradeCap, and any leftover SUI plus WAL after the deploy script cleanup transfers run.

Wallet B. Deployer

A dedicated wallet provisioned for the publish flow. Funded with a small amount of SUI for gas and a small amount of WAL for initial blob storage. The deployer wallet private key is supplied to the deploy script through an environment variable, used once to publish the package and write seed blobs, then idled. After cleanup, the deployer wallet holds approximately zero SUI and zero WAL and zero capabilities. The deployer key can be rotated or deleted at the operator discretion.

Wallet C. Prize recipient

Optional. If the operator participates in a Walrus program that pays out in WAL, this is the wallet registered as the recipient. Wallet C may be the same as Wallet A.

The deploy script is intentional about this trust model. It runs in this order:

1. Verify deployer wallet has sufficient SUI and WAL.
2. Publish the Move package.
3. Capture the package ID and the upgrade cap object ID.
4. Initialize the form registry.
5. Write the seed schema blob to Walrus.
6. Transfer the upgrade cap to the operator owner.
7. Transfer the form registry owner cap to the operator owner.
8. Sweep remaining SUI and WAL from the deployer to the operator owner.
9. Print all object IDs and transaction digests.

After step 9, the deployer wallet has no continuing authority. Auditing the resulting object graph on Sui mainnet shows that Wallet A is the rightful owner of every privileged object.

Disclosure

To report a vulnerability, contact the maintainer through the email listed in the repository profile. Do not open a public issue for security findings. Standard responsible disclosure applies.

For the data model and how blobs are laid out, see the Architecture page.