T09 · Insecure Skill Coding Practices
- Location
scripts/save_url.py:34- Finding
Unvalidated API Endpoint Allows Data Exfiltration and Internal Network Requests in URL Saving
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill does what it says: it saves user-provided URLs or memos to Cubox, with some ordinary integration risks around API-token handling and endpoint validation.
Install only if you are comfortable sending selected URLs, memo text, titles, descriptions, tags, and folder names to the Cubox API URL you configure. Treat CUBOX_API_URL as a secret token, avoid putting it in shared logs or committed files, and verify it points to the expected Cubox HTTPS endpoint before use.
scripts/save_url.py:34Unvalidated API Endpoint Allows Data Exfiltration and Internal Network Requests in URL Saving
scripts/save_memo.py:34Unvalidated API Endpoint Allows Memo Exfiltration and Internal Network Requests
README.md:28Unpinned Requests Dependency Creates a Mutable Supply-Chain Risk
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"Content-Type": "application/json"
}
response = requests.post(api_url, json=payload, headers=headers)
response.raise_for_status()
return response.json() if response.text else {"status": "success"}
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"Content-Type": "application/json"
}
response = requests.post(api_url, json=payload, headers=headers)
response.raise_for_status()
return response.json() if response.text else {"status": "success"}
The declared description states the skill can save both web pages and memos to Cubox. However, the supplied code chunk implements only memo creation: it constructs a payload with type "memo" and content text, then posts it to the configured Cubox API endpoint. There is no logic for accepting a URL, fetching page data, or saving a web page/bookmark. This is a material description-to-behavior mismatch because one of the declared primary capabilities is absent from the actual code.
The declared description says the skill can save both web pages and memos to Cubox using the Open API. The supplied code only supports creating a payload with type "url" and content set to the provided URL, then POSTing it to the Cubox API. There is no functionality for saving memos, freeform text, or note content. The rest of the behavior—sending data to Cubox via API and supporting metadata like title, description, tags, and folder—matches the declared purpose. This is therefore a partial but material mismatch in capabilities.
The README tells users to export a full Cubox API URL containing an embedded token as an environment variable, but gives no warning that this value is a secret. Environment variables are commonly exposed through shell history, process listings, debug logs, CI job output, or accidental screenshots/copy-paste, so treating a bearer-style API URL casually increases the chance of credential leakage and unauthorized saves to the user's Cubox account.
The skill requires both network access and an environment-stored secret (CUBOX_API_URL), but it does not declare any explicit tool scope or permissions boundary. This increases the risk of overbroad execution in agent environments, where undeclared capabilities can enable unintended outbound requests or secret use without clear operator review.
This code posts the user-provided memo content and optional metadata to the URL in CUBOX_API_URL, which is an external network transmission of user data. Although the module docstring says it saves a memo to Cubox, there is no explicit runtime disclosure, confirmation, or warning near the HTTP request that user content will be transmitted to a remote service.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
"Content-Type": "application/json"
}
response = requests.post(api_url, json=payload, headers=headers)
response.raise_for_status()
return response.json() if response.text else {"status": "success"}
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
"Content-Type": "application/json"
}
response = requests.post(api_url, json=payload, headers=headers)
response.raise_for_status()
return response.json() if response.text else {"status": "success"}
No suspicious patterns detected.