T09 · Insecure Skill Coding Practices
- Location
scripts/upload_images.py:19- Finding
TLS Certificate Verification Disabled in Image Uploader
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a legitimate WeChat publishing helper, but its bundled scripts handle account secrets and unpublished content with unsafe TLS settings.
Install only if you are comfortable giving the skill WeChat Official Account API credentials and sending selected drafts and images to WeChat. Avoid the bundled Python scripts until TLS verification is fixed, do not paste real AppSecrets directly into shell commands, store config.json outside shared or synced repositories with restrictive permissions, and rotate the AppSecret if it has been exposed in history, logs, or commits.
scripts/upload_images.py:19TLS Certificate Verification Disabled in Image Uploader
scripts/publish_wechat.py:20TLS Certificate Verification Disabled During Draft Publication
SKILL.md:46Insecure AppSecret Storage and Command-Line Exposure in Usage Instructions
该描述与代码存在明显不一致。代码的核心能力确实与“发布到微信公众号草稿箱”相关,这与描述中的“草稿发布”部分一致;但描述强调的是“排版和发布的完整工作流”,包括专业模板、图片上传、封面图/素材库处理等,而实际代码仅做了非常基础的本地文件读取和微信草稿接口调用。所谓 markdown_to_html 函数没有真正转换内容,模板参数仅被记录到输出结果中,cover-image 参数也完全未使用。因此,代码的实际行为只覆盖了声明中的一小部分,且多个重要能力被描述但未实现,构成描述与行为的不匹配。
The declared description presents a broad end-to-end WeChat article composition and publishing skill, including formatting templates, image upload, and draft publishing. However, the supplied code only implements one narrow subset: batch uploading images to the WeChat material API and saving their URLs locally. There is no code for article layout, template application, article creation, draft management, or publishing. This is therefore a description-to-behavior mismatch: the actual code behavior is materially narrower than the declared primary purpose. The resource access itself (WeChat API and local files) is consistent with the image-upload portion of the description, but the overall claimed workflow is not represented by this code chunk.
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
# 获取 token(成功会返回一串字符)
curl -s "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=你的 APPID&secret=你的 APPSECRET"
成功响应:
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
# 获取 token(成功会返回一串字符)
curl -s "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=你的 APPID&secret=你的 APPSECRET"
成功响应:
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
TOKEN=$(curl -s "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET" | python3 -c "import sys,json; print(json.load(sys.stdin).get('access_token',''))")
# ========== 第 2 步:上传封面图 ==========
COVER=$(curl -s -X POST "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=$TOKEN&type=image" -F "media=@/path/to/cover.jpg" | python3 -c "import sys,json; print(json.load(sys.stdin).get('media_id',''))")
# ========== 第 3 步:发布草稿(关键:-H "Content-Type: application/json; charset=utf-8") ==========
curl -s -X POST "https://api.weixin.qq.com/cgi-bin/draft/add?access_token=$TOKEN" \
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
TOKEN=$(curl -s "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET" | python3 -c "import sys,json; print(json.load(sys.stdin).get('access_token',''))")
# ========== 第 2 步:上传封面图 ==========
COVER=$(curl -s -X POST "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=$TOKEN&type=image" -F "media=@/path/to/cover.jpg" | python3 -c "import sys,json; print(json.load(sys.stdin).get('media_id',''))")
# ========== 第 3 步:发布草稿(关键:-H "Content-Type: application/json; charset=utf-8") ==========
curl -s -X POST "https://api.weixin.qq.com/cgi-bin/draft/add?access_token=$TOKEN" \
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
COVER=$(curl -s -X POST "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=$TOKEN&type=image" -F "media=@/path/to/cover.jpg" | python3 -c "import sys,json; print(json.load(sys.stdin).get('media_id',''))")
curl -s -X POST "https://api.weixin.qq.com/cgi-bin/draft/add?access_token=$TOKEN"
-H "Content-Type: application/json; charset=utf-8"
-d "{"articles":[{"title":"标题","content":"
中文内容
","thumb_media_id":"$COVER"}]}"Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
APP_SECRET = config.get('appSecret')
def get_access_token():
"""获取 access token"""
url = f'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={APP_ID}&secret={APP_SECRET}'
resp = requests.get(url, verify=False)
data = resp.json()
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
APP_SECRET = config.get('appSecret')
def get_access_token():
"""获取 access token"""
url = f'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={APP_ID}&secret={APP_SECRET}'
resp = requests.get(url, verify=False)
data = resp.json()
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
APP_SECRET = config.get('appSecret')
def get_access_token():
"""获取 access token"""
url = f'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={APP_ID}&secret={APP_SECRET}'
resp = requests.get(url, verify=False)
data = resp.json()
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
APP_SECRET = config.get('appSecret')
def get_access_token():
"""获取 access token"""
url = f'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={APP_ID}&secret={APP_SECRET}'
resp = requests.get(url, verify=False)
data = resp.json()
The skill documents file access and outbound network operations but does not declare any explicit tool scope such as allowed-tools or permissions. This creates an overbroad execution model where an agent may use capabilities the user did not clearly authorize, increasing the chance of unintended secret access or network transmission.
The example retrieves an access token by placing AppID and AppSecret directly in a curl URL. Although this is normal for the WeChat API, exposing secrets in command lines can leak them through shell history, terminal scrollback, monitoring tools, and audit logs.
# 获取 token(成功会返回一串字符)
curl -s "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=你的 APPID&secret=你的 APPSECRET"
成功响应:
The document frames correct use and validation around Chinese content only, including statements like '必须用 curl 命令' and previewing specifically for '正常中文' display. This effectively imposes a Chinese-language expectation without any opt-in or explanation that the skill is limited to a Chinese-only compliance context.
This token-fetch example sends sensitive credentials to an external endpoint and encourages inline secret handling. The behavior matches the skill's purpose, but the command format increases accidental disclosure risk and broadens exposure of publishing credentials.
# ========== 第 1 步:获取最新 token(每次发布前都要重新获取!) ==========
TOKEN=$(curl -s "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET" | python3 -c "import sys,json; print(json.load(sys.stdin).get('access_token',''))")
# ========== 第 2 步:上传封面图 ==========
COVER=$(curl -s -X POST "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=$TOKEN&type=image" -F "media=@/path/to/cover.jpg" | python3 -c "import sys,json; print(json.load(sys.stdin).get('media_id',''))")
This duplicate external-transmission finding reflects the same risk: article content and tokenized authority are sent to a third-party service. In a publishing skill this is expected, but the mechanism still carries leakage and misuse risk if secrets or unpublished content are handled insecurely.
COVER=$(curl -s -X POST "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=$TOKEN&type=image" -F "media=@/path/to/cover.jpg" | python3 -c "import sys,json; print(json.load(sys.stdin).get('media_id',''))")
curl -s -X POST "https://api.weixin.qq.com/cgi-bin/draft/add?access_token=$TOKEN"
-H "Content-Type: application/json; charset=utf-8"
-d "{"articles":[{"title":"标题","content":"
中文内容
","thumb_media_id":"$COVER"}]}"This duplicate external-transmission finding reflects the same risk: article content and tokenized authority are sent to a third-party service. In a publishing skill this is expected, but the mechanism still carries leakage and misuse risk if secrets or unpublished content are handled insecurely.
COVER=$(curl -s -X POST "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=$TOKEN&type=image" -F "media=@/path/to/cover.jpg" | python3 -c "import sys,json; print(json.load(sys.stdin).get('media_id',''))")
curl -s -X POST "https://api.weixin.qq.com/cgi-bin/draft/add?access_token=$TOKEN"
-H "Content-Type: application/json; charset=utf-8"
-d "{"articles":[{"title":"标题","content":"
中文内容
","thumb_media_id":"$COVER"}]}"The test command transmits draft content to the external WeChat API before final publication. Even test data may contain unpublished or sensitive material, so sending it externally is a genuine data-handling risk in environments where content confidentiality matters.
🧪 测试命令(发布前先用这个验证编码):
curl -s -X POST "https://api.weixin.qq.com/cgi-bin/draft/add?access_token=$TOKEN" \
-H "Content-Type: application/json; charset=utf-8" \
-d "{\"articles\":[{\"title\":\"测试文字\",\"content\":\"<p>这是中文测试</p><p>能看到吗</p>\",\"thumb_media_id\":\"$COVER\"}]}"
This token retrieval example again places credentials in an outbound request URL to an external service. The business purpose is legitimate, but the secret-handling pattern is weak and can cause credential exposure outside the intended API exchange.
# 1. 获取 token
TOKEN=$(curl -s "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=你的 APPID&secret=你的 APPSECRET" | python3 -c "import sys,json; print(json.load(sys.stdin).get('access_token',''))")
# 2. 上传封面
COVER=$(curl -s -X POST "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=$TOKEN&type=image" -F "media=@/path/to/cover.jpg" | python3 -c "import sys,json; print(json.load(sys.stdin).get('media_id',''))")
This duplicate finding again covers draft publication with tokenized authorization in the request. The main danger is not the use of the WeChat API itself, but insecure handling of unpublished content and credentials in command-line workflows.
COVER=$(curl -s -X POST "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=$TOKEN&type=image" -F "media=@/path/to/cover.jpg" | python3 -c "import sys,json; print(json.load(sys.stdin).get('media_id',''))")
curl -s -X POST "https://api.weixin.qq.com/cgi-bin/draft/add?access_token=$TOKEN"
-H "Content-Type: application/json; charset=utf-8"
-d "{"articles":[{"title":"标题","content":"
中文内容
","thumb_media_id":"$COVER"}]}"This duplicate finding again covers draft publication with tokenized authorization in the request. The main danger is not the use of the WeChat API itself, but insecure handling of unpublished content and credentials in command-line workflows.
COVER=$(curl -s -X POST "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=$TOKEN&type=image" -F "media=@/path/to/cover.jpg" | python3 -c "import sys,json; print(json.load(sys.stdin).get('media_id',''))")
curl -s -X POST "https://api.weixin.qq.com/cgi-bin/draft/add?access_token=$TOKEN"
-H "Content-Type: application/json; charset=utf-8"
-d "{"articles":[{"title":"标题","content":"
中文内容
","thumb_media_id":"$COVER"}]}"L297-L310 把 publish_wechat.py 说明为可用于“发布文章到微信草稿箱”,并给出命令行用法;但 L310 明确警告该脚本“可能导致中文乱码,建议使用 curl 命令替代”,而前文 L240 甚至写明“禁止使用 Python 脚本直接发布”。这不是单纯信息不完整,而是对该脚本预期用途的直接自我矛盾,容易误导使用者执行与文档意图相反的操作。
The manifest description is entirely in Chinese and the tags include "chinese", presenting the skill as implicitly Chinese-language only. The file does not indicate that users can choose another language or that the locale restriction is an explicit opt-in, which can violate language/locale policy requirements.
The markdown template is written entirely in Chinese and includes Chinese-only labels and instructions such as the booking flow and company description. This imposes a specific language/locale on users without any opt-in or documented region-specific justification, which matches the language/locale policy violation criteria.
Disabling TLS certificate verification when requesting the access token allows man-in-the-middle interception or modification of the response. In this script's context, that is especially dangerous because the request includes app credentials and obtains a bearer token used to publish content, enabling credential theft, token hijacking, or response tampering.
def get_access_token():
"""获取 access token"""
url = f'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={APP_ID}&secret={APP_SECRET}'
resp = requests.get(url, verify=False)
data = resp.json()
if 'access_token' in data:
return data['access_token']
No suspicious patterns detected.