Back to skill

Security audit

智能微信公众号发布技能

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims by creating WeChat drafts, but it needs review because it handles account secrets unsafely, recommends risky privileged installs, and inserts hardcoded/fabricated publishing content.

Install only after reviewing and changing the setup flow: avoid sudo/curl-to-bash instructions, do not put AppSecret in shell history or ordinary shared files, inspect the generated draft before publishing, remove hardcoded footer/author/source claims, and use a restricted WeChat credential that can be rotated.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (5)

T03 · Remote Payload Retrieval and Execution

Error
Location
docs/user_guide.md:86
Finding
Privileged Execution of an Unverified Remote Installation Script<![CDATA[ ## Vulnerability Details **File Location**: `docs/user_guide.md:86` **Vulnerability Type**: Remote payload retrieval and privileged execution **Risk Level**: Critical ### Vulnerable Code ```bash curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash - ``` ### Technical Analysis The installation guide directs users to retrieve a mutable shell script from an external URL and immediately pipe it into a root shell. The downloaded payload is not pinned to a specific version, inspected, authenticated with a detached signature, or verified against a known checksum. Although installing Node.js may support the documented OpenClaw setup process, granting an external response unrestricted root-level execution exceeds the minimum privileges needed by the WeChat publishing Skill itself. The command also prevents the user from reviewing the effective payload before execution. The payload can change after the Skill has been audited. Compromise of the upstream hosting environment, delivery infrastructure, DNS/TLS trust chain, or the referenced account could therefore convert this installation instruction into arbitrary privileged code execution. ### Attack Path 1. A user follows the Linux installation instructions. 2. The user executes the documented command with `sudo`. 3. The remote endpoint or its delivery path supplies a malicious or compromised shell script. 4. `curl` streams that script directly into `bash`. 5. The script executes with root privileges without integrity verification or prior review. 6. The payload can modify system files, install services, create privileged accounts, or collect local secrets. ### Impact Assessment Successful exploitation provides arbitrary command execution as root. An attacker could compromise the entire host, access credentials belonging to multiple users, modify security controls, install persistent services, tamper with applications, or use the host to attack other systems. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Remove all pipe-to-shell installation instructions. - Prefer installation through the operating system's signed and supported package repositories. - If a standalone installer is required: 1. Pin it to an immutable versioned artifact. 2. Download it to disk without executing it. 3. Publish and verify a cryptographic checksum or detached signature. 4. Allow the user to inspect the script. 5. Run only the operations that actually require elevated privileges with `sudo`. - Document the expected publisher, artifact version, checksum, and verification procedure. - Avoid requiring root privileges for installing or running this Skill wherever possible. ]]>

T01 · Skill Instruction Hijacking

Error
Location
templates/v5-simple.html:62
Finding
Undisclosed Third-Party Branding Is Injected into Published Articles<![CDATA[ ## Vulnerability Details **File Location**: `templates/v5-simple.html:62-66` **Vulnerability Type**: Forced publication-output manipulation **Risk Level**: High ### Vulnerable Code ```html <!-- 底部信息 --> <section style="padding:20px 18px;text-align:center;"> <p style="font-size:12px;color:#999999;margin:0 0 6px;">数据来源</p> <p style="font-size:11px;color:#888888;margin:0 0 16px;">TechCrunch AI · MIT Technology Review · The Verge</p> <p style="font-size:13px;font-weight:600;color:#1a1a1a;margin:0 0 4px;">心识孤独的猎手</p> <p style="font-size:11px;color:#999999;margin:0;">AI 行业前沿资讯 · 每日更新</p> </section> ``` The template is loaded and subsequently uploaded without removing this fixed identity: ```python template = self._load_template() content = template.replace("{DATE}", today_date) ``` ### Technical Analysis The default publication template includes a fixed third-party identity rather than a configurable identity belonging to the user's WeChat account. The publisher loads this template, replaces selected news placeholders, and submits the resulting HTML to the user's WeChat draft account. The fixed branding is not necessary to generate or upload an AI-news draft. It modifies the user's externally visible publication output and is not presented as an explicit opt-in requirement. The same footer also makes fixed source-attribution claims regardless of whether the generated content was actually obtained from those sources. ### Attack Path 1. The user accepts the default `v5-simple` template. 2. The publisher loads the template containing the fixed identity. 3. The preparation routine replaces only designated placeholders and leaves the fixed branding intact. 4. The complete HTML is submitted to the user's WeChat draft account. 5. If the user publishes the draft without identifying the injected footer, the third-party branding appears under the user's account. ### Impact Assessment The behavior can cause unauthorized attribution, reputatio ...[truncated 301 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the fixed third-party identity from the default template. - Add explicit configuration fields for publisher name, footer text, and source attribution. - Default those fields to empty values rather than developer-controlled branding. - Clearly preview the exact article content before any authenticated upload. - Require affirmative user consent before adding promotional or third-party material. - Generate source attributions from the sources actually used for each article instead of inserting unconditional claims. - Add a validation step that reports unresolved placeholders and fixed third-party identities before publication. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/publish.py:108
Finding
WeChat AppSecret and Access Tokens Are Stored in Plaintext Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/publish.py:108-120, 169-178`; `config/default.json:1-4`; `docs/user_guide.md:229-243` **Vulnerability Type**: Insecure plaintext credential storage **Risk Level**: Medium ### Vulnerable Code The runtime reads the AppSecret directly from a JSON configuration file: ```python def _get_app_secret(self): """从环境变量或配置获取 AppSecret""" # 优先从环境变量读取 app_secret = os.environ.get("WECHAT_APP_SECRET") if app_secret: self.logger.info("AppSecret 从环境变量读取成功") return app_secret # 从配置文件读取 app_secret = self.config.get("app_secret") if app_secret: self.logger.info("AppSecret 从配置文件读取成功") return app_secret ``` It also writes the bearer token to a plaintext cache: ```python cache_data = { "token": token, "time": datetime.now().isoformat(), "expires_in": result.get("expires_in", 7200) } with open(self.token_cache_path, "w", encoding="utf-8") as f: json.dump(cache_data, f, indent=2, ensure_ascii=False) ``` The supplied configuration schema contains a plaintext secret field: ```json { "app_id": "", "app_secret": "", "cover_media_id": "" } ``` The guide explicitly instructs users to store the secret in JSON: ```json { "app_id": "wxebff9eadface1489", "app_secret": "44c10204ceb1bfb3f7ac096754976454", "schedule": "06:00", "template": "v5-simple", "news_count": 15, "timezone": "Asia/Shanghai" } ``` ### Technical Analysis The Skill supports storing a long-lived WeChat AppSecret in an ordinary JSON file and caches the resulting bearer token in another ordinary JSON file. The code creates these files using normal `open()` calls and does not explicitly enforce restrictive file permissions. Consequently, protection depends on the process umask and surrounding installation environment. Backups, support bundles, accidental package archives, local malware, or another local account may expose the credentials. Possession of the token permi ...[truncated 1342 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Store the AppSecret in an operating-system keychain, credential manager, or dedicated secret-management service. - Prefer short-lived credential injection at runtime over persistent JSON storage. - Create the private state directory with mode `0700` on POSIX systems. - Create credential and token files atomically with mode `0600`; verify existing file ownership and permissions before reading them. - Avoid placing secrets in the installed Skill directory. - Exclude configuration secrets, token caches, logs, and memory files from archives and version control. - Minimize token caching and securely delete expired token material where practical. - Document credential rotation and incident-response procedures. - Never include actual credential-shaped values in examples; use unmistakable placeholders. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
docs/user_guide.md:218
Finding
Documentation Encourages Passing the AppSecret as a Command-Line Argument<![CDATA[ ## Vulnerability Details **File Location**: `docs/user_guide.md:218-223` **Vulnerability Type**: Sensitive credential exposure through process arguments and shell history **Risk Level**: Medium ### Vulnerable Code ```bash # 一条命令完成配置 openclaw skill config wechat-publisher \ --app-id wxebff9eadface1489 \ --app-secret 44c10204ceb1bfb3f7ac096754976454 ``` ### Technical Analysis Command-line arguments are generally unsuitable for secrets. Depending on the operating system and shell configuration, arguments may be retained in shell history, exposed through process inspection interfaces, captured by audit systems, recorded in terminal sessions, or copied into diagnostic logs. The example also uses a realistic credential-shaped value rather than an unmistakable placeholder, increasing the chance that users will substitute and expose their real secret using the same unsafe pattern. ### Attack Path 1. The user copies the documented command and replaces the example with a real AppSecret. 2. The shell stores the complete command in its history file, or the argument appears in a process listing while the command runs. 3. Another local user, administrative monitoring service, terminal recorder, support tool, or malware process reads the argument. 4. The exposed AppSecret is combined with the AppID to request WeChat access tokens. 5. The attacker uses those tokens for unauthorized API operations. ### Impact Assessment Exposure of the AppSecret may allow an attacker to request authenticated WeChat API tokens until the secret is rotated. This can result in unauthorized access to account-level API functionality, including manipulation of drafts within the permissions available to the affected account. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the `--app-secret` command-line example. - Collect secrets through a non-echoing interactive prompt, an operating-system keychain, or a protected file descriptor. - If environment variables are supported, warn users about inheritance and diagnostic exposure and recommend setting them only for the required process. - Ensure configuration-display commands fully redact secrets rather than displaying partial values. - Replace credential-shaped examples with placeholders such as `YOUR_WECHAT_APP_SECRET`. - Add automated tests ensuring secrets are never written to logs or included in error messages. ]]>

T08 · Insecure Dependencies

Warning
Location
docs/user_guide.md:24
Finding
Unpinned Packages Are Installed Globally and Sometimes with Root Privileges<![CDATA[ ## Vulnerability Details **File Location**: `docs/user_guide.md:24-25, 65-76, 86-90, 430-436`; `scripts/publish.py:18-21` **Vulnerability Type**: Unsafe and unpinned third-party dependency installation **Risk Level**: Medium ### Vulnerable Code The guide installs the latest available global package without a version or integrity constraint: ```bash # 第 1 步:安装 OpenClaw npm install -g openclaw ``` It repeats the installation in platform-specific instructions: ```bash # 2. 安装 OpenClaw npm install -g openclaw ``` The Linux instructions use elevated global installation: ```bash sudo npm install -g openclaw ``` The troubleshooting section introduces a different registry and again recommends root-level installation: ```bash npm config set registry https://registry.npmmirror.com npm install -g openclaw # 解决方案 2:使用 sudo(macOS/Linux) sudo npm install -g openclaw ``` The Python script similarly recommends an unconstrained dependency: ```python try: import requests except ImportError: print("❌ 缺少依赖:requests") print("请运行:pip install requests") sys.exit(1) ``` ### Technical Analysis No exact dependency versions, lockfile, package integrity values, or signature-verification instructions are supplied. Installing the latest global package makes the effective code dependent on whatever artifact the registry serves at installation time. Using `sudo npm install -g` substantially increases the consequence of malicious lifecycle scripts, package-account compromise, registry compromise, or unsafe future releases. Switching to an alternate registry adds another supply-chain trust dependency without documenting verification controls. The unconstrained `pip install requests` recommendation also makes environments non-reproducible, although `requests` itself is a well-known package and no evidence of a malicious package substitution was found in the audited artifact. ### Attack Path 1. A user follows the installation or troubleshooting instructio ...[truncated 786 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin every dependency to a reviewed version. - Supply a lockfile and integrity hashes for reproducible installation. - Avoid global package installation and use an isolated, least-privileged environment. - Do not recommend `sudo npm install -g`. - Document the expected registry and avoid changing the user's global registry configuration. - If a mirror is supported, verify package integrity independently of that mirror. - Provide a Python requirements file with exact versions and hashes, and recommend installation into a virtual environment. - Use automated dependency scanning and a controlled update-review process. - Clearly separate installation requirements for OpenClaw from the minimum dependencies needed by the publisher itself. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (23)

Tainted flow: 'params' from os.environ.get (line 147, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
for i in range(1, retry_count + 1):
            try:
                self.logger.info(f"获取 Token(尝试 {i}/{retry_count})")
                response = requests.get(token_url, params=params, timeout=30)
                response.raise_for_status()
                result = response.json()
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'params' from os.environ.get (line 147, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
for i in range(1, retry_count + 1):
            try:
                self.logger.info(f"创建草稿(尝试 {i}/{retry_count})")
                response = requests.post(
                    draft_url,
                    params=params,
                    json=data,
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Chaining Abuse

High
Category
Tool Misuse
Content
```bash
# 1. 打开终端
# 2. 安装 Node.js(如未安装)
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs

# 3. 安装 OpenClaw
Confidence
98% confidence
Finding
Chaining curl directly into sudo bash creates a one-step path from network content to privileged code execution. In a skill installation guide, this is especially dangerous because users are primed to trust and execute setup commands without inspection, amplifying supply-chain and MITM risk.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
# 1. 打开终端
# 2. 安装 Node.js(如未安装)
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs

# 3. 安装 OpenClaw
Confidence
95% confidence
Finding
The use of sudo -E preserves the caller's environment while invoking a root shell on a remotely fetched script. Preserving environment variables can unintentionally influence privileged execution and broadens the attack surface beyond the already dangerous curl-to-bash pattern.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
# 1. 打开终端
# 2. 安装 Node.js(如未安装)
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs

# 3. 安装 OpenClaw
Confidence
95% confidence
Finding
The use of sudo -E preserves the caller's environment while invoking a root shell on a remotely fetched script. Preserving environment variables can unintentionally influence privileged execution and broadens the attack surface beyond the already dangerous curl-to-bash pattern.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
# 1. 打开终端
# 2. 安装 Node.js(如未安装)
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs

# 3. 安装 OpenClaw
sudo npm install -g openclaw
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
# 1. 打开终端
# 2. 安装 Node.js(如未安装)
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs

# 3. 安装 OpenClaw
sudo npm install -g openclaw
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The guide instructs users to pass the WeChat AppSecret directly as a command-line argument. Secrets provided this way can be exposed through shell history, terminal logging, CI logs, and process listings visible to other local users, creating a realistic credential leakage path.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The manual shows a full AppSecret embedded in a plaintext configuration example and gives only minimal permission guidance later in the FAQ. This normalizes storing sensitive credentials in cleartext files without adequate storage warnings, increasing the chance of accidental disclosure via backups, screenshots, source control, or weak file permissions.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
npm install -g openclaw

# 解决方案 2:使用 sudo(macOS/Linux)
sudo npm install -g openclaw
```

**Q2: openclaw 命令找不到?**
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
# 检查配置文件权限
# macOS/Linux:
chmod 600 ~/.agents/skills/wechat-publisher/config/config.json

# Windows: 以管理员身份运行配置命令
```
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
文件头部说明、类与日志文案均以中文固定呈现,未见用户可选择语言/区域的机制,也没有声明该技能仅面向特定中文环境。按照语言/locale 政策,强制单一语言而无用户选择或合理限定,属于自然语言层面的策略问题。

External Transmission

Medium
Category
Data Exfiltration
Content
# 获取新 Token
        app_secret = self._get_app_secret()
        token_url = "https://api.weixin.qq.com/cgi-bin/token"
        params = {
            "grant_type": "client_credential",
            "appid": self.config["app_id"],
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# 获取新 Token
        app_secret = self._get_app_secret()
        token_url = "https://api.weixin.qq.com/cgi-bin/token"
        params = {
            "grant_type": "client_credential",
            "appid": self.config["app_id"],
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Intent-Code Divergence

Medium
Confidence
92% confidence
Finding
The script claims to automatically publish AI news, but the content is hardcoded placeholder text rather than sourced current news. In a publishing automation context, this mismatch can cause unauthorized or misleading publication of fabricated/stale content, creating integrity and reputational risk for the account owner.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The script includes trial enforcement, local license checks, usage tracking, and purchase upsell behavior unrelated to the core publishing function. In an agent skill context, this is risky because it introduces hidden business logic, local state manipulation, and user-pressure behavior that can interfere with automation and may not be expected by operators reviewing a publishing tool.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The script performs a remote draft-creation action against a live WeChat account without an explicit confirmation prompt, dry-run mode, or strong risk notice at the point of execution. In an agent skill setting, this increases the chance of unintended external publication actions when run automatically or by a user who misunderstands the effect.

External Transmission

Medium
Category
Data Exfiltration
Content
for i in range(1, retry_count + 1):
            try:
                self.logger.info(f"创建草稿(尝试 {i}/{retry_count})")
                response = requests.post(
                    draft_url,
                    params=params,
                    json=data,
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill explicitly automates publishing to a WeChat public account draft box and requires `app_id` and `app_secret`, but it does not warn users that content and credentials will be used to write data to an external third-party platform. This can cause users to disclose sensitive credentials or trigger unintended publication workflows without informed consent, especially because the skill markets convenience and automation rather than data-handling risks.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The config hard-codes "Asia/Shanghai" as the timezone, which is a locale-specific setting. Under the policy, forcing a specific locale without user opt-in or clear region-specific justification is a natural-language policy concern.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The natural-language content presents the entire skill guide exclusively in Chinese and does not indicate that the user can choose another language or that the skill is intentionally limited to a Chinese-speaking audience for a documented reason. Under the stated policy, forcing a specific language without opt-in can be a locale-policy issue.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The documentation sets `timezone` to `Asia/Shanghai` by default without clearly documenting that this is a China-specific locale assumption or emphasizing user choice. In an automation skill that schedules external publication, an implicit timezone default can cause posts to be published at unintended times, which may lead to operational mistakes or accidental release of content.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
This HTML template hard-codes Chinese headings and footer text alongside an English subtitle, which imposes a specific language/locale presentation on generated output. Under the policy, language constraints should either be user-selectable or clearly justified as region-specific.

Static analysis

No suspicious patterns detected.