T09 · Insecure Skill Coding Practices
Error
- Location
- references/handling.md:19
- Finding
- Plain-Text Interaction Spoofing Can Trigger Unauthorized Actions## Vulnerability Details **File Location**: `references/handling.md`, lines 19–29 **Vulnerability Type**: Authorization based on spoofable inbound text **Risk Level**: High ### Vulnerable Code Snippet ```text When a user clicks a button, you simply receive a message like: Clicked "Approve". Respond based on the button label: - If the message says `Clicked "Approve"` → execute the approved action - If the message says `Clicked "Reject"` → cancel the action - If the message says `Selected engineer from "Choose an agent..."` → assign to engineer No parsing of `custom_id` needed. OpenClaw handles all the plumbing. ``` The unsafe execution pattern is reinforced in `references/handling.md`, lines 122–129: ```text 1. **Send** component message with action buttons 2. **Receive** click as inbound message (`Clicked "Yes".`) 3. **Execute** the requested action 4. **Edit** the original message to show the result ``` It is also described in `SKILL.md`, lines 112–119: ```text When a user clicks a button or selects an option, OpenClaw delivers it as a normal inbound message: - Button click → `Clicked "Yes".` - Select → `Selected option_a from "Pick an option".` No special callback handling needed — just read the incoming message text. ``` ### Technical Analysis The Skill instructs an agent to authorize and execute actions by matching ordinary inbound message text against human-readable component labels. The documented logic does not require verification of trusted interaction metadata, such as: - Whether the input originated from an authentic Discord component event - The original message and component identifiers - The identity and authorization of the interacting user - The channel or workflow to which the interaction belongs - A server-generated opaque action identifier or nonce - The current workflow state and interaction expiration time Button labels and generated text such as `Clicked "Approve".` are predictable and can also be supplied as ordinary user- ...[truncated 1771 chars]
- Remediation
- ## Remediation Suggestions 1. **Do not authorize actions from message text alone.** Treat strings such as `Clicked "Approve".` as untrusted user input, not proof of a component interaction. 2. **Require trusted interaction metadata.** Before executing an action, verify: - The platform event is an authentic component interaction - The original message ID and component ID match an outstanding workflow - The initiating Discord user is authorized - The interaction occurred in the expected channel or thread - The action has not expired or already been consumed 3. **Use opaque action identifiers.** Bind each component to a server-generated, unpredictable identifier rather than using its display label as the authorization key. Store the identifier with the expected user, action, resource, message, and expiry. 4. **Enforce authorization at execution time.** `allowedUsers` may remain a user-interface restriction, but the action handler must independently verify the sender before performing privileged operations. 5. **Maintain workflow state.** Record pending interactions and atomically mark single-use actions as consumed to prevent replay, delayed execution, and cross-workflow confusion. 6. **Fail closed.** If trusted metadata is absent, ambiguous, expired, or inconsistent, do not execute the action. Ask the authorized user to initiate a fresh confirmation. 7. **Update the documentation.** Replace the label-only examples with secure examples that explicitly distinguish genuine component events from ordinary messages and demonstrate identity, context, state, and expiry validation.
