Skip to content

Security Guide

This guide is for smart-contract authors. It focuses on design choices that can make a contract unsafe even when the runtime, package provenance, and registry controls are working correctly.

For package evidence and release controls, use:

What Can Go Wrong

Most contract security issues come from one of these patterns:

RiskExample
Over-broad invocationA write method uses anyUser or any when only an organization should call it.
Permission escalationA caller uses a contract to reach a bucket the caller should not be able to affect.
Unbounded executionA public method loops over unbounded input and exhausts fuel.
Unstable ABICallers and indexers cannot rely on input, output, or event shapes.
Data leakageEvents or return values include plaintext, secrets, keys, or private metadata.
Unsafe C2C dependencyA nested call introduces rollback, readiness, or authorization behavior the author did not expect.
Migration lossUpgrade migration overwrites, deletes, or transforms state without enough guards.
Stale evidencePackage, manifest, provenance, or registry evidence no longer matches the code being deployed.

The rest of this guide turns those risks into authoring rules.

Authorization

Choose the narrowest invoke.allow policy that matches the method.

PolicyUse forBe careful because
userOne specific user.User ids are operationally specific and may need rotation or ownership transfer.
organizationTeam, app, or tenant-scoped methods.Everyone resolved to that organization may call.
contractExact contract-to-contract callbacks.The caller contract id must be stable and reviewed.
anyUserPublic user-facing methods.Any authenticated user can call. Avoid for writes unless business rules are intentionally public.
anyContractReviewed extension points for all contracts.Any deployed contract can call. Treat as an integration surface.
anyMethods intentionally public to users and contracts.Broader than anyUser; tooling should make reviewers pause.
systemPlatform-controlled flows.Do not use unless the platform flow is explicitly designed for it.

Example organization-only method:

json
{
  "invoke": {
    "allow": [
      { "principalType": "organization", "principalId": "org-noos" }
    ]
  }
}

Example exact C2C callback:

json
{
  "invoke": {
    "allow": [
      { "principalType": "contract", "principalId": "contract-report-caller" }
    ]
  }
}

Rules:

  • Prefer user or organization for writes and admin-like methods.
  • Use exact contract principals for C2C callbacks.
  • Use anyContract only for deliberate, reviewed extension points.
  • Treat any as a production-risk exception unless the method is intentionally public to both users and contracts.
  • Do not assume a contract caller is a human. In nested calls, reason about both the root caller and the immediate caller contract.
  • Keep governance/admin operations out of contract methods unless governance has approved that contract and every caller path.

For the full authorization model, see Authorization.

Bucket Safety

Bucket-sensitive host operations require several gates to line up:

text
method manifest declares bucket access
AND deployed contract principal has bucket permission
AND caller has bucket permission where the host operation requires it
AND local payload availability satisfies the manifest when required

Metadata-only read:

json
{
  "bucketId": "bucket-reports",
  "access": ["bucket:read_metadata"],
  "availability": "metadata"
}

Local encrypted payload availability:

json
{
  "bucketId": "bucket-reports",
  "access": ["bucket:read_encrypted"],
  "availability": "encrypted_payload_local"
}

Rules:

  • Declare only the bucket permissions a method actually needs.
  • Prefer availability: "metadata" unless the method truly depends on local encrypted payload availability.
  • Remember that readiness can fail on nodes missing required bucket permissions or local payloads.
  • Do not use a contract as a way to bypass caller bucket access.
  • Never emit plaintext, decrypted payloads, DEKs, private keys, auth tokens, or sensitive metadata in events or return values.
  • Review the bucket index schema before writing encrypted-record metadata or public indexes.

For buckets and permission details, see Data Buckets and Authorization.

Resource And Fuel Safety

NOOSChain does not charge gas, but every contract call has deterministic protocol limits: fuel, memory, host calls, argument size, event size, return size, and write effects.

Good pattern:

ts
const max = min(input.items.length, 50);
for (let i = 0; i < max; i += 1) {
  processItem(input.items[i]);
}

Bad pattern:

ts
while (true) {
  pollUntilSomethingChanges();
}

Rules:

  • Bound every loop by an input limit, manifest rule, or fixed constant.
  • Cap arrays and maps in the ABI.
  • Avoid recursion unless depth is explicitly bounded.
  • Prefer predictable storage writes over many small dynamic writes.
  • Keep events and return values compact.
  • Use method maxFuel as a local circuit breaker for public or expensive methods.
  • Split large workflows across multiple transactions.
  • Do not depend on wall-clock time, randomness, filesystem access, network access, or node-local configuration.

For method limits, see Manifest Methods.

ABI And Schema Discipline

The manifest ABI is the caller contract. Treat it like a public API.

Good input shape:

json
{
  "type": "object",
  "properties": {
    "id": { "type": "string" },
    "status": {
      "type": "string",
      "enum": ["draft", "submitted", "approved"]
    },
    "formatVersion": { "type": "integer" }
  },
  "required": ["id", "status", "formatVersion"]
}

