T09 · Insecure Skill Coding Practices
Warning
- Location
- spec/input.schema.json:10
- Finding
- Unbounded External Vote Input Can Cause Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Locations**: - `spec/input.schema.json:10` - `spec/input.schema.json:75-83` - `src/index.mjs:53-57` - `src/index.mjs:116` - `src/index.mjs:161` **Vulnerability Type**: Uncontrolled resource consumption through unbounded, persisted input **Risk Level**: Medium ### Vulnerable Code `spec/input.schema.json:10`: ```json "external_votes": { "type": "array", "items": { "$ref": "#/$defs/externalVote" } }, ``` `spec/input.schema.json:75-83`: ```json "externalVote": { "type": "object", "additionalProperties": false, "required": ["persona_id", "name", "reputation_before", "vote", "confidence", "reasons", "red_flags", "suggested_edits"], "properties": { "persona_id": { "type": "string", "minLength": 1 }, "name": { "type": "string", "minLength": 1 }, "reputation_before": { "type": "number", "minimum": 0.05, "maximum": 0.95 }, "vote": { "type": "string", "enum": ["YES", "NO", "REWRITE"] }, "confidence": { "type": "number", "minimum": 0, "maximum": 1 }, "reasons": { "type": "array", "items": { "type": "string" } }, "red_flags": { "type": "array", "items": { "type": "string" } }, "suggested_edits": { "type": "array", "items": { "type": "string" } } } } ``` `src/index.mjs:53-57`: ```js if (input.external_votes !== undefined) { if (!Array.isArray(input.external_votes)) return 'external_votes must be array'; for (const vote of input.external_votes) { const ve = validateVote(vote); if (ve) return ve; } } ``` `src/index.mjs:116`: ```js const votes = externalMode ? input.external_votes : makeVotes(personaSet, flags); ``` `src/index.mjs:161`: ```js const d = await writeArtifact(board_id, 'decision', { idempotency_key: idem, decision_id, final_decision, policy_flags: flags, votes, aggregation: ag, response }, statePath); ``` ### Technical Analysis The input schema does not impose a `maxItems` restriction on `external_votes`. It also leaves the nested `reasons`, `red_flags`, an ...[truncated 2626 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Add a conservative `maxItems` limit to `external_votes` based on the maximum legitimate persona count: ```json "external_votes": { "type": "array", "minItems": 1, "maxItems": 50, "items": { "$ref": "#/$defs/externalVote" } } ``` 2. Bound every nested array and string: ```json "persona_id": { "type": "string", "minLength": 1, "maxLength": 128 }, "name": { "type": "string", "minLength": 1, "maxLength": 256 }, "reasons": { "type": "array", "maxItems": 20, "items": { "type": "string", "maxLength": 1000 } }, "red_flags": { "type": "array", "maxItems": 20, "items": { "type": "string", "maxLength": 500 } }, "suggested_edits": { "type": "array", "maxItems": 20, "items": { "type": "string", "maxLength": 1000 } } ``` 3. Apply suitable `maxLength` limits to all other caller-controlled strings, including `board_id`, `persona_set_id`, `request_id`, `service`, `version`, and `ticket_ref`. 4. Enforce a maximum request-body or input-file size before calling `JSON.parse`. API integrations should reject oversized bodies at the transport layer. 5. Calculate or estimate the serialized artifact size before invoking `writeArtifact`, and reject artifacts exceeding a configured upper bound. 6. Add authentication, per-caller rate limiting, memory limits, execution timeouts, filesystem quotas, and isolated writable volumes where the Skill is exposed through automation. 7. Add tests covering: - More than the permitted number of external votes. - Oversized strings. - Oversized nested arrays. - Maximum accepted boundary values. - Artifact-size rejection. - Repeated requests with distinct idempotency inputs. ]]>
