--- name: "semi-trusted-roles" description: "Trigger Pattern operator/admin/manager parties listed as signatory or controller, authority-gated choices - Inject Into Breadth agents, depth-state-trace" --- # SEMI_TRUSTED_ROLES Skill (DAML) > **Trigger Pattern**: operator/admin/manager/registrar party as `signatory` or `controller`, authority-gated choices beyond pure parameter-setting > **Inject Into**: Breadth agents, depth-state-trace > **Finding prefix**: `[DML-STR-N]` > **Rules referenced**: R2, R6, R10, R13 ``` operator|admin|manager|registrar|issuer|guardian|custodian|controller|signatory|authority ``` **DAML role context**: there are no role modifiers. A "role" is a `Party` that appears as a `signatory` and/or as a `controller` of privileged choices. Authority is held by holding that party's submission rights; a choice's required authorizers are its `controller` parties (AND-joined), a `create`/`archive` requires the contract's `signatory` parties. An operator/admin party is therefore SEMI_TRUSTED: trusted to act within its choices, but its key may be compromised and its actions must be analyzed bidirectionally (R6) — what it can do TO users, and what users can do to exploit/grief it. --- ## Step 1: Inventory Role Permissions In `{TEMPLATES}`, find every choice whose `controller` includes `{ROLE_PARTY}` (operator/admin/etc.), and every template where `{ROLE_PARTY}` is a `signatory`. For each: - Which `(Template, field)` does the choice's consequence `create`/`archive` (i.e. what state does it write)? - Does the choice `exercise` another template's choice (one-hop authority propagation)? - Parameters accepted from the caller (especially a caller-supplied `ContractId` or party)? - Consume-mode (`consuming`/`nonconsuming`/`pre`/`postconsuming`)? | Choice (Template.Choice) | Controller | Consume-Mode | (Template,field) Written | Exercises Other Templates | Caller Params | |--------------------------|-----------|--------------|--------------------------|---------------------------|---------------| **Auth patterns**: `controller operator`, `controller issuer, operator` (joint), `signatory operator` (operator co-signs every successor), choice that re-`fetch`es a contract and branches on a field the operator controls. --- ## Step 2: Analyze Within-Scope Abuse (Direction 1 — role harms users) For each permitted action, ask: **Timing Abuse** (ledger-time ordered, no public mempool): - Can the role exercise a choice at a harmful time (before a user's `query`-driven action, just before a deadline)? - Can the role DELAY a choice (skip a settlement/registration crank) to harm users? **Parameter Abuse**: - Can the role pass a harmful value (inflated amount, wrong `newOwner`, attacker-controlled `ContractId`)? - Are caller parameters validated in the choice body (`assertMsg`, `ensure` on the successor), or trusted implicitly? - Can the role supply a forged config/whitelist `ContractId` the choice does not bind to a trusted issuer? **Sequence / Omission Abuse**: - Can the role exercise choices out of order (accept before propose, settle before finalize)? - Can the role harm users by NOT exercising (never registering, never unlocking, never distributing)? Is there a recovery path if the role stops? --- ## Step 3: Model Attack Scenarios ``` Scenario A: Authority-Timing Attack 1. {ROLE_PARTY} observes a user's pending action via on-chain ACS state 2. {ROLE_PARTY} submits role_choice() to land in a prior/same ledger 3. ACS changes before the user's transaction commits 4. Impact: {TIMING_IMPACT} Note: no public mempool; ordering is ledger-time / submission based. Scenario B: Parameter / Forged-CID Attack 1. {ROLE_PARTY} exercises {ROLE_CHOICE} with {MALICIOUS_PARAMS} (amount, recipient, or a lookalike ContractId) 2. Choice body does not validate against {EXPECTED_CONSTRAINTS} / does not bind the CID to the trusted issuer 3. Impact: {PARAM_IMPACT} Scenario C: Key Compromise 1. {ROLE_PARTY}'s submission key is compromised 2. Attacker can exercise: {ROLE_CHOICES} and co-sign as signatory on: {SIGNATORY_TEMPLATES} 3. Maximum extractable / corruptible state: {MAX_DAMAGE} 4. Recovery: is there a choice to rotate/replace {ROLE_PARTY}? If the role is a hardcoded signatory, rotation may be impossible. ``` --- ## Step 4: Assess Mitigations - Is the role action gated by a propose/accept two-step (multi-transaction) flow rather than a single unilateral choice? - Is `{ROLE_PARTY}` a single party or a joint `controller` (AND of multiple parties, the DAML analog of multisig)? - **Does a rotation/replacement choice EXIST?** If the role is a `signatory` baked into live contracts, replacing it may require re-creating every contract. If NO rotation path → FINDING: authority irrevocable. Min Medium if the role can mutate user-held contracts. - Rate limits / caps tracked across transactions (accumulator template)? - If the role is also a maintainer of a `key`, note: maintainers MUST be signatories — compromise of the maintainer party affects key uniqueness too. **DAML patterns**: Propose→Accept (`OperatorProposal` create + `Accept` choice), joint `controller a, b`, an `Admin` contract whose `signatory` is a governance party. --- ## Step 5: Model User-Side Exploitation (Direction 2 — R6, MANDATORY) **Predictability Analysis**: - Is the role's behavior predictable (a published schedule, a state-triggered crank, a queue)? - Can users observe via the ACS when the role will act? - Can users submit to land before the role in ledger order? ``` Scenario D: User Exploits Role Timing 1. User observes {ROLE_PARTY} exercises {ROLE_CHOICE} when {CONDITION} holds in the ACS 2. User submits a transaction to land before the role's 3. User benefits from the known impending state change. Impact: {USER_EXPLOIT_IMPACT} Scenario E: User Griefs Role Preconditions 1. {ROLE_CHOICE} requires ACS state: {PRECONDITION} (a contract present, a key resolvable, an ensure satisfiable) 2. User archives/alters a contract the role's choice fetches, or creates a key-collision the role's lookupByKey trips on 3. Role's choice aborts (CONTRACT_NOT_FOUND / PreconditionFailed); protocol enters a degraded state. Impact: {GRIEF_IMPACT} Scenario F: User Forces Suboptimal Role Action 1. User shapes ACS state so the honest role's policy chooses a harmful branch 2. Impact: {SUBOPTIMAL_IMPACT} Scenario G: Stale State via Discrete Role Updates 1. A rate/config contract is only re-created when {ROLE_PARTY} exercises {UPDATE_CHOICE} 2. User acts at the stale rate, role updates, user exits. Impact: {RATE_ARBIT_IMPACT} ``` --- ## Step 6: Precondition Griefability Check For each choice controlled by `{ROLE_PARTY}`: | Choice | Preconditions (fetched contract / resolvable key / ensure) | User Can Manipulate? | Grief Impact | |--------|-----------------------------------------------------------|----------------------|--------------| **DAML griefing**: Can a user archive a contract the role's choice `fetch`es (CONTRACT_NOT_FOUND abort)? Can a user create a contract whose `key` collides / makes the role's `lookupByKey` return a stale or false-None result? Can a user inflate an accumulator/queue contract so the role's iterating choice aborts? --- ## Step 6b: Privileged-Choice Griefability (EXHAUSTIVE) Enumerate ALL authority-gated choices: | Choice | Authority (controller/signatory) | Preconditions | User Can Manipulate? | Grief Impact | |--------|----------------------------------|---------------|----------------------|--------------| **Completeness check**: Total authority-gated choices: {N}, analyzed: {M}. If M < N → analyze the missing ones. **DAML-specific checks**: - Can users create contracts that block a role's bulk cleanup/migration (one archive per contract → unbounded)? - Can in-flight Propose/Accept contracts block a role action (a pending proposal the role must resolve)? - Can a user archive a precondition contract just before the role's `exercise`, causing CONTRACT_NOT_FOUND? - Can an unsolicited contract created with the role as `observer`/`signatory` bloat the role's view or force consent? --- ## Common False Positives - **Pure read / nonconsuming view choices**: no abuse vector - **Idempotent choices**: timing abuse limited - **User-initiated dependency**: role acts only after the user proposes first — front-running may not apply - **Joint controller already present**: a choice already `controller a, b` is not single-where-joint - **Fully-trusted governance party**: if the project's trust table marks the party FULLY_TRUSTED, apply the −1 trusted-actor tier modifier (do NOT apply it to semi-trusted operator/admin) --- ## Finding Template ```markdown **ID**: [DML-STR-N] **Verdict**: CONFIRMED / PARTIAL / REFUTED / CONTESTED **Step Execution**: (see below) **Rules Applied**: [R2:___, R6:___, R10:___, R13:___] **Severity**: Critical/High/Medium/Low/Info **Location**: {Module}.daml:LineN (template X, choice Y) **Title**: {what the role party can do to users / what users can exploit or grief} **Description**: {specific abuse vector with code reference — which controller/signatory, which unvalidated parameter} **Impact**: {quantified damage at worst-state parameters — Rule 10} **PoC steer**: `submit roleParty (exerciseCmd ...)` succeeds with harmful state (Direction 1), or user `submit`/archive griefs the role's precondition so its choice aborts (Direction 2); `submitMustFail` proves a guard holds. ``` --- ## Step Execution Checklist (MANDATORY) | Step | Required | Completed? | Notes | |------|----------|------------|-------| | 1. Inventory Role Permissions | YES | | Controller + signatory choices | | 2. Analyze Within-Scope Abuse | YES | | | | 3. Model Attack Scenarios (A, B, C) | YES | | | | 4. Assess Mitigations | YES | | Rotation/replacement choice exists? | | 5. Model User-Side Exploitation (D, E, F, G) | **YES** | | **MANDATORY (R6)** — never skip | | 6. Precondition Griefability Check | **YES** | | **MANDATORY** — never skip | | 6b. Privileged-Choice Griefability | **YES** | | **MANDATORY** — never skip | ### Cross-Reference Markers **After Step 4**: DO NOT STOP HERE — Steps 5-6 analyze the reverse (R6) direction. **After Step 5**: Cross-reference with CHOICE_SEMANTICS for value-bearing role choices and CID_CAPABILITY_SAFETY for role choices accepting a caller-supplied `ContractId`. IF the role's actions are time-predictable → document ledger-ordering vectors. **After Step 6**: IF any precondition is user-griefable → severity >= MEDIUM. Document the protocol degradation timeline if the role is blocked indefinitely. **After Step 6b**: IF the role iterates over user-creatable contracts → check for unbounded iteration / abort. ### Output Format for Step Execution ```markdown **Step Execution**: ✓1,2,3,4,5,6,6b | (no skips for this skill) ```