/authorization-model
Trigger Pattern Always required for DAML audits - Inject Into Breadth agents, depth-state-trace, depth-external
$ npx -y skills add PlamenTSV/plamen --skill authorization-model --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/authorization-model
Context preview
The summary Claude sees to decide when to auto-load this skill.
Trigger Pattern Always required for DAML audits - Inject Into Breadth agents, depth-state-trace, depth-external
SKILL.md
authorization-model.SKILL.mdname: "authorization-model"
description: "Trigger Pattern Always required for DAML audits - Inject Into Breadth agents, depth-state-trace, depth-external"
AUTHORIZATION_MODEL Skill (DAML)
> **Trigger Pattern**: Always required for DAML audits > **Inject Into**: Breadth agents, depth-state-trace, depth-external > **Finding prefix**: `[DML-AM-N]` > **Rules referenced**: R4, R6, R12, R13
DAML's authorization model has no `msg.sender`. Authority flows through the transaction tree: the required authorizers of every node MUST be a subset of the parties who authorized the submission. A `create` requires the new contract's `signatory` parties; an `exercise`/`fetch` requires the choice's `controller` parties; an `archive` requires the signatories. Signatory authority propagates exactly ONE hop into a choice's consequences. The most common critical bug class is a choice whose controller is derived from a choice *argument* (privilege injection), or a choice that performs a privileged action with only one authorizer where joint authorization is required.
1. Choice-Authority Inventory
For EVERY choice in each template, record who must authorize it and what it does:
| Template.Choice | Consume-Mode | Controller Expr | Controller Source | Privileged Action? | Co-Auth Required? | |-----------------|--------------|-----------------|-------------------|--------------------|-------------------| | `{T.C}` | consuming/nonconsuming/pre/postconsuming | `{controller expr}` | FIXED-SIGNATORY / ARG-DERIVED / FETCHED | YES/NO | YES/NO |
**Critical patterns to flag**:
- A choice that moves value, changes ownership, or updates config but lists only ONE controller where the action affects multiple parties (single-where-joint → `[ELEVATE:MISSING_COAUTH]`).
- A `controller` expression that reads a field of the *choice argument* rather than a template signatory/fixed party (privilege injection → `[ELEVATE:PARAM_CONTROLLER]`, ALWAYS flag).
**DAML note**: `controller p` makes `p` the required authorizer AND an automatic observer. A controller derived from `arg.someParty` lets the caller name themselves as the authorizer — there is no `msg.sender` to constrain it.
2. Controller-Source Trace (privilege injection)
For each choice whose controller is NOT a fixed template signatory, trace where the controlling party comes from:
| Template.Choice | Controller Party Origin | Bound to Template Signatory? | Attacker Can Set It? | Finding? | |-----------------|-------------------------|------------------------------|----------------------|----------| | `{T.C}` | `arg.X` / `this.field` / `fetch(...).field` | YES/NO | YES/NO | `[DML-AM-N]` if attacker-settable |
**Attack**: If `controller` resolves from a value the caller supplies (choice argument, or a field of a contract the caller created), the caller authorizes their own privileged action. Compare against the intended authority from the AUTHORIZATION MATRIX in `attack_surface.md`.
**ARG-DERIVED controller is ALWAYS a finding candidate** — it must be proven safe (the arg is itself constrained by a prior signatory check) before it is dismissed.
3. In-Body Validation Enumeration
A correct controller does NOT replace in-body checks. Enumerate the validation each choice performs against its controller:
| Template.Choice | Controller | In-Body Check Present? | Check Expr | Sufficient? | |-----------------|------------|------------------------|-----------|-------------| | `{T.C}` | `{party}` | YES/NO | `assertMsg "..." (owner == ctl)` / NONE | YES/NO |
**Check for**:
- A choice that lets ANY party be the controller but then acts on `this.owner` without asserting `owner == controllingParty` (missing `owner == party`).
- A choice that updates a per-party balance/position but does not bind the controller to the affected party.
- Reliance on the controller alone where the choice consequences touch parties the controller should not be able to affect.
4. Guard / Whitelist / Flag Bypass
Enumerate every conditional that gates a privileged path:
| Template.Choice | Guard Expr | Guard Source | Bypassable? | Finding? | |-----------------|-----------|--------------|-------------|----------| | `{T.C}` | `when (paused == False)` / `elem p whitelist` | template field / arg / fetched | YES/NO | `[DML-AM-N]` if bypass |
**Patterns**:
- A flag (`paused`, `frozen`, `active`) read from a contract the caller can re-create with a forged value.
- A whitelist membership test against a list supplied as a choice argument rather than a signed template field.
- A guard short-circuited by an alternative choice on the same template that reaches the same consequence without the guard.
5. Fetch-Based Auth Bypass
A `fetch`/`fetchByKey` returns a contract that the choice may branch on for an authorization decision. If the fetched contract is not bound to a trusted signatory, the caller can forge it.
| Template.Choice | Fetched Template | Auth Decision On Fetched Field? | Fetched Contract Signed By Trusted Party? | Finding? | |-----------------|------------------|----------------------------------|-------------------------------------------|----------| | `{T.C}` | `{T2}` | YES/NO | YES/NO | `[DML-AM-N]` if unbound |
**Attack**: A choice fetches a `Config`/`Role`/`Approval` contract and grants access based on a field, but the caller can create that contract themselves (they are a signatory of it). The auth decision rests on attacker-controlled state. Verify the fetched contract's signatories include the party whose authority the decision relies on (`[ELEVATE:FETCH_AUTH]`).
Finding Template
**ID**: [DML-AM-N]
**Severity**: [Critical if value/ownership, High if config/co-auth, Medium if view-privileged]
**Step Execution**: ✓1,2,3,4,5 | ✗(reasons) | ?(uncertain)
**Rules Applied**: [R4:✓/✗, R6:✓/✗, R12:✓/✗, R13:✓/✗]
**Location**: {Module}.daml:LineN (template X, choice Y)
**Title**: {Choice} controller derived from argument / missing co-authorization allows unRead more
name: "authorization-model" description: "Trigger Pattern Always required for DAML audits - Inject Into Breadth agents, depth-state-trace, depth-external"
AUTHORIZATION_MODEL Skill (DAML)
> **Trigger Pattern**: Always required for DAML audits > **Inject Into**: Breadth agents, depth-state-trace, depth-external > **Finding prefix**: `[DML-AM-N]` > **Rules referenced**: R4, R6, R12, R13
DAML's authorization model has no `msg.sender`. Authority flows through the transaction tree: the required authorizers of every node MUST be a subset of the parties who authorized the submission. A `create` requires the new contract's `signatory` parties; an `exercise`/`fetch` requires the choice's `controller` parties; an `archive` requires the signatories. Signatory authority propagates exactly ONE hop into a choice's consequences. The most common critical bug class is a choice whose controller is derived from a choice *argument* (privilege injection), or a choice that performs a privileged action with only one authorizer where joint authorization is required.
1. Choice-Authority Inventory
For EVERY choice in each template, record who must authorize it and what it does:
| Template.Choice | Consume-Mode | Controller Expr | Controller Source | Privileged Action? | Co-Auth Required? | |-----------------|--------------|-----------------|-------------------|--------------------|-------------------| | `{T.C}` | consuming/nonconsuming/pre/postconsuming | `{controller expr}` | FIXED-SIGNATORY / ARG-DERIVED / FETCHED | YES/NO | YES/NO |
**Critical patterns to flag**:
- A choice that moves value, changes ownership, or updates config but lists only ONE controller where the action affects multiple parties (single-where-joint → `[ELEVATE:MISSING_COAUTH]`).
- A `controller` expression that reads a field of the *choice argument* rather than a template signatory/fixed party (privilege injection → `[ELEVATE:PARAM_CONTROLLER]`, ALWAYS flag).
**DAML note**: `controller p` makes `p` the required authorizer AND an automatic observer. A controller derived from `arg.someParty` lets the caller name themselves as the authorizer — there is no `msg.sender` to constrain it.
2. Controller-Source Trace (privilege injection)
For each choice whose controller is NOT a fixed template signatory, trace where the controlling party comes from:
| Template.Choice | Controller Party Origin | Bound to Template Signatory? | Attacker Can Set It? | Finding? | |-----------------|-------------------------|------------------------------|----------------------|----------| | `{T.C}` | `arg.X` / `this.field` / `fetch(...).field` | YES/NO | YES/NO | `[DML-AM-N]` if attacker-settable |
**Attack**: If `controller` resolves from a value the caller supplies (choice argument, or a field of a contract the caller created), the caller authorizes their own privileged action. Compare against the intended authority from the AUTHORIZATION MATRIX in `attack_surface.md`.
**ARG-DERIVED controller is ALWAYS a finding candidate** — it must be proven safe (the arg is itself constrained by a prior signatory check) before it is dismissed.
3. In-Body Validation Enumeration
A correct controller does NOT replace in-body checks. Enumerate the validation each choice performs against its controller:
| Template.Choice | Controller | In-Body Check Present? | Check Expr | Sufficient? | |-----------------|------------|------------------------|-----------|-------------| | `{T.C}` | `{party}` | YES/NO | `assertMsg "..." (owner == ctl)` / NONE | YES/NO |
**Check for**:
- A choice that lets ANY party be the controller but then acts on `this.owner` without asserting `owner == controllingParty` (missing `owner == party`).
- A choice that updates a per-party balance/position but does not bind the controller to the affected party.
- Reliance on the controller alone where the choice consequences touch parties the controller should not be able to affect.
4. Guard / Whitelist / Flag Bypass
Enumerate every conditional that gates a privileged path:
| Template.Choice | Guard Expr | Guard Source | Bypassable? | Finding? | |-----------------|-----------|--------------|-------------|----------| | `{T.C}` | `when (paused == False)` / `elem p whitelist` | template field / arg / fetched | YES/NO | `[DML-AM-N]` if bypass |
**Patterns**:
- A flag (`paused`, `frozen`, `active`) read from a contract the caller can re-create with a forged value.
- A whitelist membership test against a list supplied as a choice argument rather than a signed template field.
- A guard short-circuited by an alternative choice on the same template that reaches the same consequence without the guard.
5. Fetch-Based Auth Bypass
A `fetch`/`fetchByKey` returns a contract that the choice may branch on for an authorization decision. If the fetched contract is not bound to a trusted signatory, the caller can forge it.
| Template.Choice | Fetched Template | Auth Decision On Fetched Field? | Fetched Contract Signed By Trusted Party? | Finding? | |-----------------|------------------|----------------------------------|-------------------------------------------|----------| | `{T.C}` | `{T2}` | YES/NO | YES/NO | `[DML-AM-N]` if unbound |
**Attack**: A choice fetches a `Config`/`Role`/`Approval` contract and grants access based on a field, but the caller can create that contract themselves (they are a signatory of it). The auth decision rests on attacker-controlled state. Verify the fetched contract's signatories include the party whose authority the decision relies on (`[ELEVATE:FETCH_AUTH]`).
Finding Template
**ID**: [DML-AM-N]
**Severity**: [Critical if value/ownership, High if config/co-auth, Medium if view-privileged]
**Step Execution**: ✓1,2,3,4,5 | ✗(reasons) | ?(uncertain)
**Rules Applied**: [R4:✓/✗, R6:✓/✗, R12:✓/✗, R13:✓/✗]
**Location**: {Module}.daml:LineN (template X, choice Y)
**Title**: {Choice} controller derived from argument / missing co-authorization allows unAutonomous Web3 security auditor for Claude Code and OpenAI Codex CLI. Orchestrates 18-100 AI agents across 40+ phases to produce audit reports with verified PoC exploits — for smart contracts and L1 node-client infrastructure.
Repo: PlamenTSV/plamen
Other skills on plamen.
- /ability-analysis
Trigger Pattern Always (Aptos Move) - foundational security check - Inject Into Breadth agents, depth agents
Open skill - /bit-shift-safety
Trigger Pattern Always (Aptos Move) - Move VM aborts on shift = bit width - Inject Into Breadth agents, depth-edge-case
Open skill - /centralization-risk
Trigger Protocol has privileged roles (admin, operator, governance, resource account owner) - Covers Single points of failure, privilege escalation, external governance dependen...
Open skill - /cross-chain-timing
Trigger Pattern wormhole|layerzero|ccip|bridge|cross_chain|vaa|guardian|emitter|relay|remote_chain|payload|nonce.sequence - Inject Into Breadth agents, depth-external
Open skill - /dependency-audit
Trigger EXTERNAL_LIB flag detected (protocol uses third-party Move dependencies) - Used by Breadth agents, depth-external
Open skill - /economic-design-audit
Trigger Pattern MONETARY_PARAMETER flag (required) - Inject Into Breadth agents (merged via M4 hierarchy)
Open skill

