Back to skill

Security audit

OpenClaw Weixin Channel

Security checks for vulnerabilities and agentic risk

Overview

This WeChat channel plugin is mostly coherent, but it includes under-scoped file upload, URL download, log upload, and token logging behavior that could expose local files or credentials.

Review this plugin before installing on a machine with sensitive files or cloud credentials. Only use it in an isolated OpenClaw environment, avoid debug logging during login, do not run the log-upload command except to a trusted HTTPS endpoint, and treat stored Weixin credentials and context-token files as secrets.

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 (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/channel.ts:42
Finding

Unrestricted Local File Disclosure Through Outbound Media Upload

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/cdn/upload.ts:30
Finding

Server-Side Request Forgery Through Unrestricted Remote Media Downloads

Content
View full analysis
{ logger.debug(`downloadRemoteImageToTemp: fetching url=${url}`); const res = await fetch(url); if (!res.ok) { const msg = `remote media download failed: ${res.status} ${res.statusText} url=${url}`; logger.error(`downloadRemoteImageToTemp: ${msg}`); throw new Error(msg); } const buf = Buffer.from(await res.arrayBuffer()); logger.debug(`downloadRemoteImageToTemp: downloaded ${buf.length} bytes`); await fs.mkdir(destDir, { recursive: true }); const ext = getExtensionFromContentTypeOrUrl(res.headers.get("content-type"), url); const name = tempFileName("weixin-remote", ext); const filePath = path.join(destDir, name); await fs.writeFile(filePath, buf); logger.debug(`downloadRemoteImageToTemp: saved to ${filePath} ext=${ext}`); return filePath; } ``` The function is reached through code such as: ```ts } else if (mediaUrl.startsWith("http://") || mediaUrl.startsWith("https://")) { logger.debug(`outbound: downloading remote mediaUrl=${mediaUrl.slice(0, 80)}...`); filePath = await downloadRemoteImageToTemp(mediaUrl, MEDIA_OUTBOUND_TEMP_DIR); logger.debug(`outbound: remote image downloaded to filePath=${filePath}`); } ``` ### Technical Analysis The plugin performs a server-side `fetch` against a media URL influenced by Agent output or message-tool input. It accepts both HTTP and HTTPS and does not validate the destination host or resolved IP address. There are no controls blocking: - Loopback destinations - RFC 1918 private networks - Link-local addresses - Cloud instance metadata services - IPv6 local and private ranges - Internal DNS nam ...[truncated 1543 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/log-upload.ts:91
Finding

Arbitrary File Exfiltration Through the Log Upload Command

Content
View full analysis
{ const uploadUrl = options.url ?? getConfiguredUploadUrl(config); if (!uploadUrl) { console.error( `[weixin] No upload URL specified. Pass --url or set it with:\n openclaw config set channels.openclaw-weixin.logUploadUrl `, ); process.exit(1); } const logDir = mainLogDir(); const rawFile = options.file ?? currentDayLogFileName(); const fileName = resolveLogFileName(rawFile); const filePath = path.isAbsolute(fileName) ? fileName : path.join(logDir, fileName); let content: Buffer; try { content = await fs.readFile(filePath); } catch (err) { console.error(`[weixin] Failed to read log file: ${filePath}\n ${String(err)}`); process.exit(1); } console.log(`[weixin] Uploading ${filePath} (${content.length} bytes) to ${uploadUrl} ...`); const formData = new FormData(); formData.append("file", new Blob([new Uint8Array(content)], { type: "text/plain" }), fileName); let res: Response; try { res = await fetch(uploadUrl, { method: "POST", body: formData }); ``` ### Technical Analysis The command is presented as a log uploader, but its `--file` option accepts arbitrary absolute paths. Relative paths are joined to the log directory without canonical containment validation, so traversal components may also escape the intended directory. Symbolic links are not checked. The `--url` option accepts an arbitrary destination without requiring HTTPS or restricting the endpoint to a trusted support service. The selected file is read in full and posted without redacting tokens, credentials, message content, personal data, or other sensitive information. Although the command requires local CLI invocation, copied troubleshooting ...[truncated 1422 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/auth/login-qr.ts:90
Finding