Rules:

  • Include formatVersion for inputs and stored values that will evolve.
  • Make required fields explicit.
  • Use enums for workflow states.
  • Avoid hidden defaults that depend on time, randomness, or external services.
  • Keep output schemas stable.
  • Document event schemas in the manifest.
  • Treat breaking ABI or event changes as a package version change.

For ABI fields, see Manifest Methods.

Events And Returns

Events are durable execution records for observers and indexers. Return values are structured call results for the transaction CALL_CONTRACT receipt.

Rules:

  • Use stable topic names, such as report.saved or migration.completed.
  • Include ids, public status, and correlation fields.
  • Keep payloads small and bounded.
  • Return one structured value per successful call.
  • Do not include secrets, plaintext encrypted payloads, private keys, auth tokens, or sensitive operational metadata.
  • Assume events and returns may be retained and indexed.

For AssemblyScript helpers, see AssemblyScript SDK.

Contract-To-Contract Safety

C2C calls are useful for composition, but they introduce dependency and rollback behavior.

Caller manifest:

json
{
  "calls": [
    {
      "contractId": "contract-report-target",
      "methods": ["summarize"],
      "requiredBuckets": []
    }
  ]
}

Target method authorization:

json
{
  "invoke": {
    "allow": [
      { "principalType": "contract", "principalId": "contract-report-caller" }
    ]
  }
}

Rules:

  • Declare every outbound target and method.
  • Keep nested calls shallow.
  • Avoid dependency cycles.
  • Treat nested calls as all-or-nothing: if the target fails, the parent call rolls back.
  • Avoid broad target auth when the method is intended for one caller contract.
  • Include target bucket requirements on the caller edge.
  • Review target readiness and deactivation risk before relying on a target.

For C2C manifest fields, see Manifest Calls.

Migration Safety

Contract state is isolated by contract id. Upgrades usually deploy a new contract id and then migrate selected state.

Rules:

  • Version state keys or stored values, for example reports:v1:<id> or { "formatVersion": 1 }.
  • Pin expected source and target code hashes.
  • Pin expected source and target manifest hashes.
  • Dry-run migration payloads before submitting.
  • Use resumable migration jobs for large state moves.
  • Keep batches small enough for fuel and write-effect limits.
  • Prefer schema-transform migrations when declarative transforms are enough.
  • Use contract-defined WASM migrations only when transformation logic needs contract code.
  • Keep old packages, manifests, registry entries, and migration receipts for replay and incident review.
  • Test rollback assumptions before deactivating the old contract.

Good migrated value:

json
{
  "formatVersion": 2,
  "sourceContractId": "contract-report-store-v1",
  "id": "report-001"
}

For migration flows, see Manifest Migrations and Publishing.

Package Handoff

This guide does not duplicate package, provenance, and registry rules. Before asking an operator or reviewer to approve a package, hand off enough evidence for those pages to be checked:

  • package directory;
  • noos-contract.json;
  • manifest;
  • WASM artifact;
  • package provenance signatures, if required;
  • tests and review notes;
  • registry payload or registry entry id, if required;
  • migration plan and receipts, if upgrading.

Use:

Review Checklist

Authorization:

  • [ ] Every method has the narrowest practical invoke.allow.
  • [ ] Write/admin-like methods do not use broad caller policies without review.
  • [ ] C2C target methods use exact contract principals or deliberate anyContract extension points.

Data and buckets:

  • [ ] Every bucket host operation has a matching manifest bucket declaration.
  • [ ] Contract principal bucket grants are minimal.
  • [ ] Caller bucket access is considered where host checks require it.
  • [ ] Events and returns contain no plaintext, secrets, or keys.

Execution limits:

  • [ ] Every loop is bounded.
  • [ ] ABI inputs cap arrays and large values.
  • [ ] Public or expensive methods have suitable maxFuel.
  • [ ] Tests cover traps, host errors, and fuel exhaustion where relevant.

ABI, events, and returns:

  • [ ] Inputs and stored values include version fields where they may evolve.
  • [ ] Required fields and enums are explicit.
  • [ ] Output and event schemas are documented and stable.

C2C:

  • [ ] Caller manifests declare outbound calls.
  • [ ] Target methods authorize the intended caller contract.
  • [ ] Dependency cycles and deactivation risk are reviewed.

Migrations:

  • [ ] Source and target hashes are pinned.
  • [ ] Migration dry-run has been reviewed.
  • [ ] Large migrations use resumable jobs.
  • [ ] Receipts and old package artifacts are archived.

Package/release handoff:

  • [ ] Package descriptor matches WASM and manifest hashes.
  • [ ] Provenance requirements are understood.
  • [ ] Registry requirements are understood.
  • [ ] Publishing checklist is complete.

Next Steps

Audience-first NOOSChain documentation.