T09 · Insecure Skill Coding Practices
- Location
SKILL.md:85- Finding
Unquoted Call Identifier Allows curl Argument Injection and Potential Credential Disclosure
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 85–89
Vulnerability Type: Shell argument injection
Risk Level: HighVulnerable Code
bash curl -s https://api.speko.dev/v1/calls/$ID \ -H "Authorization: Bearer $SPEKO_PLATFORM_API_KEY" | jq '{status, duration_seconds, ended_at}' curl -s https://api.speko.dev/v1/calls/$ID/report \ -H "Authorization: Bearer $SPEKO_PLATFORM_API_KEY" | jq '{summary, outcome, cost_micro_usd}'Technical Analysis
The call identifier is interpolated into both curl commands without quoting or validation. In a POSIX-compatible shell, an unquoted variable is subject to field splitting and pathname expansion. Although the document states that call identifiers are UUIDs, the example commands do not enforce that requirement before using
$ID.If attacker-controlled input containing whitespace is assigned to
$ID, curl can interpret the resulting fields as additional command-line options or request URLs rather than as one URL path component. The fixedAuthorizationheader may then be applied to an attacker-controlled URL included in the injected arguments.This is an argument-injection issue rather than direct shell metacharacter execution: shell operators embedded inside an expanded variable are not reparsed as shell syntax. Nevertheless, curl's support for multiple URLs and numerous command-line options provides a practical exploitation surface.
Attack Path
- An attacker supplies a crafted value while presenting it as a call identifier.
- The agent or operator assigns that value to
$IDwithout checking that it is a single valid UUID. - The value is expanded unquoted in one of the documented curl commands.
- Shell field splitting converts whitespace-separated content into multiple curl arguments.
- curl interprets an injected field as another URL or option.
- A request may be made to an attacker-controlled endpoint with the platform bearer ...[truncated 743 chars]
- Remediation
View remediation
Remediation Suggestions
-
Validate the identifier before invoking curl. Accept only a canonical UUID and reject every other value:
bash case "$ID" in *[!0-9A-Fa-f-]*|'') printf '%s\n' "Invalid call ID" >&2 exit 1 ;; esac if ! printf '%s\n' "$ID" | grep -Eq '^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[1-5][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$'; then printf '%s\n' "Invalid call ID" >&2 exit 1 fi -
Quote the complete URL so the identifier cannot undergo field splitting or pathname expansion:
bash curl --silent --show-error --fail-with-body \ -H "Authorization: Bearer $SPEKO_PLATFORM_API_KEY" \ -- "https://api.speko.dev/v1/calls/$ID" | jq '{status, duration_seconds, ended_at}' curl --silent --show-error --fail-with-body \ -H "Authorization: Bearer $SPEKO_PLATFORM_API_KEY" \ -- "https://api.speko.dev/v1/calls/$ID/report" | jq '{summary, outcome, cost_micro_usd}' -
Do not execute either request unless UUID validation succeeds. Avoid attempting to sanitize malformed input into a valid identifier.
-
Configure curl defensively: reject unexpected redirects, use an explicit HTTPS-only protocol policy where supported, and avoid features such as configuration-file loading when processing untrusted input.
-
If these commands were previously used with untrusted identifiers, rotate the platform API key and review platform audit logs for requests from unexpected sources, unauthorized calls, and transcript or report access.
-
