/cid-capability-safety
Trigger Pattern Always required for DAML audits - Inject Into Breadth agents, depth-external, depth-edge-case
$ npx -y skills add PlamenTSV/plamen --skill cid-capability-safety --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
/cid-capability-safety
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-external, depth-edge-case
SKILL.md
cid-capability-safety.SKILL.mdname: "cid-capability-safety"
description: "Trigger Pattern Always required for DAML audits - Inject Into Breadth agents, depth-external, depth-edge-case"
CID_CAPABILITY_SAFETY Skill (DAML)
> **Trigger Pattern**: Always required for DAML audits > **Inject Into**: Breadth agents, depth-external, depth-edge-case > **Finding prefix**: `[DML-CC-N]` > **Rules referenced**: R4, R8, R12
A `ContractId t` is a DAML-distinctive capability: holding one lets a party `fetch`/`exercise` the referenced contract. When a choice accepts a `ContractId` as an *argument*, that CID is attacker-chosen unless the body re-binds it to the operation. The four high-yield bug shapes: (1) caller-supplied CID not bound to the operation (caller passes a lookalike), (2) a config/whitelist CID that is missing → the choice **fails open**, (3) a hardcoded/stale config CID that has been archived → the choice **bricks**, (4) wrong-CID / type confusion via unchecked `fromInterfaceContractId` coercion.
1. Caller-Supplied CID Inventory
For every choice that takes a `ContractId` argument, determine whether the body binds it to the operation:
| Template.Choice | CID Arg | Fetched/Exercised? | Bound To Operation? | Binding Check | Finding? | |-----------------|---------|--------------------|---------------------|---------------|----------| | `{T.C}` | `cid : ContractId T2` | YES/NO | YES/NO | `assertMsg ... (fetched.owner == this.owner)` / NONE | `[DML-CC-N]` if unbound |
**Critical patterns to flag**:
- A choice that `fetch cid` and then acts on the fetched contract's fields without asserting the fetched contract relates to `this` (e.g., same owner, same asset, expected template) — caller passes any CID they can see (`[ELEVATE:CID_BINDING]`).
- A choice that exercises a caller-supplied CID to move value, with no check that the CID is the *intended* counterparty contract.
**DAML note**: `fetch cid` succeeds for ANY contract the exercising party is a stakeholder of (or that is divulged). There is no implicit "this is the right contract" guarantee — the body MUST assert the relationship.
2. Config / Whitelist CID Fail-Open
A choice that looks up a config or whitelist contract by CID and proceeds when it is absent fails open.
| Template.Choice | Config/Whitelist CID Source | Absent-Handling | Fail-Open? | Finding? | |-----------------|-----------------------------|-----------------|------------|----------| | `{T.C}` | arg / template field / key | proceeds / errors / default-permit | YES/NO | `[DML-CC-N]` if fail-open |
**Attack**: A choice intended to enforce a whitelist fetches a `Whitelist` contract and checks membership, but if the whitelist CID is not provided (or `lookupByKey` returns `None`), the code path skips the check and permits the action (`[ELEVATE:FAIL_OPEN]`). Verify the absent/None case DENIES, not permits.
3. Hardcoded / Stale Config CID Brick
A CID stored in a template field (or hardcoded) that points to a contract which can be archived creates a brick.
| Template.Field | Holds A CID? | Referenced Contract Archivable? | Update Path For The CID? | Brick Risk? | |----------------|--------------|----------------------------------|--------------------------|-------------| | `{T.f}` | YES/NO | YES/NO | YES/NO | `[DML-CC-N]` if no update path |
**Attack**: A long-lived contract stores a `ContractId Config` field. The referenced `Config` is archived/superseded; every choice that `fetch`es the stale CID now gets `CONTRACT_NOT_FOUND` and bricks, with no choice to update the field (`[ELEVATE:CID_BRICK]`). Verify either the referenced contract is non-archivable or there is an authorized update choice.
4. Wrong-CID / Type Confusion (interface coercion)
`fromInterfaceContractId` and `coerceContractId` reinterpret a CID as a different template/interface without runtime proof.
| Site | Coercion | Source CID Verified As Target Type? | fetch-after-coerce Guard? | Finding? | |------|----------|--------------------------------------|---------------------------|----------| | `{choice:line}` | `fromInterfaceContractId @T cid` | YES/NO | YES/NO | `[DML-CC-N]` if unverified |
**Attack**: A choice coerces an interface CID to a concrete template via `fromInterfaceContractId @T` and immediately acts, but the underlying contract is a *different* template implementing the same interface. The subsequent `fetch` may succeed against an unintended template, or the choice trusts fields that mean something different. Verify a `fetch` after coercion (which fails for the wrong template) OR an explicit type/field assertion guards the coercion.
Finding Template
**ID**: [DML-CC-N]
**Severity**: [Critical if value moved on forged CID, High if fail-open/brick, Medium if type-confusion needs setup]
**Step Execution**: ✓1,2,3,4 | ✗(reasons) | ?(uncertain)
**Rules Applied**: [R4:✓/✗, R8:✓/✗, R12:✓/✗]
**Location**: {Module}.daml:LineN (template X, choice Y)
**Title**: Caller-supplied ContractId unbound / fail-open config CID in {Choice} allows {forged-target / bypass / brick}
**Description**: [The CID argument or config CID, the missing binding/absent-handling, and the contract the attacker substitutes]
**Impact**: [Action against attacker-chosen contract / whitelist bypass / permanent brick / type-confused field read]
**PoC steer**: pass a lookalike CID the attacker created and assert harm; or archive the config contract and assert the brick (CONTRACT_NOT_FOUND); or omit the whitelist CID and assert the gated action still succeeds.---
Step Execution Checklist (MANDATORY)
| Section | Required | Completed? | Notes | |---------|----------|------------|-------| | 1. Caller-Supplied CID Inventory | YES | ✓/✗/? | Every choice taking a ContractId arg | | 2. Config / Whitelist CID Fail-Open | IF config/whitelist CID lookups present | ✓/✗(N/A)/? | Verify absent → deny | | 3. Hardcoded / Stale Config CID Brick | IF a template field holds a CID | ✓/✗(N/A)/? | Verify update path exists | | 4. Wrong-CID
Read more
name: "cid-capability-safety" description: "Trigger Pattern Always required for DAML audits - Inject Into Breadth agents, depth-external, depth-edge-case"
CID_CAPABILITY_SAFETY Skill (DAML)
> **Trigger Pattern**: Always required for DAML audits > **Inject Into**: Breadth agents, depth-external, depth-edge-case > **Finding prefix**: `[DML-CC-N]` > **Rules referenced**: R4, R8, R12
A `ContractId t` is a DAML-distinctive capability: holding one lets a party `fetch`/`exercise` the referenced contract. When a choice accepts a `ContractId` as an *argument*, that CID is attacker-chosen unless the body re-binds it to the operation. The four high-yield bug shapes: (1) caller-supplied CID not bound to the operation (caller passes a lookalike), (2) a config/whitelist CID that is missing → the choice **fails open**, (3) a hardcoded/stale config CID that has been archived → the choice **bricks**, (4) wrong-CID / type confusion via unchecked `fromInterfaceContractId` coercion.
1. Caller-Supplied CID Inventory
For every choice that takes a `ContractId` argument, determine whether the body binds it to the operation:
| Template.Choice | CID Arg | Fetched/Exercised? | Bound To Operation? | Binding Check | Finding? | |-----------------|---------|--------------------|---------------------|---------------|----------| | `{T.C}` | `cid : ContractId T2` | YES/NO | YES/NO | `assertMsg ... (fetched.owner == this.owner)` / NONE | `[DML-CC-N]` if unbound |
**Critical patterns to flag**:
- A choice that `fetch cid` and then acts on the fetched contract's fields without asserting the fetched contract relates to `this` (e.g., same owner, same asset, expected template) — caller passes any CID they can see (`[ELEVATE:CID_BINDING]`).
- A choice that exercises a caller-supplied CID to move value, with no check that the CID is the *intended* counterparty contract.
**DAML note**: `fetch cid` succeeds for ANY contract the exercising party is a stakeholder of (or that is divulged). There is no implicit "this is the right contract" guarantee — the body MUST assert the relationship.
2. Config / Whitelist CID Fail-Open
A choice that looks up a config or whitelist contract by CID and proceeds when it is absent fails open.
| Template.Choice | Config/Whitelist CID Source | Absent-Handling | Fail-Open? | Finding? | |-----------------|-----------------------------|-----------------|------------|----------| | `{T.C}` | arg / template field / key | proceeds / errors / default-permit | YES/NO | `[DML-CC-N]` if fail-open |
**Attack**: A choice intended to enforce a whitelist fetches a `Whitelist` contract and checks membership, but if the whitelist CID is not provided (or `lookupByKey` returns `None`), the code path skips the check and permits the action (`[ELEVATE:FAIL_OPEN]`). Verify the absent/None case DENIES, not permits.
3. Hardcoded / Stale Config CID Brick
A CID stored in a template field (or hardcoded) that points to a contract which can be archived creates a brick.
| Template.Field | Holds A CID? | Referenced Contract Archivable? | Update Path For The CID? | Brick Risk? | |----------------|--------------|----------------------------------|--------------------------|-------------| | `{T.f}` | YES/NO | YES/NO | YES/NO | `[DML-CC-N]` if no update path |
**Attack**: A long-lived contract stores a `ContractId Config` field. The referenced `Config` is archived/superseded; every choice that `fetch`es the stale CID now gets `CONTRACT_NOT_FOUND` and bricks, with no choice to update the field (`[ELEVATE:CID_BRICK]`). Verify either the referenced contract is non-archivable or there is an authorized update choice.
4. Wrong-CID / Type Confusion (interface coercion)
`fromInterfaceContractId` and `coerceContractId` reinterpret a CID as a different template/interface without runtime proof.
| Site | Coercion | Source CID Verified As Target Type? | fetch-after-coerce Guard? | Finding? | |------|----------|--------------------------------------|---------------------------|----------| | `{choice:line}` | `fromInterfaceContractId @T cid` | YES/NO | YES/NO | `[DML-CC-N]` if unverified |
**Attack**: A choice coerces an interface CID to a concrete template via `fromInterfaceContractId @T` and immediately acts, but the underlying contract is a *different* template implementing the same interface. The subsequent `fetch` may succeed against an unintended template, or the choice trusts fields that mean something different. Verify a `fetch` after coercion (which fails for the wrong template) OR an explicit type/field assertion guards the coercion.
Finding Template
**ID**: [DML-CC-N]
**Severity**: [Critical if value moved on forged CID, High if fail-open/brick, Medium if type-confusion needs setup]
**Step Execution**: ✓1,2,3,4 | ✗(reasons) | ?(uncertain)
**Rules Applied**: [R4:✓/✗, R8:✓/✗, R12:✓/✗]
**Location**: {Module}.daml:LineN (template X, choice Y)
**Title**: Caller-supplied ContractId unbound / fail-open config CID in {Choice} allows {forged-target / bypass / brick}
**Description**: [The CID argument or config CID, the missing binding/absent-handling, and the contract the attacker substitutes]
**Impact**: [Action against attacker-chosen contract / whitelist bypass / permanent brick / type-confused field read]
**PoC steer**: pass a lookalike CID the attacker created and assert harm; or archive the config contract and assert the brick (CONTRACT_NOT_FOUND); or omit the whitelist CID and assert the gated action still succeeds.---
Step Execution Checklist (MANDATORY)
| Section | Required | Completed? | Notes | |---------|----------|------------|-------| | 1. Caller-Supplied CID Inventory | YES | ✓/✗/? | Every choice taking a ContractId arg | | 2. Config / Whitelist CID Fail-Open | IF config/whitelist CID lookups present | ✓/✗(N/A)/? | Verify absent → deny | | 3. Hardcoded / Stale Config CID Brick | IF a template field holds a CID | ✓/✗(N/A)/? | Verify update path exists | | 4. Wrong-CID
Autonomous 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

