T09 · Insecure Skill Coding Practices
- Location
scripts/aivideo-client.mjs:201- Finding
Unvalidated Task Identifier Enables Authenticated Same-Origin Path Manipulation
- Content
View full analysis
Vulnerability Details
File Location:
scripts/aivideo-client.mjs:201-222andscripts/run-workflow.mjs:73-94
Vulnerability Type: Authenticated request path injection
Risk Level: MediumUser-controlled
taskIdvalues are inserted directly into API paths without validation or URL encoding.Relevant client code:
javascript async getTask(taskId) { return request({ method: "GET", path: `/api/v1/tasks/${taskId}`, idempotent: true, }); }, async getStatus(taskId) { return request({ method: "GET", path: `/api/v1/tasks/${taskId}/status`, idempotent: true, }); }, async cancelTask(taskId) { return request({ method: "PUT", path: `/api/v1/tasks/${taskId}/cancel`, idempotent: false, }); },The value originates directly from a command-line argument:
javascript async function runAction(client, args) { const action = args.action; const taskId = args.taskId; if (action === "getStatus") { if (!taskId) throw new Error("--taskId is required for --action getStatus"); const result = await client.getStatus(taskId); print(result); return; } if (action === "getTask") { if (!taskId) throw new Error("--taskId is required for --action getTask"); const result = await client.getTask(taskId); print(result); return; } if (action === "cancelTask") { if (!taskId) throw new Error("--taskId is required for --action cancelTask"); const result = await client.cancelTask(taskId); print(result); return; } }Technical Analysis
The client constructs the request URL by concatenating
config.baseUrland a path containing the rawtaskId. It does not enforce the documented task-ID format and does not encode the identifier as an individual URL path segment.Consequently, values containing path-navigation tokens such as
../, query delimite ...[truncated 2862 chars]- Remediation
View remediation
Remediation Suggestions
-
Validate task identifiers before constructing any request. Use a strict allowlist matching the provider's actual identifier format, for example:
javascript function validateTaskId(taskId) { if (typeof taskId !== "string" || !/^ck[a-zA-Z0-9_-]+$/.test(taskId)) { throw new Error("Invalid task ID"); } return taskId; } -
Encode the validated identifier as one URL path segment:
javascript const safeTaskId = encodeURIComponent(validateTaskId(taskId)); path: `/api/v1/tasks/${safeTaskId}` -
Construct requests with the
URLAPI and enforce destination invariants immediately beforefetch:javascript const url = new URL(path, config.baseUrl); const expectedOrigin = new URL(config.baseUrl).origin; if (url.origin !== expectedOrigin) { throw new Error("Unexpected API origin"); } -
Restrict each operation to its expected normalized pathname pattern. Reject paths containing traversal tokens, query strings, fragments, encoded separators, or unexpected prefixes.
-
Apply validation inside the client methods rather than only in the CLI so that direct programmatic callers cannot bypass it.
-
Add regression tests covering
../,%2e%2e,/,?,#, backslashes, percent-encoded separators, empty values, oversized identifiers, and valid task IDs. -
If supported by the service, use an API credential scoped exclusively to video-generation task operations to reduce the impact of any future request-routing flaw.
-
