T09 · Insecure Skill Coding Practices
- Location
cover_generator.py:53- Finding
Configurable AI Endpoint Can Receive Bearer Credentials
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill matches its WeChat publishing purpose, but it handles account/API credentials and can send an AI bearer token to an arbitrary configured endpoint without enough guardrails or disclosure.
Review before installing. Use only trusted WeChat and AI provider credentials, avoid putting secrets directly in examples or committed .env files, do not point AI_IMAGE_BASE_URL at an untrusted or plaintext endpoint, prefer the base64 AI image path over URL downloads, and expect article content, prompts, covers, and publishing metadata to be sent to external services.
cover_generator.py:53Configurable AI Endpoint Can Receive Bearer Credentials
cover_generator.py:127Unvalidated Image URL Fetch Permits Server-Side Request Forgery
requirements.txt:1Dependency Versions Are Not Reproducibly Pinned
The request target is built from a configurable base URL taken from an environment variable or function parameter, and the Authorization bearer token is sent to that endpoint. If an attacker can influence base_url or the environment, they can redirect requests and exfiltrate the API key to an attacker-controlled server, making this an SSRF-style secret leakage issue rather than a harmless configuration feature.
"response_format": "b64_json"
}
response = requests.post(url, headers=headers, json=payload, timeout=120)
response.raise_for_status()
data = response.json()
This second image-generation path has the same problem: it sends the API key in an Authorization header to a URL derived from environment input or caller-supplied base_url. A malicious or misconfigured endpoint could capture credentials and request contents, so the risk is real in agent or shared execution environments.
"response_format": "url"
}
response = requests.post(url, headers=headers, json=payload, timeout=120)
response.raise_for_status()
data = response.json()
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 微信公众号配置模板
# 复制此文件为 .env 并填写实际值
# 微信公众号 AppID
WECHAT_APP_ID=
The README explicitly instructs users to send prompts and an API key to an external AI image service, but it provides no warning about third-party data handling, prompt sensitivity, retention, or billing exposure. This creates a real security/privacy risk because users may unknowingly transmit proprietary content or secrets to an outside provider under the assumption the feature is self-contained.
This example shows configuration of an external endpoint for AI image generation, which implies user prompts and credentials will be transmitted off-system. In context, external transmission is expected functionality rather than covert exfiltration, but it is still security-relevant because sensitive prompts or mishandled API keys could be disclosed to a third party.
generate_cover_with_ai(
output_path="./cover_ai.png",
prompt="A modern tech blog cover with blue gradient and abstract shapes",
base_url="https://api.openai.com/v1",
api_key="your_api_key",
model="dall-e-3"
)
The environment variable example configures a third-party API endpoint and secret for outbound requests, confirming the skill depends on external data transmission. This is not inherently malicious, but without accompanying warnings it can lead to accidental disclosure of sensitive prompts or insecure secret management practices.
# AI 图片生成配置
export AI_IMAGE_BASE_URL="https://api.openai.com/v1"
export AI_IMAGE_API_KEY="your_api_key"
export AI_IMAGE_MODEL="dall-e-3"
The skill instructs users to configure公众号凭据 and an optional AI image API, but it does not warn that article content and API credentials may be transmitted to third-party services during operation. In this context, users may unknowingly send unpublished content or sensitive tokens to external providers, creating confidentiality and supply-chain risk.
The documented default AI_IMAGE_BASE_URL points to an external API endpoint, indicating that generated prompts and possibly article-derived input will be transmitted off-host. This is not inherently malicious, but without clear disclosure and validation controls it can expose unpublished content, metadata, or secrets to a third party and normalize use of external services in a publishing workflow.
| WECHAT_APP_ID | 公众号 AppID | - |
| WECHAT_APP_SECRET | 公众号 AppSecret | - |
| WECHAT_ACCOUNT_NAME | 作者署名 | - |
| AI_IMAGE_BASE_URL | AI 图片 API 地址 | https://api.openai.com/v1 |
| AI_IMAGE_API_KEY | AI 图片 API 密钥 | - |
| AI_IMAGE_MODEL | AI 图片模型 | dall-e-3 |
This Python file contains only Chinese natural-language descriptions in its module docstring, presenting the skill as Chinese-only without any indication that users can choose another language or locale. Under the policy rule, forcing a specific language without user opt-in is a natural-language policy concern.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# ==================== 配置区域 ====================
# AI 图片生成配置(从环境变量读取)
AI_IMAGE_BASE_URL = os.getenv("AI_IMAGE_BASE_URL", "https://api.openai.com/v1")
AI_IMAGE_API_KEY = os.getenv("AI_IMAGE_API_KEY", "")
AI_IMAGE_MODEL = os.getenv("AI_IMAGE_MODEL", "dall-e-3")
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# ==================== 配置区域 ====================
# AI 图片生成配置(从环境变量读取)
AI_IMAGE_BASE_URL = os.getenv("AI_IMAGE_BASE_URL", "https://api.openai.com/v1")
AI_IMAGE_API_KEY = os.getenv("AI_IMAGE_API_KEY", "")
AI_IMAGE_MODEL = os.getenv("AI_IMAGE_MODEL", "dall-e-3")
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# ==================== 配置区域 ====================
# AI 图片生成配置(从环境变量读取)
AI_IMAGE_BASE_URL = os.getenv("AI_IMAGE_BASE_URL", "https://api.openai.com/v1")
AI_IMAGE_API_KEY = os.getenv("AI_IMAGE_API_KEY", "")
AI_IMAGE_MODEL = os.getenv("AI_IMAGE_MODEL", "dall-e-3")
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
"response_format": "b64_json"
}
response = requests.post(url, headers=headers, json=payload, timeout=120)
response.raise_for_status()
data = response.json()
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
"response_format": "b64_json"
}
response = requests.post(url, headers=headers, json=payload, timeout=120)
response.raise_for_status()
data = response.json()
The code downloads from image_url returned by the remote API without validating the destination host, scheme, or content type. If the upstream service, custom base URL, or response is malicious, this can be abused to trigger server-side requests to arbitrary locations and store unexpected content locally.
data = response.json()
image_url = data["data"][0]["url"]
image_response = requests.get(image_url, timeout=60)
image_response.raise_for_status()
os.makedirs(os.path.dirname(output_path) if os.path.dirname(output_path) else ".", exist_ok=True)
Natural-language policy violations apply to all file types, including code comments, docstrings, and user-facing print strings. This file presents its description and user-facing messages only in Chinese, which effectively forces a specific language without indicating that the user can choose another locale.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
'introduction': ''
}, ensure_ascii=False)
}
response = requests.post(url, params=params, files=files, data=data)
result = response.json()
if 'media_id' in result:
The README content, headings, and usage guidance are presented only in Chinese, which can amount to a language policy issue when no user opt-in or alternative language is offered. There is also no note explaining that the skill is intentionally limited to Chinese-speaking users or a region-specific audience.
This code accesses WECHAT_APP_ID and WECHAT_APP_SECRET from environment variables, which falls under sensitive credential access for code files. Although the variables are named clearly, there is no nearby warning, comment, or runtime notice explaining that the script consumes account credentials beyond a generic configuration note.
The dependency specification for requests uses a lower-bound constraint instead of pinning to a specific version. This makes builds non-reproducible and can allow installation of a vulnerable or unexpected release if the environment resolves to an unsafe version.
requests>=2.28.0
markdown2>=2.4.0
Pillow>=9.0.0
Requests has multiple known advisories, and because the manifest does not pin a version, there is no way to verify from this file whether the installed release is affected. The danger is not that requests is always vulnerable, but that the project permits ambiguous resolution to versions that may include credential leakage or other known flaws.
The markdown2 dependency is not pinned to an exact version, so different installations may resolve to different releases. Because markdown parsers have a history of XSS and ReDoS issues, this increases supply-chain and patch-management risk.
requests>=2.28.0
markdown2>=2.4.0
Pillow>=9.0.0
Markdown2 has a history of security advisories, including XSS and denial-of-service issues, and the lack of version pinning prevents verification that a safe release will be installed. If this skill processes untrusted markdown, the practical risk increases because vulnerable parser behavior may be reachable.
Pillow is specified with only a minimum version, which leaves room for unsafe or inconsistent dependency resolution across environments. Since image-processing libraries often receive security fixes for memory and parsing flaws, unpinned installation can expose deployments to avoidable risk.
requests>=2.28.0
markdown2>=2.4.0
Pillow>=9.0.0
Pillow has numerous historical vulnerabilities, including image parsing issues that can lead to denial of service or worse, and the unpinned requirement means the deployed version cannot be verified as safe. This is more concerning than a typical utility library because image-processing code often handles complex attacker-controlled file formats.
No suspicious patterns detected.