T09 · Insecure Skill Coding Practices
- Location
scripts/publish_to_wechat.py:105- Finding
Unrestricted Image URL Fetching Enables Server-Side Request Forgery
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is mostly a WeChat publishing workflow, but it should be reviewed because it can install Python packages at runtime, use account credentials, fetch arbitrary image URLs, and upload content to WeChat without a clear final consent boundary.
Review before installing. Use it only in an isolated environment with the intended WeChat account, preinstall pinned dependencies yourself, avoid untrusted HTML or remote image URLs, and confirm exactly what content and images will be uploaded before creating a draft. Prefer environment or secret-store credentials over typing AppSecret into the echoed prompt.
scripts/publish_to_wechat.py:105Unrestricted Image URL Fetching Enables Server-Side Request Forgery
scripts/publish_to_wechat.py:27Runtime Installation of Unpinned Python Dependencies
scripts/publish_to_wechat.py:431WeChat AppSecret Is Entered Through an Echoing Terminal Prompt
The declared description promises a full pipeline from many content sources through HTML generation and final publication to WeChat. The supplied code only performs one middle step: converting existing HTML into a more WeChat-compatible inline-style HTML fragment. It has no logic for ingesting non-HTML formats, crawling URLs, processing folders, generating HTML from an idea, or interacting with WeChat services or draft boxes. The only extra behavior beyond conversion is auto-installing Python dependencies, which is a supporting implementation detail rather than the main mismatch. Therefore the description materially overstates the skill's actual capabilities and primary purpose.
The declared description significantly overstates the skill’s capabilities. The code only publishes already-prepared HTML content to the WeChat draft box, with support for uploading images and replacing image URLs. It does not implement the promised 'accept anything' ingestion flow, HTML generation, or automatic WeChat conversion. Its WeChat publishing portion is accurately described, but the primary workflow described is materially broader than the actual implementation, so this is a mismatch.
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.
rules[selector] = props
except Exception:
pass
return rules
def selector_matches(tag, selector):
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
publish_to_wechat.py — Self-contained WeChat Official Account draft publisher.
Uploads HTML articles with cover images to the WeChat Official Account draft box
via the draft/add API. Handles access token, image upload to WeChat CDN, and
HTML image URL replacement.
Usage:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
publish_to_wechat.py — Self-contained WeChat Official Account draft publisher.
Uploads HTML articles with cover images to the WeChat Official Account draft box
via the draft/add API. Handles access token, image upload to WeChat CDN, and
HTML image URL replacement.
Usage:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
publish_to_wechat.py — Self-contained WeChat Official Account draft publisher.
Uploads HTML articles with cover images to the WeChat Official Account draft box
via the draft/add API. Handles access token, image upload to WeChat CDN, and
HTML image URL replacement.
Usage:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
publish_to_wechat.py — Self-contained WeChat Official Account draft publisher.
Uploads HTML articles with cover images to the WeChat Official Account draft box
via the draft/add API. Handles access token, image upload to WeChat CDN, and
HTML image URL replacement.
Usage:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
publish_to_wechat.py — Self-contained WeChat Official Account draft publisher.
Uploads HTML articles with cover images to the WeChat Official Account draft box
via the draft/add API. Handles access token, image upload to WeChat CDN, and
HTML image URL replacement.
Usage:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
publish_to_wechat.py — Self-contained WeChat Official Account draft publisher.
Uploads HTML articles with cover images to the WeChat Official Account draft box
via the draft/add API. Handles access token, image upload to WeChat CDN, and
HTML image URL replacement.
Usage:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
if "access_token" in data:
self.access_token = data["access_token"]
print("[OK] Access token obtained successfully")
return True
else:
errcode = data.get("errcode", "unknown")
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
if "access_token" in data:
self.access_token = data["access_token"]
print("[OK] Access token obtained successfully")
return True
else:
errcode = data.get("errcode", "unknown")
The skill instructs the agent to read environment variables, read and write files, invoke shell commands, and perform networked publishing, but it declares no explicit tool scope or permissions boundary. That increases the blast radius of accidental or malicious invocation because users and the runtime cannot easily constrain what capabilities the skill may exercise.
Overly broad trigger phrases can cause the skill to activate on routine requests that users did not intend to send to an external publishing workflow. In this context, accidental activation is more dangerous because the skill handles content transformation, credential use, file access, and outbound publication to a third-party platform.
The skill promises seamless publishing but does not prominently warn that user content and images will be uploaded to WeChat, an external service. This undermines informed consent and can lead to unintended disclosure of sensitive documents, internal reports, or copyrighted material.
The manifest advertises that it can accept virtually any input type, including files, folders, URLs, and freeform ideas, without stating constraints, validation rules, or exclusions. In a skill that also transforms content and publishes it outward, this broad scope increases the risk of unintended data exposure, unsafe handling of sensitive local content, and misuse through ambiguous invocation.
The description promises automatic publishing to a WeChat Official Account draft box but does not warn that content may be transmitted to an external platform. For a workflow that can ingest arbitrary local or remote material, failing to disclose outbound publication behavior can cause accidental exfiltration of confidential, proprietary, or personal data.
The skill's stated purpose is HTML conversion for WeChat, but it also performs runtime package installation, adding network and software installation capability unrelated to the core task. In the skill context, this is more dangerous because agent skills often run automatically and may have broad environment access, turning a document conversion step into an implicit code-fetch and execution path.
The script automatically executes pip install at runtime when imports fail, which gives this content-conversion tool package-management and external network capability. In an agent or automation environment, that behavior can introduce unreviewed code into the runtime, enable supply-chain compromise, and violate least-privilege expectations for a local HTML conversion step.
except ImportError:
print("[INFO] Installing beautifulsoup4...")
import subprocess
subprocess.check_call([sys.executable, "-m", "pip", "install", "beautifulsoup4", "-q"])
from bs4 import BeautifulSoup, Tag
try:
This second pip install path has the same security issue: the script can reach out to package repositories and execute package installation logic during normal operation. That expands the trust boundary from local file conversion to remote code acquisition, which is especially risky inside agent skills that may run with sensitive tokens or filesystem access.
except ImportError:
print("[INFO] Installing cssutils...")
import subprocess
subprocess.check_call([sys.executable, "-m", "pip", "install", "cssutils", "-q"])
import cssutils
cssutils.log.setLevel(50)
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
# 10. Write output
output_file = Path(output_path)
output_file.parent.mkdir(parents=True, exist_ok=True)
output_file.write_text(output_html, encoding='utf-8')
size = len(output_html.encode('utf-8'))
print(f"[DONE] WeChat-ready HTML: {output_path}")
Auto-installing a Python package at runtime is not necessary for the core publishing workflow and gives the skill software-installation behavior. That increases attack surface through dependency confusion, tampered mirrors, or unexpected environment changes, especially in shared or privileged runtimes.
The skill silently installs software through subprocess without warning in the interface or usage contract. Even if not overtly malicious, hidden package installation violates least surprise and can lead to unauthorized environment modification or execution of third-party code.
The script executes a runtime pip installation via subprocess when requests is missing. In an agent-skill context, this expands capability beyond publishing and can modify the environment, pull code from external package indexes, and introduce supply-chain risk or unexpected side effects without explicit user approval.
except ImportError:
print("[INFO] Installing requests...")
import subprocess
subprocess.check_call([sys.executable, "-m", "pip", "install", "requests", "-q"])
import requests
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
class WeChatPublisher:
"""WeChat Official Account HTML draft publisher."""
BASE_URL = "https://api.weixin.qq.com/cgi-bin"
def __init__(self, app_id: str, app_secret: str):
self.app_id = app_id
The code reads WECHAT_APP_ID and WECHAT_APP_SECRET and sends them to the WeChat token endpoint to obtain an access token. While this is part of the tool's purpose, the file does not clearly warn users that supplied credentials and article content/images will be sent to WeChat services, which is relevant to privacy and account-safety expectations.
No suspicious patterns detected.