T09 · Insecure Skill Coding Practices
- Location
scripts/gradient_image.py:91- Finding
Output Path Validation Can Be Bypassed to Write Outside the Working Directory
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill mostly matches its DigitalOcean AI purpose, but its image-saving and pricing-cache code have unsafe local file-write behavior that should be reviewed before installation.
Review this skill before installing. Use it only if you are comfortable sending selected prompts and the Gradient API key to DigitalOcean, avoid enabling --cache for sensitive prompts, run it as a non-privileged user, and prefer a sandboxed working directory for image outputs until the path validation, URL download controls, and /tmp cache handling are fixed.
scripts/gradient_image.py:91Output Path Validation Can Be Bypassed to Write Outside the Working Directory
scripts/gradient_image.py:106Unrestricted Server-Supplied Image URL Enables SSRF and Unbounded Downloads
scripts/gradient_pricing.py:24Predictable Shared Temporary Cache Enables Cache Poisoning and Symlink-Based File Overwrite
SKILL.md:14Unpinned Third-Party Dependencies Reduce Supply-Chain Integrity
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"max_tokens": max_tokens,
}
resp = requests.post(CHAT_COMPLETIONS_URL, headers=headers, json=payload, timeout=60)
resp.raise_for_status()
data = resp.json()
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
if store:
payload["store"] = True
resp = requests.post(RESPONSES_URL, headers=headers, json=payload, timeout=60)
resp.raise_for_status()
data = resp.json()
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"size": size,
}
resp = requests.post(IMAGE_GENERATION_URL, headers=headers, json=payload, timeout=120)
resp.raise_for_status()
data = resp.json()
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"Content-Type": "application/json",
}
resp = requests.get(f"{INFERENCE_BASE_URL}/models", headers=headers, timeout=15)
resp.raise_for_status()
data = resp.json()
The code accurately supports part of the description: it is OpenAI-compatible in style, calls DigitalOcean Gradient serverless inference, supports chat completions, supports the Responses API, and exposes prompt caching through the store flag. However, the declared description also claims capabilities to discover available models and pricing and to generate images. None of those behaviors appear in this code chunk: there are no endpoints or functions for listing models, checking prices, or creating images. The primary purpose is narrower than declared, so this is a description/behavior mismatch.
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
Direct API call:
curl -s https://inference.do-ai.run/v1/models \
-H "Authorization: Bearer $GRADIENT_API_KEY" | python3 -m json.tool
The skill advertises capabilities that include environment access, file read/write, and network use, but it does not declare any explicit tool scope such as permissions or allowed-tools. That creates an avoidable trust gap: a user or orchestrator cannot easily constrain the skill to the minimum required privileges, increasing the blast radius if the scripts are modified, abused, or invoked in an unexpected context.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
Direct API call:
curl -s https://inference.do-ai.run/v1/chat/completions \
-H "Authorization: Bearer $GRADIENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
Direct API call:
curl -s https://inference.do-ai.run/v1/images/generations \
-H "Authorization: Bearer $GRADIENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
"max_tokens": max_tokens,
}
resp = requests.post(CHAT_COMPLETIONS_URL, headers=headers, json=payload, timeout=60)
resp.raise_for_status()
data = resp.json()
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
if store:
payload["store"] = True
resp = requests.post(RESPONSES_URL, headers=headers, json=payload, timeout=60)
resp.raise_for_status()
data = resp.json()
The --cache option enables prompt caching/storage on the remote service, which can cause user prompts to be retained or reused by the provider without any explicit runtime warning or consent step. In an agent skill context, prompts may contain sensitive user or workspace data, making silent retention a privacy and data-handling risk.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
"size": size,
}
resp = requests.post(IMAGE_GENERATION_URL, headers=headers, json=payload, timeout=120)
resp.raise_for_status()
data = resp.json()
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
"""Write pricing data to the cache file."""
data["cached_at"] = time.time()
try:
CACHE_PATH.write_text(json.dumps(data, indent=2))
except OSError:
pass # Best-effort caching
No suspicious patterns detected.