Back to skill

Security audit

Direct WeChat Article Reader

Security checks for vulnerabilities and agentic risk

Overview

This skill is purpose-aligned for reading WeChat articles, but it can navigate a browser to arbitrary URLs and installs browser tooling at runtime without enough scoping or disclosure.

Install only if you are comfortable with the skill installing npm dependencies and Chromium, and only run it on trusted WeChat article links. It should ideally validate that inputs are exactly https://mp.weixin.qq.com URLs, block redirects to private or local networks, and move dependency/browser installation to an explicit reviewed setup step before broad use.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/extract.js:4
Finding

Unrestricted Browser Navigation Enables Server-Side Request Forgery

Content
View full analysis

Vulnerability Details

File Location: scripts/extract.js, lines 4–15
Vulnerability Type: Server-Side Request Forgery through insufficient URL validation
Risk Level: Medium

Vulnerable Code

javascript
const url = process.argv[2];
if (!url) {
  console.error('usage: node scripts/extract.js <mp.weixin.qq.com url>');
  process.exit(1);
}

const browser = await chromium.launch({ headless: false });
const page = await browser.newPage({
  userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36'
});

await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });

The shell entry point also forwards the argument without validation:

bash
URL="${1:-}"
if [[ -z "$URL" ]]; then
  echo "usage: $0 <mp.weixin.qq.com url>" >&2
  exit 1
fi

SKILL_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$SKILL_DIR"

if [[ ! -d node_modules/playwright ]]; then
  npm install >/dev/null 2>&1
fi

PLAYWRIGHT_BROWSERS_PATH="$HOME/.cache/ms-playwright"
export PLAYWRIGHT_BROWSERS_PATH

if [[ ! -x "$PLAYWRIGHT_BROWSERS_PATH/chromium-1217/chrome-linux64/chrome" ]]; then
  npx playwright install chromium >/dev/null 2>&1
fi

node scripts/extract.js "$URL"

Technical Analysis

Although the documentation describes the input as an mp.weixin.qq.com article URL, the implementation only verifies that an argument exists. It does not parse the URL or enforce its scheme, hostname, port, or resolved destination.

The untrusted value is supplied directly to Playwright's page.goto(). Chromium therefore initiates a request using the network privileges and reachability of the machine running the skill. The script subsequently extracts the destination's title and up to 20,000 characters of rendered body text and returns that content as JSON.

This creates a browser-based server-side request forgery primitive. A caller may direct the browser to loopback int ...[truncated 1659 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse input with the standard URL class and reject malformed values.
  2. Permit only the https: scheme.
  3. Require the normalized hostname to equal mp.weixin.qq.com; do not use substring or suffix checks that can accept deceptive domains.
  4. Reject embedded credentials, nonstandard ports, IP-literal hosts, and unsupported URL schemes.
  5. Intercept browser requests and reject navigation to loopback, private, link-local, multicast, and reserved address ranges.
  6. Resolve hostnames and verify all returned addresses before navigation, while accounting for DNS rebinding.
  7. Validate every redirect destination rather than checking only the initial URL.
  8. Restrict subresources if WeChat pages do not require unrestricted third-party requests.
  9. Apply outbound firewall or sandbox controls as defense in depth so the browser cannot reach internal or metadata networks.
  10. Return a clear validation error without navigating when the URL falls outside the approved scope.

A basic initial validation should include logic equivalent to:

javascript
function validateArticleUrl(value) {
  const parsed = new URL(value);

  if (parsed.protocol !== 'https:') {
    throw new Error('Only HTTPS URLs are permitted');
  }

  if (parsed.hostname !== 'mp.weixin.qq.com') {
    throw new Error('Only mp.weixin.qq.com URLs are permitted');
  }

  if (parsed.username || parsed.password || parsed.port) {
    throw new Error('Credentials and nonstandard ports are not permitted');
  }

  return parsed.href;
}

This application-level check should be combined with redirect validation and network-layer blocking because hostname validation alone does not fully address DNS rebinding or prohibited subresource requests.

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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `SKILL.md`

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly instructs the agent to run Playwright against user-supplied mp.weixin.qq.com URLs, but the markdown provides no warning that doing so causes automated outbound network access to third-party infrastructure and may expose client IP, browser fingerprinting data, or trigger external tracking and anti-bot controls. In a tool that is meant to be directly installed and executed, the lack of disclosure materially increases the risk of unintended external interaction and unsafe handling of untrusted URLs.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill performs npm install and then downloads a Chromium browser at runtime before reading article content. This expands the trust boundary from a simple content-reading task to arbitrary dependency installation and large binary retrieval, exposing users to supply-chain compromise, non-reproducible execution, and unexpected code execution paths. Given the stated purpose of merely extracting WeChat article text, the self-bootstrapping behavior is disproportionate and increases risk in routine operation.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
86% confidence
Finding

The script invokes npx playwright install chromium without pinning the Playwright package version at execution time. If the local dependency state is altered or an unexpected version is resolved, the skill may fetch and execute installer logic and browser artifacts that differ from what was reviewed, creating a supply-chain risk. In a skill that automatically bootstraps itself, this is more dangerous because the network fetch and execution happen implicitly during normal use.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding

The script invokes npx playwright install chromium without pinning the Playwright package version at execution time. If the local dependency graph changes or a different Playwright version is resolved, setup may fetch and run unexpected package code or incompatible browser installer logic, reducing build reproducibility and increasing supply-chain risk. In this skill context, the command is part of an executable setup path, so users are more exposed than with a purely instructional skill.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest description is written entirely in Chinese and presents the skill in a way that assumes Chinese-language interaction, without offering a language option or documenting a justified region-specific constraint. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest description is entirely in Chinese and presents the skill as directly installable/runnable in that language, with no indication of multilingual support or user opt-in for locale. This can violate language/locale policy when a skill implicitly assumes a specific language for all users.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

Using a caret range for the Playwright dependency allows future minor or patch releases to be installed automatically, which can change behavior or introduce a compromised upstream version through the supply chain. In a skill that executes browser automation code and installs Chromium, dependency drift increases the attack surface because runtime behavior depends on externally fetched package and browser artifacts.

Content

Scanner excerpt · package.json (reported line 12)May include surrounding context.

json
"install:browser": "playwright install chromium"
  },
  "dependencies": {
    "playwright": "^1.58.2"
  }
}

Static analysis

No suspicious patterns detected.