T09 · Insecure Skill Coding Practices
- Location
index.py:73- Finding
Configurable API Endpoints Can Exfiltrate Bearer Credentials
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a disclosed social media posting tool, but it can publish externally on a schedule and has unsafe network and credential handling that warrants review before installation.
Install only after reviewing the public-posting workflow and credentials. Use least-privilege API keys, protect the JSON config files, avoid passing secrets on the command line, restrict outbound network access to the intended provider domains, and require human approval or a dry run before scheduled posts go live.
index.py:73Configurable API Endpoints Can Exfiltrate Bearer Credentials
index.py:84Unvalidated Render URL Enables Server-Side Request Forgery and Response Relay
index.py:161NewsAPI Credential Is Required as a Command-Line Argument
The description understates the skill's real behavior: it not only retrieves news, but also renders media, reads local config files, writes output, and publishes content to third-party platforms on a schedule. This mismatch is dangerous because users may approve or invoke the skill without understanding that it performs external posting and broader data handling than the title and summary imply.
The skill declares no explicit tool scope even though its documented behavior requires file access, network access, and likely file output. In an agent environment, missing permission boundaries can allow broader-than-expected execution and reduce a user's ability to assess or constrain what the skill is allowed to do.
The skill automates recurring publication to social-media-related APIs, but the description does not clearly warn users that it can post externally on a schedule. In context, this increases the risk of unintended publication, reputational harm, and unauthorized outbound actions because operators may treat it as simple content generation rather than autonomous posting.
The skill lists API keys and third-party providers but does not warn that content, metadata, and potentially sensitive business information are transmitted to external services. This is risky because users may supply credentials and content without understanding the data-sharing implications or the trust boundary introduced by those vendors.
The documented UploadPost endpoint confirms that the skill sends data to an external service, which creates an exfiltration and trust-boundary risk even if the behavior is intended. In this skill's context, outbound transmission is central to functionality, but it remains dangerous if not tightly disclosed and constrained because media, generated content, and credentials-related operations interact with third-party infrastructure.
{
"api_key": "...",
"endpoint": "https://api.upload-post.com/api/upload_photos"
}
The NewsAPI query explicitly forces English-language content, and the same constraint appears again in the relationship news fetch path. This imposes a language choice without user opt-in and is a natural-language locale policy issue under the stated rules.
The NewsAPI query explicitly forces English-language content, and the file does not provide a way for the user to select another language or acknowledge this restriction. That makes the locale constraint a policy concern rather than an implementation detail.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
}
try:
r = requests.post(
self.tpl_cfg.get('endpoint', 'https://api.templated.io/v1/render'),
headers=headers, json=data, timeout=60
)
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
try:
r = requests.post(
self.tpl_cfg.get('endpoint', 'https://api.templated.io/v1/render'),
headers=headers, json=data, timeout=60
)
if r.status_code == 200:
The code blindly trusts a render_url returned by an external API and immediately fetches it with requests.get. If the rendering service or its response is compromised, this can be used for SSRF-style behavior, internal network probing, or downloading unexpected content from attacker-controlled URLs.
if r.status_code == 200:
url = r.json().get('render_url')
if url:
img = requests.get(url, timeout=30)
if img.status_code == 200:
return {"url": url, "data": img.content}
except Exception as e:
This code sends image data and captions to a third-party publishing endpoint, which can affect public-facing accounts and transmit user/system-generated data externally. While publishing is part of the skill's purpose, this file provides no confirmation prompt or user-facing disclosure before the outbound post occurs.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
data = {"caption": caption}
try:
r = requests.post(
self.upload_cfg.get('endpoint', 'https://api.upload-post.com/api/upload_photos'),
headers=headers, files=files, data=data, timeout=60
)
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
try:
r = requests.post(
self.upload_cfg.get('endpoint', 'https://api.upload-post.com/api/upload_photos'),
headers=headers, files=files, data=data, timeout=60
)
return r.json()
This JSON file contains only generic promotional phrases such as tax reminders, refunds, and compliance benefits, but provides no specific invocation phrases, scope limits, or exclusion conditions. If these strings are used as activation or matching text in a manifest-like context, they are ambiguous and could overlap with common tax-related user speech, increasing the risk of unintended invocation.
The config sets "timezone":"Africa/Johannesburg" directly, which imposes a locale-specific operating context in natural-language-adjacent configuration without indicating that users can choose or override it. The policy allows locale constraints when clearly documented and justified, but this single-line config provides no such justification or opt-in.
The script persists execution results, including posting metadata, to a local JSON file. This is a file write operation, and the file does not include an explicit warning, prompt, or explanatory comment about saving output to disk.
No suspicious patterns detected.