T09 · Insecure Skill Coding Practices
- Location
ops.sh:14- Finding
State-Changing API Requests May Be Executed Twice
- Content
View full analysis
Vulnerability Details
File Location:
ops.sh, lines 14-31
Vulnerability Type: Duplicate execution caused by response-formatting fallback
Risk Level: MediumVulnerable Code
bash # Helper function for API calls api_call() { local method=$1 local endpoint=$2 local data=$3 if [ -n "$data" ]; then curl -s -X "$method" "$RAVENCLAW_URL$endpoint" \ -H "Content-Type: application/json" \ -d "$data" | python3 -m json.tool 2>/dev/null || \ curl -s -X "$method" "$RAVENCLAW_URL$endpoint" \ -H "Content-Type: application/json" \ -d "$data" else curl -s -X "$method" "$RAVENCLAW_URL$endpoint" \ -H "Content-Type: application/json" | python3 -m json.tool 2>/dev/null || \ curl -s -X "$method" "$RAVENCLAW_URL$endpoint" \ -H "Content-Type: application/json" fi }Technical Analysis
The first
curlinvocation is piped intopython3 -m json.tool. The shell's||fallback is controlled by the exit status of the JSON formatter, not by whether the HTTP request was successfully processed.If Ravenclaw successfully performs an operation but returns an empty, malformed, truncated, or non-JSON response,
json.toolexits with a nonzero status. The fallback then issues the same HTTP request a second time.This affects state-changing endpoints used elsewhere in the script, including:
POST /sendPOST /schedulePOST /checkPOST /schedule/cancel/<id>
A presentation-layer failure therefore changes application behavior and violates the expectation that one CLI invocation results in one API operation.
Attack Path
- A user invokes a state-changing command such as
./ops.sh send. - The first
curlrequest reaches Ravenclaw, which processes and sends the email. - Ravenclaw, a reverse proxy, or an intermediary returns a succe ...[truncated 995 chars]
- Remediation
View remediation
Remediation Suggestions
Execute each HTTP request exactly once. Capture the response before attempting presentation formatting:
bash response=$(curl --fail-with-body -sS -X "$method" \ "$RAVENCLAW_URL$endpoint" \ -H "Content-Type: application/json" \ ${data:+--data "$data"}) curl_status=$? if [ "$curl_status" -ne 0 ]; then printf '%s\n' "$response" >&2 return "$curl_status" fi if ! printf '%s' "$response" | python3 -m json.tool; then printf '%s\n' "$response" fiBecause conditional argument expansion can be error-prone, separate data and no-data branches or use a Bash array for production code. Additional hardening should include:
- Use
curl --fail-with-body --show-errorand inspect HTTP status codes. - Never retry non-idempotent requests solely because response parsing failed.
- If retries are required, implement server-supported idempotency keys for send and schedule operations.
- Print success messages only after confirming a successful HTTP status and valid application result.
- Use
