T09 · Insecure Skill Coding Practices
Error
- Location
- src/index.mjs:68
- Finding
- Caller-Controlled External Votes Can Bypass Local Safety Evaluation<![CDATA[ ## Vulnerability Details **File Location**: `src/index.mjs:16-17` and `src/index.mjs:68-73` **Vulnerability Type**: Untrusted decision input and authorization bypass **Risk Level**: High ### Complete Code Snippet ```js if(input.mode!==undefined && !['persona','external_agent'].includes(input.mode)) return 'mode must be persona|external_agent'; if(input.external_votes!==undefined && !Array.isArray(input.external_votes)) return 'external_votes must be array'; ``` ```js const externalMode = input.mode === 'external_agent'; const idem = makeIdempotencyKey({ board_id, proposed_action: input.proposed_action, constraints: input.constraints||{}, persona_set_id: input.persona_set_id||null }); const prior = await getDecisionByKey(board_id, idem, statePath); if (prior?.response) return prior.response; let personaSet = externalMode ? null : (input.persona_set_id ? await getPersonaSet(board_id, input.persona_set_id, statePath) : await getLatest(board_id, 'persona_set', statePath)); if (!personaSet && !externalMode) { personaSet = { persona_set_id: null, personas: [1,2,3,4,5].map((n)=>({ persona_id:`default-${n}`, name:`Default Persona ${n}`, reputation:0.5 })) }; } const votes = externalMode ? input.external_votes : makeVotes(personaSet, input.proposed_action, input.constraints || {}); const ag = aggregateVotes(votes, { method:'WEIGHTED_APPROVAL_VOTE', approve_threshold:0.7 }); ``` ### Technical Analysis When `mode` is `external_agent`, the caller-provided `external_votes` array is passed directly to `aggregateVotes()`. Local validation only confirms that the value is an array. The code does not enforce a vote schema, authenticate voter identities, verify signatures, restrict voters to an authorized set, or establish an independent quorum. External mode also bypasses `makeVotes()`, which is where this package applies its local checks for high-risk irreversible actions, sensitive-data flags, and human-confirmation requirements. Consequently, a party capab ...[truncated 1468 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Define and enforce a strict schema for every external vote, including required fields, allowed vote values, confidence bounds, and numeric reputation bounds. 2. Authenticate each external voter and verify a digital signature over the board ID, action digest, vote, timestamp, and nonce. 3. Restrict accepted identities to a board-specific allowlist and reject duplicate, expired, replayed, or unknown votes. 4. Require a minimum quorum of distinct trusted voters rather than relying only on caller-supplied weights. 5. Do not trust reputation or voting weight supplied by the request. Load these values from trusted board state. 6. Apply non-bypassable local policy before aggregation. Sensitive-data, prohibited-action, and high-risk irreversible checks should be able to force `BLOCK` regardless of external consensus. 7. Bind the idempotency key to the vote set or trusted vote-artifact identifiers when external votes can affect the result. 8. Add negative tests proving that self-issued votes, unknown voters, forged weights, duplicate voters, and external votes for locally prohibited actions cannot produce `ALLOW`. ]]>
