Back to skill

Security audit

WeChat MP Multi-Publisher

Security checks for vulnerabilities and agentic risk

Overview

The skill largely does what it claims, but it can upload local files referenced by Markdown and publish to a live WeChat account without strong safety checks.

Review this before installing if you publish sensitive or externally supplied Markdown. Use --dry-run first, do not run --publish unless you intend live publication, keep WeChat credentials in environment or a protected secret store when possible, set owner-only permissions if using the credentials file, and only process Markdown/images you trust until image path confinement is fixed.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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

Error
Location
scripts/publish.mjs:128
Finding

Markdown Image Paths Can Read and Upload Files Outside the Article Directory

Content
View full analysis
]*src="([^"]+\.(png|jpg|jpeg|gif|webp))"[^>]*>/gi; let result = html; for (const match of [...html.matchAll(imgRegex)]) { const src = match[1]; if (src.startsWith("http")) continue; const wxUrl = await uploadInlineImage(path.resolve(mdDir, src), accessToken); result = wxUrl ? result.replace(src, wxUrl) : result.replace(match[0], `

[Image load failed]

`); } return result; } ``` ### Technical Analysis The source path of each rendered image is derived from article content and resolved with `path.resolve(mdDir, src)`. The resulting path is not checked to ensure that it remains inside the Markdown article directory or another explicitly authorized asset directory. Consequently, absolute paths and paths containing `../` components can escape `mdDir`. The program then reads the resolved file with `fs.readFileSync()` and uploads its contents to the WeChat media API. File type handling relies solely on the filename suffix and does not validate the actual file format. The exploitable scope is limited to files readable by the publishing process whose path ...[truncated 1469 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
references/setup.md:17
Finding

Credential File Setup Does Not Enforce Restrictive Permissions

Content
View full analysis
~/.config/wechat-mp/credentials.json << 'EOF' { "appId": "your_appid", "appSecret": "your_appsecret" } EOF ``` ### Technical Analysis The documented setup stores a reusable WeChat application secret in a plaintext JSON file but does not set permissions on either the containing directory or the credential file. The effective permissions therefore depend on the user's current `umask` and any preexisting directory permissions. In an environment with permissive defaults, other local users may be able to read the credentials. The publishing script subsequently trusts and uses these values to request an API access token. Storing the credential is necessary for unattended publishing, but access should be restricted to the account running the publisher. The current instructions do not enforce that least-privilege boundary. ### Attack Path 1. A user follows the documented credential-file setup. 2. The user's `umask` or existing directory permissions allow group or other users to read the generated file. 3. Another local user reads `~/.config/wechat-mp/credentials.json`. 4. The attacker extracts the WeChat application ID and application secret. 5. If the attacker can operate from an IP accepted by the WeChat account's API policy, the credentials can be used to request an access token. 6. The token can then be used for operations permitted to that WeChat application. ### Impact Assessment Exposure of the application secret may permit unauthorized use of the associated WeChat API account, subject to WeChat's IP whitelist and other platform controls. Potential consequences include unauthorized media uploads, draft creation, and publication actions available to the application. The issue does not itself bypass WeChat's extern ...[truncated 136 chars]
Remediation
View remediation
"$HOME/.config/wechat-mp/credentials.json" << 'EOF' { "appId": "your_appid", "appSecret": "your_appsecret" } EOF chmod 600 "$HOME/.config/wechat-mp/credentials.json" ``` Additional hardening measures: 1. Verify file ownership and mode in `getCredentials()` before reading it. 2. Reject credential files writable or readable by unauthorized users. 3. Prefer a managed secret store for CI, servers, and scheduled execution. 4. Avoid placing secrets directly in shell command histories. 5. Document credential rotation and immediate revocation procedures. 6. Grant the associated WeChat application only the permissions required for draft and publication operations. ]]>

T08 · Insecure Dependencies

Warning
Location
references/setup.md:3
Finding

Third-Party npm Dependency Is Installed Without Version or Integrity Pinning

Content
View full analysis
Remediation
View remediation
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
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (19)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 29)May include surrounding context.

md
node scripts/publish.mjs main-article.md [sub-article.md ...]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 56)May include surrounding context.

md
node scripts/publish.mjs main-article.md [sub-article.md ...]

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The documented creation of ~/.config/wechat-mp/credentials.json stores appId and appSecret in a predictable plaintext location, which can be read by other processes, accidentally backed up, or included in support bundles if file permissions are not locked down. Because the appSecret enables authenticated API access, compromise could allow unauthorized draft management or publication actions.

Content

Scanner excerpt · references/setup.md (reported line 21)May include surrounding context.

Option B — Credentials file:

bash
mkdir -p ~/.config/wechat-mp
cat > ~/.config/wechat-mp/credentials.json << 'EOF'
{
  "appId": "your_appid",
  "appSecret": "your_appsecret"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 16)May include surrounding context.

