T09 · Insecure Skill Coding Practices
- Location
scripts/push_draft.py:48- Finding
WeChat AppSecret Exposed Through Process Command-Line Arguments
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a disclosed WeChat publishing toolkit, but it enables scheduled public publishing with credentialed account access and has insecure credential/temp-file handling that users should review before installing.
Install only if you are comfortable giving the agent access to a WeChat Official Account AppID/AppSecret and with scheduled jobs that can publish to all subscribers. Prefer using it for draft creation unless you add an explicit approval step before freepublish/submit, keep the env file tightly permissioned, rotate credentials if logs may have captured them, and avoid shared hosts until the temp-file and command-line secret handling are fixed.
scripts/push_draft.py:48WeChat AppSecret Exposed Through Process Command-Line Arguments
scripts/push_draft.py:119Predictable Shared Temporary File Allows Symlink Overwrite and Draft Disclosure
The second description-behavior mismatch similarly shows that the skill advertises scheduling and auto-publish features that are not present, while also exposing additional draft-management and image-upload actions not prominently declared. Overstating some capabilities and understating others weakens user consent and security review because the real operational surface is different from the advertised one.
The second description-behavior mismatch similarly shows that the skill advertises scheduling and auto-publish features that are not present, while also exposing additional draft-management and image-upload actions not prominently declared. Overstating some capabilities and understating others weakens user consent and security review because the real operational surface is different from the advertised one.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
Requirements:
- curl
- A .env file with WECHAT_APPID and WECHAT_SECRET
- The account must be a verified enterprise/organization (freepublish permission)
"""
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
Requirements:
- curl
- A .env file with WECHAT_APPID and WECHAT_SECRET
- The account must be a verified enterprise/organization (freepublish permission)
"""
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
Requirements:
- curl
- A .env file with WECHAT_APPID and WECHAT_SECRET
- The account must be a verified enterprise/organization (freepublish permission)
"""
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
Requirements:
- curl
- A .env file with WECHAT_APPID and WECHAT_SECRET
- The account must be a verified enterprise/organization (freepublish permission)
"""
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
Requirements:
- curl
- A .env file with WECHAT_APPID and WECHAT_SECRET
- The account must be a verified enterprise/organization (freepublish permission)
"""
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
Requirements:
- curl
- A .env file with WECHAT_APPID and WECHAT_SECRET
- The account must be a verified enterprise/organization (freepublish permission)
"""
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
Requirements:
- curl
- A .env file with WECHAT_APPID and WECHAT_SECRET
- The account must be a verified enterprise/organization (freepublish permission)
"""
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
Requirements:
- curl
- A .env file with WECHAT_APPID and WECHAT_SECRET
- The account must be a verified enterprise/organization (freepublish permission)
"""
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# Load credentials
creds = load_credentials(args.env)
# Get access token
token = get_access_token(creds["WECHAT_APPID"], creds["WECHAT_SECRET"])
# Attempt publish with retries for transient system errors
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# Load credentials
creds = load_credentials(args.env)
# Get access token
token = get_access_token(creds["WECHAT_APPID"], creds["WECHAT_SECRET"])
# Attempt publish with retries for transient system errors
The skill documents and encourages file access, shell execution, and outbound network/API operations but does not declare any explicit tool scope or permissions boundary. In an agent environment, this increases the chance that the skill can be invoked with broader capabilities than reviewers or users expect, enabling unintended command execution, credential file access, or external publication actions.
The skill proposes daily auto-publish automation without an explicit per-run warning that publication sends content to all subscribers and is irreversible. In this context, silent or poorly signposted automation can cause accidental mass publication, reputational damage, and dissemination of unreviewed or maliciously altered content.
The documentation includes a destructive delete-draft API call without any warning, confirmation guidance, or recovery note. In a publishing automation skill, this increases the chance an agent or integrator invokes deletion unintentionally, causing content loss or workflow disruption.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
Do NOT use:
# WRONG — garbles Chinese
requests.post(url, json=draft_data)
DO use:
The manifest describes a toolkit for pushing drafts and publishing to WeChat, which clearly justifies network access to WeChat APIs. However, this documentation recommends invoking an external shell utility via Python's subprocess module to perform the upload, introducing process-execution capability that is not inherently required by the stated purpose and expands the operational model beyond ordinary API usage.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
with open(json_path, "w", encoding="utf-8") as f:
json.dump(draft_data, f, ensure_ascii=False, separators=(",", ":"))
# 2. Upload with curl --data-binary (preserves UTF-8 bytes)
subprocess.run([
"curl", "-s", "-X", "POST", url,
"-H", "Content-Type: application/json",
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
### Step 4: Publish the draft
1. Get access_token:
curl -s "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET"
2. If errcode=40164 (IP whitelist): get server IP with `curl -s https://api.ipify.org` and notify the user to add it to the whitelist.
3. Call publish API:
curl -X POST "https://api.weixin.qq.com/cgi-bin/freepublish/submit?access_token=TOKEN" \
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def get_access_token(appid, secret):
"""Get WeChat access_token. Handle IP whitelist error (40164)."""
result = subprocess.run(
[
"curl", "-s",
f"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={secret}",
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def get_access_token(appid, secret):
"""Get WeChat access_token. Handle IP whitelist error (40164)."""
result = subprocess.run(
[
"curl", "-s",
f"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={secret}",
The script sends WECHAT_APPID and WECHAT_SECRET to an external service by embedding them directly in the request URL query string. Even though the destination is the legitimate WeChat API and HTTPS is used, secrets in URLs are more likely to be exposed via process listings, proxies, logs, crash reports, or monitoring systems.
result = subprocess.run(
[
"curl", "-s",
f"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={secret}",
],
capture_output=True,
text=True,
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
errcode = data.get("errcode")
print(f"ERROR getting access_token: {data}")
if errcode == 40164:
ip_result = subprocess.run(
["curl", "-s", "https://api.ipify.org"],
capture_output=True,
text=True,
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
errcode = data.get("errcode")
print(f"ERROR getting access_token: {data}")
if errcode == 40164:
ip_result = subprocess.run(
["curl", "-s", "https://api.ipify.org"],
capture_output=True,
text=True,
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def publish_draft(token, media_id):
"""Call freepublish/submit to publish a draft. Returns the API response dict."""
result = subprocess.run(
[
"curl", "-s", "-X", "POST",
f"https://api.weixin.qq.com/cgi-bin/freepublish/submit?access_token={token}",
Detected: suspicious.exposed_secret_literal