Weixin Bot Token Exposure in QR Login Debug Logs

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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
Findings (36)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

If the plugin actually performs log collection, remote upload, config deletion, uninstall execution, or maintenance utilities unrelated to the stated WeChat channel purpose, then the manifest materially understates risky behavior. Hidden or undocumented capabilities are dangerous because they can enable data exfiltration, destructive changes, or command execution under the cover of an innocuous messaging plugin.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

If the plugin actually performs log collection, remote upload, config deletion, uninstall execution, or maintenance utilities unrelated to the stated WeChat channel purpose, then the manifest materially understates risky behavior. Hidden or undocumented capabilities are dangerous because they can enable data exfiltration, destructive changes, or command execution under the cover of an innocuous messaging plugin.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: @mariozechner/pi-coding-agent==0.61.1 — 3 advisory(ies): CVE-2026-54326 (Pi Agent: Potential XSS in HTML session exports via Markdown URL sanitization by); CVE-2026-54328 (Pi Agent: Predictable temporary extension install paths allow local privilege es); CVE-2026-54327 (Pi Agent: Race condition in Pi auth.json writes could expose stored credentials)

High
Category
Supply Chain
Confidence
93% confidence
Finding

@mariozechner/pi-coding-agent 0.61.1 carries multiple advisories including XSS in HTML exports, predictable temporary extension paths, and credential exposure via auth.json write races. Although this package is a transitive devDependency through openclaw and not obviously required for the 微信 channel runtime, it is a genuine vulnerability set with meaningful local impact in developer or CI environments where the coding-agent features may execute and handle credentials or generated HTML.

Content

No source excerpt is available for this finding.

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · src/auth/accounts.ts (reported line 88)May include surrounding context.

ts
* Called after a successful QR login to ensure only the latest account remains
 * for a given WeChat user, preventing ambiguous contextToken matches.
 *
 * @param onClearContextTokens callback to clear context tokens for the removed account
 */
export function clearStaleAccountsForUserId(
  currentAccountId: string,

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 · src/auth/accounts.ts (reported line 131)May include surrounding context.

ts
}

/**
 * Legacy single-file token: `credentials/openclaw-weixin/credentials.json` (pre per-account files).
 */
function loadLegacyToken(): string | undefined {
  const legacyPath = path.join(resolveStateDir(), "credentials", "openclaw-weixin", "credentials.json");

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 · src/auth/accounts.ts (reported line 134)May include surrounding context.

ts
}

/**
 * Legacy single-file token: `credentials/openclaw-weixin/credentials.json` (pre per-account files).
 */
function loadLegacyToken(): string | undefined {
  const legacyPath = path.join(resolveStateDir(), "credentials", "openclaw-weixin", "credentials.json");

Context Leakage

High
Category
Data Exfiltration
Confidence
75% confidence
Finding

Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.

Content

Scanner excerpt · src/messaging/inbound.ts (reported line 259)May include surrounding context.

ts
return ctx;
}

/** Extract the context_token from an inbound WeixinMsgContext. */
export function getContextTokenFromMsgContext(ctx: WeixinMsgContext): string | undefined {
  return ctx.context_token;
}

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding

The README instructs users to execute a package via npx without pinning an exact version, which can cause installation or execution of whatever package version is current at the time. If the package is compromised, a malicious release is published, or a dependency-chain attack occurs, users may execute attacker-controlled code directly on their systems.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The README states that login credentials are saved locally automatically but gives no warning that these credentials are sensitive or guidance on how they are stored and protected. In a plugin handling WeChat account access, unclear credential handling increases the risk of token theft, accidental disclosure, insecure backups, or weak filesystem permissions leading to account compromise.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding

