T09 · Insecure Skill Coding Practices
Warning
- Location
- src/index.ts:588
- Finding
- Unvalidated Identifiers Permit Authenticated API Path Manipulation## Vulnerability Details **File Location**: `src/index.ts:588-594` and equivalent identifier interpolation at `src/index.ts:634-640`, `src/index.ts:656-693` **Vulnerability Type**: Improper validation and encoding of URL path segments **Risk Level**: Medium ### Vulnerable Code ```typescript case "volkern_get_lead": return volkernRequest(`/leads/${args.leadId}`); case "volkern_create_lead": return volkernRequest("/leads", "POST", args); case "volkern_update_lead": { const { leadId, ...data } = args; return volkernRequest(`/leads/${leadId}`, "PATCH", data); } ``` The same pattern is used for catalog items, services, tasks, interactions, and notes: ```typescript case "volkern_get_catalogo_item": return volkernRequest(`/catalogo/${args.itemId}`); case "volkern_update_catalogo_item": { const { itemId, ...data } = args; return volkernRequest(`/catalogo/${itemId}`, "PATCH", data); } case "volkern_get_servicio": return volkernRequest(`/servicios/${args.servicioId}`); case "volkern_create_task": { const { leadId, ...taskData } = args; return volkernRequest(`/leads/${leadId}/tasks`, "POST", taskData); } case "volkern_list_tasks": return volkernRequest(`/leads/${args.leadId}/tasks`); case "volkern_complete_task": return volkernRequest(`/tasks/${args.taskId}`, "PATCH", { completada: true }); case "volkern_list_interactions": return volkernRequest(`/leads/${args.leadId}/interactions`); case "volkern_create_interaction": { const { leadId, ...interactionData } = args; return volkernRequest(`/leads/${leadId}/interactions`, "POST", interactionData); } case "volkern_list_notes": return volkernRequest(`/leads/${args.leadId}/notes`); case "volkern_create_note": { const { leadId: noteLeadId, ...noteData } = args; return volkernRequest(`/leads/${noteLeadId}/notes`, "POST", noteData); } ``` The resulting request includes the configured bearer credent ...[truncated 3130 chars]
- Remediation
- ## Remediation Suggestions 1. Validate every entity identifier before constructing an API path. Use the exact identifier grammar supported by Volkern rather than merely checking that the value is a string. 2. Reject identifiers containing path separators, traversal sequences, query delimiters, fragment delimiters, control characters, or encoded variants of those values. 3. Encode each validated path segment with `encodeURIComponent` before interpolation. 4. Centralize path construction to prevent future handlers from bypassing validation. ```typescript function encodeEntityId(value: unknown, fieldName: string): string { if (typeof value !== "string") { throw new Error(`${fieldName} must be a string`); } // Replace this expression with Volkern's exact documented CUID grammar. if (!/^c[a-z0-9]+$/i.test(value)) { throw new Error(`${fieldName} has an invalid format`); } return encodeURIComponent(value); } case "volkern_get_lead": { const leadId = encodeEntityId(args.leadId, "leadId"); return volkernRequest(`/leads/${leadId}`); } ``` 5. Apply the same protection to `leadId`, `itemId`, `servicioId`, `taskId`, and every future identifier used in a URL path. 6. Perform runtime argument validation in the request handler rather than relying only on MCP tool-schema declarations. 7. Add negative tests covering `/`, `../`, `?`, `#`, `%2f`, `%2e%2e`, backslashes, control characters, and mixed or double encoding. 8. Regenerate `dist/index.js` from the corrected TypeScript source and verify that the distributed code contains the same validation. 9. Continue enforcing server-side API authorization, tenant isolation, and per-object permission checks as a separate defense-in-depth boundary.
