T09 · Insecure Skill Coding Practices
- Location
scripts/publish.py:217- Finding
Arbitrary External Image Fetching Enables Server-Side Request Forgery
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill mostly matches its WeChat formatting and publishing purpose, but it needs Review because some optional workflows can post live replies, send comments or article content to external AI services, and fetch or modify content with limited safeguards.
Install only if you are comfortable giving the skill WeChat account credentials and using external WeChat and AI APIs. Use dry-run or preview modes first, avoid untrusted Markdown/HTML and external image URLs, and do not run comment_reply.py unless you have reviewed the scope and accept automated public replies plus external AI processing of reader comments.
scripts/publish.py:217Arbitrary External Image Fetching Enables Server-Side Request Forgery
scripts/format.py:724Unsanitized Markdown HTML Executes in Automatically Opened Local Previews
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
user_msg += f"文章内容摘要:{article_digest}\n"
user_msg += f"\n读者评论:{comment_content}\n\n请生成回复:"
resp = requests.post(
f"{ai_config['url']}/chat/completions",
headers={
"Authorization": f"Bearer {ai_config['key']}",
If the skill actually sends prompt or reference image data to a third-party AI image API not disclosed in the description, that is a meaningful data exfiltration and scope-mismatch risk. Users expecting local WeChat formatting could unknowingly transmit article content or images to an external model provider, which is especially sensitive for unpublished drafts or proprietary media.
If the skill actually sends prompt or reference image data to a third-party AI image API not disclosed in the description, that is a meaningful data exfiltration and scope-mismatch risk. Users expecting local WeChat formatting could unknowingly transmit article content or images to an external model provider, which is especially sensitive for unpublished drafts or proprietary media.
If the skill actually sends prompt or reference image data to a third-party AI image API not disclosed in the description, that is a meaningful data exfiltration and scope-mismatch risk. Users expecting local WeChat formatting could unknowingly transmit article content or images to an external model provider, which is especially sensitive for unpublished drafts or proprietary media.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
- Formatting and local previews are safe.
- Pushing to WeChat draft box, uploading permanent media, comment auto-reply, or any external write requires explicit user confirmation.
- Never print `app_secret`, access tokens, or AI API keys.
- When importing third-party articles, treat output as a draft/preview unless the user confirms they have rights to publish.
## Quick commands
Referenced artifact was not completely inspected
- `scripts/format.py` — Markdown → WeChat-compatible inline HTML + preview/gallery.
The skill documents destructive or state-changing behavior: renaming existing output directories and directly modifying article files, yet provides no explicit warning or confirmation requirement. In an agent context, especially with broad natural-language triggering, this creates a significant risk of unintended data loss, workflow corruption, or edits to user content without informed consent.
This script performs automatic comment reading, AI processing, and live posting of replies, which exceeds the skill's stated formatting/publishing scope. In an agent-skill context, that scope mismatch is dangerous because a user invoking a formatting tool may unknowingly trigger external side effects on a public WeChat account, including reputational damage and unauthorized public communications.
The manifest describes a skill for converting Markdown/notes into WeChat-compatible HTML, previewing themes, uploading images, generating optional article covers, and pushing drafts to WeChat. This file is a standalone API image-generation client that reads prompts and reference images, calls a third-party model endpoint, and writes generated images to disk, which is materially broader and different from the advertised formatting/publishing workflow.
The entire skill description and operating instructions are written only in Chinese, and the file gives no indication that language selection is optional or that the skill is intentionally limited to Chinese-speaking users. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.
The skill advertises capabilities that imply shell, file, environment, and network access, but it does not declare an explicit tool/permission scope. That creates an over-privilege and transparency problem: a host or reviewer cannot easily enforce least privilege, and users may not realize the full execution surface before the skill reads local files, opens browsers, or performs networked actions.
该 markdown/manifest 描述写明“当用户要求'公众号封面''微信封面''文章封面'时使用”,其中“文章封面”尤其宽泛,可能覆盖普通对话中的常见表达。文件没有提供负例、上下文限制或更明确的调用范围,因此存在意外触发风险。
提示词中写明“除非另有说明,默认使用中文”以及“画面内所有可读文字必须使用简体中文”,这构成了默认语言/地区约束。文件未说明用户可在常规流程中选择其他语言,也未将该限制表述为特定合规场景下的必要约束。
The sub-skill documents that it will directly modify the source article by inserting a generated image without asking the user. This is a state-changing file write that exceeds the parent skill’s stated optional cover-generation role and violates the expectation that external writes or content mutations should require explicit user confirmation.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
def get_access_token(wechat_config):
resp = requests.get("https://api.weixin.qq.com/cgi-bin/token", params={
"grant_type": "client_credential",
"appid": wechat_config["app_id"],
"secret": wechat_config["app_secret"]
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
def get_access_token(wechat_config):
resp = requests.get("https://api.weixin.qq.com/cgi-bin/token", params={
"grant_type": "client_credential",
"appid": wechat_config["app_id"],
"secret": wechat_config["app_secret"]
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
def get_access_token(wechat_config):
resp = requests.get("https://api.weixin.qq.com/cgi-bin/token", params={
"grant_type": "client_credential",
"appid": wechat_config["app_id"],
"secret": wechat_config["app_secret"]
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
def get_access_token(wechat_config):
resp = requests.get("https://api.weixin.qq.com/cgi-bin/token", params={
"grant_type": "client_credential",
"appid": wechat_config["app_id"],
"secret": wechat_config["app_secret"]
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
def get_access_token(wechat_config):
resp = requests.get("https://api.weixin.qq.com/cgi-bin/token", params={
"grant_type": "client_credential",
"appid": wechat_config["app_id"],
"secret": wechat_config["app_secret"]
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
def get_access_token(wechat_config):
resp = requests.get("https://api.weixin.qq.com/cgi-bin/token", params={
"grant_type": "client_credential",
"appid": wechat_config["app_id"],
"secret": wechat_config["app_secret"]
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
def get_access_token(wechat_config):
resp = requests.get("https://api.weixin.qq.com/cgi-bin/token", params={
"grant_type": "client_credential",
"appid": wechat_config["app_id"],
"secret": wechat_config["app_secret"]
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
def get_published_articles(token, count=10):
"""获取已发布文章列表"""
resp = requests.post(
f"https://api.weixin.qq.com/cgi-bin/freepublish/batchget?access_token={token}",
json={"offset": 0, "count": count}
).json()
The code comments/documentation indicate only curated/selected comments should be replied to, but the implementation appends all unreplied comments. That mismatch broadens automation scope and can cause the bot to respond publicly to unreviewed, abusive, sensitive, or out-of-context comments, increasing the chance of harmful or embarrassing account actions.
Reader comments and article digests are transmitted to an external AI service to generate replies, yet the skill description does not clearly warn about this third-party data sharing. This is dangerous because comments may contain personal data or sensitive user submissions, and sending them to a configurable external provider creates privacy, compliance, and trust risks.
This outbound request sends article digests and user comment content to an external AI service. In this skill context, that is security-relevant because it exports third-party content outside WeChat to a configurable provider without an obvious consent or review boundary, creating privacy and data-governance risk.
user_msg += f"文章内容摘要:{article_digest}\n"
user_msg += f"\n读者评论:{comment_content}\n\n请生成回复:"
resp = requests.post(
f"{ai_config['url']}/chat/completions",
headers={
"Authorization": f"Bearer {ai_config['key']}",