md
*
 * Credentials (priority order):
 *   1. Env vars: WECHAT_APP_ID, WECHAT_APP_SECRET
 *   2. ~/.config/wechat-mp/credentials.json  { "appId": "...", "appSecret": "..." }
 */

import { renderStyledContent } from "@wenyan-md/core/wrapper";

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/publish.mjs (reported line 11)May include surrounding context.

js
*
 * Credentials (priority order):
 *   1. Env vars: WECHAT_APP_ID, WECHAT_APP_SECRET
 *   2. ~/.config/wechat-mp/credentials.json  { "appId": "...", "appSecret": "..." }
 */

import { renderStyledContent } from "@wenyan-md/core/wrapper";

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/publish.mjs (reported line 19)May include surrounding context.

js
*
 * Credentials (priority order):
 *   1. Env vars: WECHAT_APP_ID, WECHAT_APP_SECRET
 *   2. ~/.config/wechat-mp/credentials.json  { "appId": "...", "appSecret": "..." }
 */

import { renderStyledContent } from "@wenyan-md/core/wrapper";

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/publish.mjs (reported line 95)May include surrounding context.

js
*
 * Credentials (priority order):
 *   1. Env vars: WECHAT_APP_ID, WECHAT_APP_SECRET
 *   2. ~/.config/wechat-mp/credentials.json  { "appId": "...", "appSecret": "..." }
 */

import { renderStyledContent } from "@wenyan-md/core/wrapper";

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/publish.mjs (reported line 282)May include surrounding context.

js
}

  const { appId, appSecret } = getCredentials();
  console.log("🔑 Getting access token...");
  const token = await getAccessToken(appId, appSecret);

  console.log("🖼️  Processing inline images...");

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The activation text is broad enough to trigger on general requests about WeChat publishing, scheduling, or automation without clearly constraining scope or requiring explicit confirmation. In a skill that can create drafts and optionally publish externally visible content, over-broad activation increases the chance of unintended invocation and accidental outbound actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The description advertises optional immediate publish but does not warn that this can make content externally visible on a live WeChat Official Account. Users or downstream agents may treat the capability as routine formatting/transfer rather than a potentially irreversible publication action.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The --publish flag triggers freepublish after draft creation, but the CLI reference gives no warning about external visibility, account impact, or the need for deliberate confirmation. This makes accidental live publication more likely, especially in automation or when invoked by another agent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The setup guide instructs users to place WeChat credentials in environment variables and a plaintext JSON file without warning about shell history, file permissions, backup leakage, or secret exposure on multi-user systems and CI logs. While common in setup docs, this still increases the chance of credential compromise because these secrets grant API access to draft creation and publication workflows.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/setup.md (reported line 20)May include surrounding context.

Option B — Credentials file:

bash
mkdir -p ~/.config/wechat-mp
cat > ~/.config/wechat-mp/credentials.json << 'EOF'
{
  "appId": "your_appid",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The guide shows commands that upload drafts and can immediately publish content to a live WeChat Official Account, but it does not prominently warn that these operations cause remote side effects. In automation contexts, users may run examples assuming they are local tests, leading to unintended publication or disclosure of draft content.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/setup.md (reported line 58)May include surrounding context.

bash
# Daily push at 6am (Beijing)
# crontab -e
0 22 * * * cd /your/project && node publish.mjs articles/deep.md articles/news.md >> /var/log/wechat-push.log 2>&1

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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/publish.mjs (reported line 18)May include surrounding context.

js
import fs from "fs";
import path from "path";

const WECHAT_API = "https://api.weixin.qq.com/cgi-bin";
const CREDENTIALS_PATH = path.resolve(process.env.HOME, ".config/wechat-mp/credentials.json");

// === Cover image: keyword → Unsplash search ===

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/publish.mjs (reported line 95)May include surrounding context.

js
const creds = JSON.parse(fs.readFileSync(CREDENTIALS_PATH, "utf-8"));
    return { appId: creds.appId, appSecret: creds.appSecret };
  }
  throw new Error("No credentials found. Set WECHAT_APP_ID + WECHAT_APP_SECRET env vars, or create ~/.config/wechat-mp/credentials.json");
}

async function getAccessToken(appId, appSecret) {

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script obtains credentials, uploads article content and images to external services, creates drafts, and can immediately publish when flags are present, but it does not require an explicit runtime confirmation before transmission. In an agent-skill context, this increases the risk of unintended publication or transmission of sensitive local content if invoked automatically or with user-supplied paths.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The manifest describes a Markdown-to-WeChat publishing skill, but does not mention reading secrets from ~/.config/wechat-mp/credentials.json. While credential use is expected for WeChat API access, silently sourcing them from a home-directory file is an additional capability not declared in the stated purpose text.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.env_credential_access, suspicious.potential_exfiltration

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/publish.mjs:19

Sensitive-looking file read is paired with a network send.

Warn
Code
suspicious.potential_exfiltration
Location
scripts/publish.mjs:92