Back to skill

Security audit

微信公众号文章生产SOP

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent WeChat article workflow, but its draft submission script can expose local files and stores a live WeChat access token in plaintext.

Review this skill before installing. It needs WeChat account credentials and can submit drafts and upload article assets. Do not run it on untrusted HTML, and avoid using it in workspaces containing sensitive images until image path confinement is fixed. Treat generated draft.json files as sensitive because the current script stores a WeChat access token there.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/submit-draft.js:463
Finding

WeChat Access Token Persisted in Plaintext

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/submit-draft.js:262
Finding

Unrestricted HTML Image Paths Can Upload Files Outside the Article Directory

Content
View full analysis
]+src=["']([^"']+)["'][^>]*>/g; const images = []; let match; // HTML文件所在目录 const htmlDir = path.dirname(path.resolve(htmlPath)); while ((match = imgRegex.exec(html)) !== null) { let imgSrc = match[1]; // 如果是相对路径,解析为绝对路径 if (!imgSrc.startsWith('http')) { // 解析为绝对路径 const absolutePath = path.resolve(htmlDir, imgSrc); // 检查图片是否存在 if (fs.existsSync(absolutePath)) { images.push(absolutePath); } } } ``` The resulting paths are later read and uploaded: ```javascript const allImages = new Set([...images]); for (const image of allImages) { const uploadResult = await uploadImage(accessToken, image); uploadedImages.push(uploadResult); // 替换HTML中的本地图片URL为微信服务器URL const localImagePath = image; const localImageName = path.basename(localImagePath); const wechatImageUrl = uploadResult.url; // 替换相对路径的图片 (如 images/api-summary.png) const htmlDir = path.dirname(path.resolve(options.html)); const relativePath = path.relative(htmlDir, localImagePath); // 替换带 ./ 前缀的相对路径 const withDotSlashPattern = new RegExp('\\./' + relativePath.replace(/\//g, '\\/'), 'g'); let tempContent = processedContent; tempContent = tempContent.replace(withDotSlashPattern, wechatImageUrl); // 替换标准相对路径 const normalPattern = new RegExp(relativePath.replace(/\//g, '\\/'), 'g'); tempContent = tempContent.replace(normalPattern, wechatImageUrl); // 替换纯文件名的图片 const namePattern = new RegExp(localImageName, 'g'); tempContent = tempContent.replace(namePattern, wechatIm ...[truncated 3094 chars]
Remediation
View remediation
/images`. 2. Canonicalize both the allowed root and candidate file using `fs.realpathSync()` before comparing them. This also addresses symlink escapes. 3. Reject absolute paths, traversal components, non-regular files, and paths outside the allowed root. 4. Validate file signatures and MIME types rather than relying only on extensions. 5. Enforce maximum file sizes before reading files into memory. 6. Require explicit user confirmation of the final upload manifest before network transmission. Example confinement logic: ```javascript const allowedRoot = fs.realpathSync( path.join(path.dirname(path.resolve(htmlPath)), 'images') ); function resolveApprovedImage(imgSrc) { if ( path.isAbsolute(imgSrc) || /^https?:\/\//i.test(imgSrc) || imgSrc.includes('\0') ) { throw new Error(`Disallowed image path: ${imgSrc}`); } const candidate = fs.realpathSync(path.resolve(allowedRoot, imgSrc)); const relative = path.relative(allowedRoot, candidate); if ( relative === '' || relative.startsWith(`..${path.sep}`) || relative === '..' || path.isAbsolute(relative) ) { throw new Error(`Image escapes approved directory: ${imgSrc}`); } const stats = fs.statSync(candidate); if (!stats.isFile()) { throw new Error(`Image is not a regular file: ${imgSrc}`); } return candidate; } ``` If HTML image paths are expected to be relative to the article directory rather than `images/`, use that directory as the approved root while retaining all canonical-path and file-type checks. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/temp-convert.js:47
Finding

Sandbox-Disabled Chromium Renders Caller-Supplied Active HTML

Content
View full analysis
Remediation
View remediation
{ const url = request.url(); if (url === 'about:blank' || url.startsWith('data:')) { request.continue(); } else { request.abort(); } }); ``` 4. Sanitize HTML before rendering by rejecting scripts, frames, object/embed elements, event-handler attributes, and remote resource URLs. 5. Run the converter under a dedicated low-privilege operating-system account with no access to credentials or unrelated workspace files. 6. Apply container-level filesystem and network restrictions as defense in depth. Do not treat a container as a replacement for Chromium’s own sandbox. 7. Keep Puppeteer and its bundled Chromium version updated, and add tests confirming that generated pages cannot make external requests. 8. Apply execution timeouts and page-size limits to reduce denial-of-service risks from pathological HTML. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (36)

Vague Triggers

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The trigger condition is extremely broad, instructing immediate use whenever a user mentions common article-related phrases. This can cause unintended activation in ordinary conversation and may launch a workflow that performs research, content generation, file creation, and eventual external publication steps without sufficiently explicit user intent for this specific skill.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: basic-ftp==5.2.0 — 4 advisory(ies): GHSA-6v7q-wjvx-w8wg (basic-ftp: Incomplete CRLF Injection Protection Allows Arbitrary FTP Command Exe); CVE-2026-39983 (basic-ftp has FTP Command Injection via CRLF); CVE-2026-41324 (basic-ftp vulnerable to denial of service via unbounded memory consumption in Cl) +1 more

High
Category
Supply Chain
Confidence
92% confidence
Finding

The lockfile includes basic-ftp 5.2.0, which is flagged for FTP command injection and denial-of-service issues. In this dependency graph it is only pulled in transitively via get-uri/pac-proxy-agent/proxy-agent for proxy handling, so exposure depends on whether the application processes attacker-controlled FTP/PAC URIs or proxy settings; that makes the issue real but likely less directly reachable from normal Puppeteer usage.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: extract-zip==2.0.1 — 2 advisory(ies): CVE-2026-19693 (extract-zip allows arbitrary file writes through symlink archive entries); CVE-2026-56876 (extract-zip unvalidated symlink path traversal)

High
Category
Supply Chain
Confidence
96% confidence
Finding

extract-zip 2.0.1 is present and has reported symlink/path traversal issues that can lead to arbitrary file writes during archive extraction. Because Puppeteer and @puppeteer/browsers use archive download/extraction flows for browser binaries, this becomes more relevant than a dormant library issue if untrusted archives, mirrors, or manipulated downloads are ever processed.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ip-address==10.1.0 — 2 advisory(ies): CVE-2026-69192 (ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco); CVE-2026-42338 (ip-address has XSS in Address6 HTML-emitting methods)

High
Category
Supply Chain
Confidence
80% confidence
Finding

ip-address 10.1.0 is reported with parsing and HTML-emission issues. In this tree it is a transitive dependency of socks, used by socks-proxy-agent/proxy-agent, so the vulnerable functionality may only matter if the application accepts attacker-controlled proxy configuration or renders library-produced HTML; otherwise practical exploitability is limited.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: js-yaml==4.1.1 — 4 advisory(ies): CVE-2026-84375 (js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources); CVE-2026-59869 (js-yaml: YAML merge-key chains can force quadratic CPU consumption); GHSA-5p4m-2wfm-xmqj (JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026) +1 more

High
Category
Supply Chain
Confidence
89% confidence
Finding

js-yaml 4.1.1 is included with advisories for CPU-exhaustion via crafted YAML structures. In this dependency graph it comes from cosmiconfig, which means the danger depends on whether the tool loads YAML configuration from untrusted sources; for a CLI/automation skill that may read local config, this is a plausible denial-of-service vector rather than remote code execution.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ws==8.20.0 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
90% confidence
Finding

ws 8.20.0 is flagged for memory disclosure and memory exhaustion issues. Since Puppeteer relies on WebSocket communication with Chromium via puppeteer-core, malformed or attacker-influenced WebSocket traffic could affect confidentiality or availability if the debugging connection is exposed, proxied, or otherwise reachable by untrusted parties.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script persists the access token into draft.json on disk, creating a local plaintext credential artifact that may be readable by other users, backup systems, logs, or later tools. In a skill/agent environment this is especially risky because workspace files are often inspected, uploaded, or retained automatically, turning a short-lived token into a broader credential exposure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill integrates with external services including the WeChat Official Account API and Feishu documents, and it culminates in draft submission, but the top-level description does not clearly warn that user content may be transmitted to third parties. In a content-production skill, this increases the risk of users unintentionally disclosing unpublished, sensitive, or proprietary material to external platforms.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
80% confidence
Finding

The document title and all instructions are written exclusively in Chinese, presenting the style guide as a fixed language-specific standard rather than offering language selection. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale constraint is clearly documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The file explicitly defines itself as a Chinese AI text detector and all detection patterns, CLI description, and output strings are hard-coded for Chinese text only. There is no user choice of language or locale, so the skill imposes a specific language behavior rather than offering opt-in or documenting a justified regional constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The module description states that it humanizes Chinese AI-generated text, and the rest of the CLI/help text is also fixed to Chinese. Under the policy rule for language or locale constraints, this is a natural-language locale restriction without an explicit user language choice or justification as a region-specific tool.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The module docstring describes a Chinese AI text humanizer focused on text transformations such as sentence restructuring and replacement. However, the optional style feature invokes an external script via subprocess, introducing process-execution capability beyond the stated text-processing purpose in this file's documentation.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/humanize_cn.py (reported line 495)May include surrounding context.

python
tmp_path = tmp.name
            
            try:
                proc = subprocess.run(
                    ['python3', style_script, tmp_path, '--style', args.style],
                    capture_output=True, text=True, encoding='utf-8'
                )

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This JSON file is entirely specialized to Chinese phrases, regexes, and Chinese-language descriptions, which indicates the skill behavior is constrained to a specific language/locale. Under the policy, forcing a specific language without explicit user choice or a clearly documented justification can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The module description states that it transforms text into different Chinese writing styles, which imposes a fixed language/locale behavior. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the constraint is clearly documented as a justified region-specific limitation or the user is given a choice.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script reads WeChat credentials not only from explicit environment variables but also from a separate ~/.openclaw/env file, widening the trust boundary and potentially using secrets from an unrelated local context without clear user consent. In an agent/skill setting, this can cause unintended credential harvesting or cross-project secret use if the skill is run on a host that already has OpenClaw credentials configured.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/submit-draft.js (reported line 100)May include surrounding context.

js
// 获取access_token - 使用微信官方接口
async function getAccessToken() {
  console.log('正在获取access_token...');
  const apiUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`;
  
  try {
    const response = await fetch(apiUrl, {

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/submit-draft.js (reported line 129)May include surrounding context.

js
// 获取access_token - 使用微信官方接口
async function getAccessToken() {
  console.log('正在获取access_token...');
  const apiUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`;
  
  try {
    const response = await fetch(apiUrl, {

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/submit-draft.js (reported line 169)May include surrounding context.

js
// 获取access_token - 使用微信官方接口
async function getAccessToken() {
  console.log('正在获取access_token...');
  const apiUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`;
  
  try {
    const response = await fetch(apiUrl, {

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/submit-draft.js (reported line 220)May include surrounding context.

js
// 获取access_token - 使用微信官方接口
async function getAccessToken() {
  console.log('正在获取access_token...');
  const apiUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`;
  
  try {
    const response = await fetch(apiUrl, {

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/submit-draft.js (reported line 323)May include surrounding context.

js
// 获取access_token - 使用微信官方接口
async function getAccessToken() {
  console.log('正在获取access_token...');
  const apiUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`;
  
  try {
    const response = await fetch(apiUrl, {

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The markdown explicitly instructs the skill to prioritize Chinese sources (优先中文源). This is a natural-language locale constraint that does not offer the user a choice or explain a region-specific necessity, which fits the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill instructs the agent to create a Feishu document and send the resulting document or link to the user without any explicit user consent step or warning that research content will be shared to an external third-party service. If the research includes sensitive prompts, internal notes, proprietary data, or user-provided content, this can cause unintended data disclosure outside the primary interaction channel.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This markdown file instructs the user exclusively in Chinese, from the title through the output instructions, with no indication that language preference is optional. Under the policy, forcing a specific language without user opt-in is a natural-language locale violation unless clearly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This markdown file presents all operational instructions and acceptance criteria exclusively in Chinese. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is clearly documented and justified, which is not present here.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/submit-draft.js:15