sandscript.run

Grants

SandScript uses a grant system for capability-based security. Code inside a grant block runs with specific capabilities that the host provides. The host decides whether to approve or deny each grant request. On this site, the host is the runner page, and its policy is the set of identifiers you tick at the consent gate.

Basic usage

grant "database" {
  let result = Database.query();
  Console.log("result:", result);
}

When execution reaches the grant statement, the runtime yields to the host with a grant request. The host approves the request and provides the capability, or denies it.

The denied block

The denied block provides structured recovery when a grant is denied or revoked:

grant "database" {
  let result = Database.query();
  Console.log("result:", result);
} denied (revoked) {
  Console.log("capability denied:", revoked);
}

The denied block fires in two cases:

The optional parameter receives an array of the denied or revoked identifiers.

Multiple grants

Request multiple capabilities at once with parenthesized identifiers:

grant ("database", "network") {
  let data = Database.query();
  Network.send(data);
} denied (revoked) {
  Console.log("denied:", revoked);
}

All identifiers must be approved for the block to execute. If the host denies any of them, the denied block fires with the array of denied identifiers.

Block precedence

The denied block takes precedence over try/catch for grant-related revocation. They are independent control flow mechanisms:

grant "database" {
  try {
    let result = Database.query();
  } catch (e) {
    // Does NOT catch revocation
  }
} denied (revoked) {
  // Fires on revocation — takes precedence over try/catch
  Console.log("revoked:", revoked);
}

Without a denied block, revocation throws a GrantDeniedError, which propagates through try/catch normally.

Grant identifiers are expressions

A grant identifier is an arbitrary expression, not only a string. What a program will request is therefore not knowable before it runs. A host enforces its policy at request time, as an allowlist, never as a prediction. This is why the runner on this site compares identifiers by their marshalled bytes: two structurally equal identifiers must compare equal, whatever their type.