Back to skill

Security audit

多个微信公众号文章同步和下载

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its WeChat article-sync purpose, but it handles WeChat login secrets in ways that can expose them through diagnostics, local storage, and user-configured gateway relays.

Install only if you are comfortable giving this skill access to a WeChat MP login session and local persistent storage. Avoid configuring third-party gateway/proxy URLs for authenticated sync, do not paste doctor or login-info JSON into shared logs, keep the data directory private, and prefer disabling notifications or using a private trusted target for QR codes and sync status.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/mp_client.py:556
Finding

Authenticated WeChat credentials can be relayed to an arbitrary gateway

Content
View full analysis
dict[str, str]: headers = { "User-Agent": session.headers.get("User-Agent", DEFAULT_USER_AGENT), "Referer": session.headers.get("Referer", referer), "Origin": session.headers.get("Origin", "https://mp.weixin.qq.com"), "Accept-Encoding": session.headers.get("Accept-Encoding", "identity"), } cookie_header = requests.utils.dict_from_cookiejar(session.cookies) if cookie_header: headers["Cookie"] = "; ".join(f"{k}={v}" for k, v in cookie_header.items()) return headers def _build_gateway_url( self, target_url: str, *, proxy_base: str | None = None, headers: dict[str, str] | None = None, include_headers: bool = False, normalize_article: bool = False, preset: str = "", ) -> str: gateway_base = proxy_base or self._gateway_base_url() normalized_target = normalize_mp_article_short_url(target_url) if normalize_article else target_url separator = '&' if '?' in gateway_base else '?' gateway_url = f"{gateway_base}{separator}url={quote(normalized_target, safe=':/')}" if preset: gateway_url += f"&preset={quote(preset, safe='')}" if include_headers and headers: header_json = json.dumps(headers or {}, ensure_ascii=False) gateway_url += f"&headers={quote(header_json, safe='')}" return gateway_url ``` The authenticated synchronization request is constructed as follows: ```python def _request_sync_article_page(self, session: Session, params: dict[str, Any]) -> dict[str, Any]: endpoint = "https://mp.weixin.qq.com/cgi-bin/appmsgpublish" ...[truncated 3128 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/utils.py:127
Finding

Unrestricted article URLs permit server-side request forgery

Content
View full analysis
str: value = (url or "").strip() if not value: raise ValueError("缺少公众号文章链接") if not value.startswith(("http://", "https://")): value = f"https://{value}" return value def normalize_mp_article_short_url(url: str) -> str: value = normalize_mp_article_url(url) match = re.search(r"https?://mp\.weixin\.qq\.com/s/[^\s?#]+", value, re.IGNORECASE) if match: return match.group(0) return value ``` The normalized URL is subsequently requested with redirects enabled: ```python response = self.request( session, "GET", link, operation="article", allow_redirects=True, ) html = response.text ``` ### Technical Analysis The URL normalization function accepts any `http://` or `https://` URL. Although it attempts to extract a WeChat short URL when one appears in the input, it returns the original arbitrary URL when no such match exists. The article-fetching code then performs a server-side request to that URL and follows redirects. It does not restrict the hostname to expected WeChat domains, reject private or link-local addresses, resolve and validate DNS results, or revalidate redirect destinations. Consequently, a caller who can control the `--link` argument can direct the Skill to access services reachable from the Agent host. Because response content is processed as article HTML, partial response data or behavioral differences may also be exposed through success states, errors, processing results, or timing. The same general validation weakness applies to configured gateway URLs, which can also point to arbitrary destinations. ### Attack Path 1. An attacker supplies a crafted URL as the article link. 2. ...[truncated 980 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/login_service.py:452
Finding

Login and diagnostic commands expose complete session tokens

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/schema.py:12
Finding

WeChat session credentials are stored as plaintext in SQLite

Content
View full analysis
sqlite3.Connection: if self._connection is None: conn = sqlite3.connect(self.db_path) ``` The default location is under the user’s OpenClaw media directory: ```python return Path.home().joinpath(".openclaw", "media", "wechat-article-assistant").resolve() ``` ### Technical Analysis The login token, complete cookie JSON, and a prebuilt cookie header are persisted in plaintext. No encryption, operating-system credential store, or explicit owner-only file mode is applied by the shown database initialization. Storing both structured cookies and a cookie header also creates unnecessary duplicate copies of the same sensitive material. SQLite WAL and related sidecar files may produce additional plaintext copies during normal operation. The location under a media-oriented directory may also increase exposure to backup, synchronization, indexing, or support tooling. Security ultimately depends on ambient filesystem permissions rather than an explicit control implemented by the Skill. ### Attack Path 1. An attacker obtains local read access through another p ...[truncated 853 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (55)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The documented purpose centers on WeChat article sync and retrieval, but the skill also supports outbound notifications through external messaging and execution of an external CLI. This behavior expansion creates a trust gap: users may authorize article-processing actions without realizing metadata, failure details, or other content can be sent to third-party channels or routed via auxiliary tooling.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/dev/smoke_test.py (reported line 70)May include surrounding context.

python
command.extend(extra_args)
    command.append("--json")

    env = os.environ.copy()
    env["WECHAT_ARTICLE_ASSISTANT_HOME"] = str(home)
    completed = subprocess.run(command, capture_output=True, env=env)
    payload: dict[str, Any] | None = None

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill exposes capabilities implying shell, network, filesystem, and environment access, but the manifest does not declare any tool scope or allowed-tools restrictions. That omission weakens least-privilege controls and makes it harder for users or a runtime policy layer to understand and constrain what the skill may do.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill instructs saving article details and downloading images locally without warning users that content will be written to disk and retained. This can lead to unintentional storage of copyrighted, sensitive, or large-volume content in local workspaces where other tools or users may access it.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The proxy setup instructions encourage routing article-fetch and sync traffic through a configured proxy but do not warn that requests, cookies, article URLs, and related metadata may transit or be exposed to that proxy. In a login-backed workflow, this can materially increase credential, session, and privacy risk if the proxy is untrusted or misconfigured.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documentation describes Feishu/openclaw progress notifications that are outside the stated article-sync scope. Even if intended for convenience, this creates an undocumented exfiltration path for account names, sync status, and error details to external systems, increasing privacy and operational risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The sync notification feature sends progress and failure information to an external messaging channel without a clear disclosure that operational data will leave the local environment. Depending on message contents, this may reveal account identities, activity timing, sync volume, and internal error details to third parties.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The design explicitly supports sending login QR code flow data to a Telegram target, but the documentation shown does not mention user consent, privacy implications, transport sensitivity, or restrictions on what metadata may be transmitted. For a WeChat admin login workflow, QR/session-related data can expose account association, login timing, and potentially sensitive session bootstrap information to a third-party messaging platform, increasing the risk of account compromise or unintended disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation explicitly recommends routing article-fetch and sync requests through a third-party gateway by rewriting target URLs into /?url=https://mp.weixin.qq.com/..., but it does not warn that full request URLs, query parameters, metadata, and potentially authenticated traffic may be exposed to the gateway operator. In a skill that handles account login and article synchronization, this can leak browsing targets, session-correlated activity, and other sensitive operational data to an untrusted intermediary.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The cron guidance recommends background execution with --announce, which automatically posts synchronization results back to the current chat, but it does not warn that this creates ongoing background activity and can disclose article/account information into a chat context without fresh user confirmation each run. In a tool that syncs公众号 content and status, this can expose operational summaries, identifiers, or failure details to unintended chat participants or retained conversation logs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

This code fetches a public article over the network via client.fetch_public_article(normalized_url), which transmits the user-supplied URL and performs external network access. The file contains no nearby comment, docstring, print/log message to the user, or confirmation indicating that a network request will be made as part of resolving an account from a URL.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code performs a network call to fetch remote articles and may then write the returned data into the local database. While there is a debug log, there is no user-facing disclosure, confirmation, or explanatory comment/docstring warning that remote data will be retrieved and optionally persisted.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code downloads remote image binaries and writes them to local storage with local_path.write_bytes(binary). While there is debug logging, there is no clear user-facing warning or nearby documentation that the skill may download external content and persist files on disk, which can affect user data and storage.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The function performs an external network request to fetch article content via client.fetch_public_article(link). Although the module docstring mentions fetching and persistence, there is no user-facing confirmation, warning, or explicit disclosure in comments/docstrings near the operation about transmitting the provided link and contacting a remote service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

When save_files is enabled, the function writes article contents to JSON, Markdown, and optionally HTML files. The top-level docstring says persistence occurs, but there is no explicit user-facing warning or nearby explanation of what will be saved and where, despite this being a data-affecting file write operation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The code saves generated report markdown to disk for account reports, and the report content includes full article text and metadata. Although the module docstring mentions reports, there is no confirmation prompt, print/log statement, or inline warning near the write operation to disclose that potentially sensitive fetched content will be written to local files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This block writes a combined markdown report containing multiple accounts' article details and content to a local file. The function exposes a save_file toggle, but there is no visible disclosure, confirmation, or user-facing logging around the write to warn that aggregated content is being persisted.

Content

No source excerpt is available for this finding.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/cli_handlers.py (reported line 146)May include surrounding context.

python
if args.command == "login-clear":
            return login_clear(db)
        if args.command == "proxy-set":
            now = int(__import__("time").time())
            proxy_urls = parse_proxy_urls(getattr(args, "urls", []) or [])
            proxy_urls.extend(parse_proxy_urls(getattr(args, "url", "")))
            db.execute(

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The doctor command returns sensitive session metadata including token values, nickname, head image URL, timestamps, and whether cookie headers are present. In a CLI/agent skill context, this data may be surfaced to users, logs, upstream orchestrators, or other integrations, increasing the risk of credential leakage and account takeover if the output is exposed.

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/dev/smoke_test.py (reported line 72)May include surrounding context.

python
env = os.environ.copy()
    env["WECHAT_ARTICLE_ASSISTANT_HOME"] = str(home)
    completed = subprocess.run(command, capture_output=True, env=env)
    payload: dict[str, Any] | None = None
    stdout = decode_output(completed.stdout)
    stderr = decode_output(completed.stderr)

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/env_check.py (reported line 44)May include surrounding context.

python
"path": path or "",
        }
        if path:
            proc = subprocess.run([cmd, "--version"], capture_output=True, text=True, check=False)
            entry["ok"] = proc.returncode == 0
            entry["version"] = (proc.stdout or proc.stderr).strip()
        else:

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/env_check.py (reported line 55)May include surrounding context.

python
def _pip_show_version(package_name: str) -> str:
    proc = subprocess.run(
        [sys.executable, "-m", "pip", "show", package_name],
        capture_output=True,
        text=True,

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/env_check.py (reported line 143)May include surrounding context.

python
"path": path or "",
    }
    if path:
        proc = subprocess.run(["openclaw", "--help"], capture_output=True, text=True, check=False)
        data["ok"] = proc.returncode == 0
    else:
        data["ok"] = False

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Creating directories and a database file without clear user disclosure weakens transparency and safe operation, especially for a tool that may be run automatically by agents. In this skill context, silent writes are more concerning because the assistant is designed to fetch, sync, and export content, so users may reasonably expect a check action to be non-mutating.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file emits user-facing messages such as "python/python3 均不可用" and "Skill 环境检查完成" only in Chinese. This imposes a specific language on users without offering locale selection or documenting a justified region-specific restriction.

Content

No source excerpt is available for this finding.