T09 · Insecure Skill Coding Practices
- Location
scripts/md_converter.py:327- Finding
Markdown Image Paths Can Disclose Files Outside the Article Directory
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill mostly does what it advertises, but draft mode can upload local files referenced by Markdown to WeChat without strong path limits or confirmation.
Install only if you trust the Markdown files you process and understand that --draft sends article content and images to WeChat. Avoid running draft mode on untrusted documents until image paths are restricted to the article directory, uploads are confirmed before transmission, preview HTML is sanitized, and dependencies are pinned.
scripts/md_converter.py:327Markdown Image Paths Can Disclose Files Outside the Article Directory
scripts/html_formatter.py:92Insufficient HTML Sanitization Allows Active Content in Local Previews
scripts/wechat_client.py:219Predictable Shared Temporary Filename Enables Symlink-Based File Overwrite
requirements.txt:4Broad Unhashed Dependency Constraints Create Supply-Chain Risk
声明描述的是一个端到端能力:Markdown 解析与排版、元数据支持、图片上传,以及发送到微信公众号草稿箱。给出的代码片段实际只是一个 HTML 格式化器,用于把已有 HTML 调整为适配微信公众号的内联样式形式。它没有 Markdown 解析、没有任何网络/API 调用、没有图片上传、没有 Front Matter 处理,也没有表格专门处理逻辑。代码行为与声明中的一部分“微信公众号兼容的内联样式 HTML”相符,但无法覆盖其核心宣称的完整转换和一键发送能力,因此属于明显描述与实际行为不一致。
该代码与声明的前半部分基本一致:确实完成 Markdown→微信公众号兼容内联样式 HTML 的转换,并支持 Front Matter、表格、代码块、列表,以及在有 publisher 时上传正文内本地图片并替换为微信 URL。还会生成本地预览 HTML、清理微信不兼容字符并处理超长内容。但声明中的关键能力“一键发送到微信草稿箱”在此代码块中没有实现:没有看到创建草稿、调用微信草稿接口、提交文章到远端草稿箱等行为,仅构造并返回包含 title/content/author/summary 等字段的字典。因此描述高估了该代码块的实际能力,构成描述与行为不一致。
声明的核心用途是“将 Markdown 文件转换为微信公众号兼容的内联样式 HTML,并发送到微信草稿箱”,这是一个包含内容解析与排版转换的完整工作流。但该代码片段实际只覆盖微信公众号 API 交互部分:令牌管理、图片上传、草稿创建、默认封面生成和连接测试。它接收的 article['content'] 似乎应当已经是现成 HTML/内容,代码本身没有读取 Markdown 文件、没有 Markdown 解析、没有 CSS 内联、没有 Front Matter 提取,也没有实现表格、代码块、列表等排版转换逻辑。因此该代码行为只匹配声明中的“发送到微信草稿箱、图片上传”部分,而缺失了声明中更主要的 Markdown 转换与排版能力,属于明显的描述与实际行为不一致。
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# md2wechat-skill 环境变量配置模板
# 将此文件复制为 .env 并填写真实值
# ──────────────────────────────────────────
# 微信公众号配置(必填)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# md2wechat-skill 环境变量配置模板
# 将此文件复制为 .env 并填写真实值
# ──────────────────────────────────────────
# 微信公众号配置(必填)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# md2wechat-skill 环境变量配置模板
# 将此文件复制为 .env 并填写真实值
# ──────────────────────────────────────────
# 微信公众号配置(必填)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# md2wechat-skill 环境变量配置模板
# 将此文件复制为 .env 并填写真实值
# ──────────────────────────────────────────
# 微信公众号配置(必填)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# md2wechat-skill 环境变量配置模板
# 将此文件复制为 .env 并填写真实值
# ──────────────────────────────────────────
# 微信公众号配置(必填)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# md2wechat-skill 环境变量配置模板
# 将此文件复制为 .env 并填写真实值
# ──────────────────────────────────────────
# 微信公众号配置(必填)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# md2wechat-skill 环境变量配置模板
# 将此文件复制为 .env 并填写真实值
# ──────────────────────────────────────────
# 微信公众号配置(必填)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# md2wechat-skill 环境变量配置模板
# 将此文件复制为 .env 并填写真实值
# ──────────────────────────────────────────
# 微信公众号配置(必填)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# md2wechat-skill 环境变量配置模板
# 将此文件复制为 .env 并填写真实值
# ──────────────────────────────────────────
# 微信公众号配置(必填)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# md2wechat-skill 环境变量配置模板
# 将此文件复制为 .env 并填写真实值
# ──────────────────────────────────────────
# 微信公众号配置(必填)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# md2wechat-skill 环境变量配置模板
# 将此文件复制为 .env 并填写真实值
# ──────────────────────────────────────────
# 微信公众号配置(必填)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# md2wechat-skill 环境变量配置模板
# 将此文件复制为 .env 并填写真实值
# ──────────────────────────────────────────
# 微信公众号配置(必填)
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# md2wechat-skill 环境变量配置模板
# 将此文件复制为 .env 并填写真实值
# ──────────────────────────────────────────
# 微信公众号配置(必填)
The README explicitly advertises uploading article content, embedded local images, and cover images to WeChat, but it does not warn users that this transmits potentially sensitive local data to a third-party platform and stores it remotely as drafts or media. In a publishing skill, this behavior is expected, but the lack of a clear privacy/data-transfer notice can lead users to unintentionally exfiltrate confidential content or images.
Without declared permissions the skill's intent is opaque and cannot be validated.
The entire article, including the title, authoring, and instructional content, is written exclusively in Chinese with no indication that language choice is optional. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified.
The module title and class docstring are written only in Chinese and explicitly target WeChat public-account formatting, which imposes a single language/locale context without offering a user choice or opt-in. The policy for this audit flags language or locale constraints when they are forced rather than optionally selected or clearly justified as user-configurable.
The image handling code automatically uploads any locally referenced image in the rendered HTML to WeChat when a publisher object is supplied, which causes local file contents to be transmitted to an external service. In the context of a Markdown-to-WeChat publishing skill, this behavior is expected for functionality, but it is still a real privacy and data-exfiltration risk because there is no explicit consent gate, allowlist, or warning at the point of transfer.
This file's docstrings, prompts, status messages, and error text are consistently presented in Chinese, including operational and failure notices shown to users. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is explicitly documented and justified, which it is not here.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
try:
import requests
url = f"https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token={self.client.access_token}"
with open(image_path, 'rb') as f:
files = {'media': f}
resp = requests.post(url, files=files)
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
try:
import requests
url = f"https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token={self.client.access_token}"
with open(image_path, 'rb') as f:
files = {'media': f}
resp = requests.post(url, files=files)
The dependency is specified with only a lower bound, so builds may resolve to different versions over time and can unexpectedly pull in vulnerable or breaking releases. In a skill that publishes content to WeChat and processes Markdown/HTML, supply-chain drift increases the risk of introducing exploitable parser or network-library flaws without any code change in the repository.
# md2wechat-skill Python 依赖
# 安装命令:pip install -r requirements.txt
wechatpy>=1.8.18
markdown>=3.4
beautifulsoup4>=4.12
requests>=2.28
No suspicious patterns detected.