The README instructs users to execute an unpinned package directly via npx, which fetches and runs the latest published code at install time. This creates a supply-chain execution risk: if the package is compromised, replaced, or updated with malicious code, users may execute attacker-controlled code on their local system.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The README states that login credentials are automatically saved locally but does not warn users that these artifacts are sensitive, where they are stored, or how to protect or revoke them. Stored authorization material can be stolen from disk backups, shared machines, or malware, enabling unauthorized access to linked WeChat accounts.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The README documents API requests transmitting bearer tokens and user identifiers but does not explicitly require transport protections or warn that these values are sensitive authentication and identity data. In this plugin context, interception, logging, or misrouting of these headers could expose account access and user metadata to unauthorized parties.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill metadata declares installation and operational steps for a plugin that inherently needs network access and likely environment/config interaction, but it does not declare any explicit tool scope or permissions boundary. This is dangerous because users and automated platforms cannot accurately understand or constrain what the skill may access, increasing the risk of overprivileged execution and unsafe installation of a package with external connectivity.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill advertises QR-code login and message send/receive capability but does not provide a clear warning that authorization may grant ongoing access to WeChat communications and related account data. This is dangerous because users may authorize the plugin without understanding the persistence and privacy implications of connecting a messaging account.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The function persists token-bearing account data to per-account JSON files, which is a safety-relevant file write involving credentials. Although there is an internal comment and best-effort chmod, there is no confirmation prompt, user-visible log/print, or other disclosure in this file to inform the user that authentication data is being stored locally.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This function removes multiple on-disk files, including credentials and context-token state, which is a destructive local operation. The code has only comments and silent exception handling, with no user-facing disclosure, prompt, or visible log at the point of deletion.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The code prints and logs QR-code URLs obtained from an external service directly to stdout and logs. In a QR-login flow, that URL is effectively a bearer-like login artifact: anyone who can read terminal output, CI logs, remote console sessions, or centralized logging may be able to view or reuse the QR content and interfere with or hijack the login process before confirmation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This code presents user-facing login instructions entirely in Chinese, including status and QR-scan guidance, without offering a language choice. That is a natural-language locale policy issue because the skill forces a specific language for interactive workflow messages.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The skill manifest frames the plugin as a Weixin communication channel integration. Spawning a child process to invoke a plugin-management uninstall command is an administrative capability unrelated to receiving or replying to WeChat messages, and it expands the skill's operational power beyond its stated purpose.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The CLI implements arbitrary log exfiltration by reading a local file and POSTing it to a user-supplied or configuration-supplied URL. Even if framed as diagnostics, this creates a built-in data export path for potentially sensitive logs, and the feature is not tightly constrained to trusted destinations or explicit safe file scopes beyond the default log directory.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
91% confidence
Finding

The code persists per-user context_token values to disk in plaintext JSON under an account-derived filename so sessions survive restarts. If the state directory is readable by other local users, included in backups, or exposed via another file-read bug, an attacker could recover active tokens and potentially impersonate or hijack outbound messaging context for affected accounts.

Content

Scanner excerpt · src/messaging/inbound.ts (reported line 58)May include surrounding context.

ts
}

/**
 * Restore persisted context tokens for an account into the in-memory map.
 * Called once during gateway startAccount to survive restarts.
 */
export function restoreContextTokens(accountId: string): void {

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This TypeScript file contains multiple natural-language strings in Chinese for debug traces and user-visible error/debug messages, beginning at L101-L104 and continuing elsewhere in the file. Because the skill does not offer a language preference or document that it is intentionally limited to Chinese-speaking users, it violates the language/locale policy criterion.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The primary README is written in English and links to a Simplified Chinese version, but it does not explain language selection or locale expectations for users. Under the policy, forcing a specific language without explicit opt-in can be a natural-language policy concern unless the locale constraint is documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The natural-language content of the skill description and instructions is entirely in Chinese, with no indication that other languages are supported or that the locale restriction is intentional and required. Per policy, forcing a specific language without user opt-in can be a natural-language policy issue.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The manifest sets the channel to "openclaw-weixin", which implies a specific platform/locale selection in configuration text. Forcing a locale- or platform-specific context without any accompanying opt-in or justification can violate language/locale policy expectations.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.exposed_secret_literal

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
src/log-upload.ts:76

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
src/api/api.ts:83