Back to skill

Security audit

Baoyu Post To Weibo

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but it uses an authenticated browser, clipboard automation, process control, and an unpinned runtime download path that users should review before installing.

Review this skill before installing. Use a locally installed trusted Bun runtime instead of the npx fallback, run it with an isolated Chrome profile, and verify all content in the browser before publishing. Be cautious on shared machines because it uses the system clipboard, real paste keystrokes, authenticated Weibo session state, and a predictable temporary article file.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/weibo-utils.ts:118
Finding
Unpinned Runtime Package Is Downloaded and Executed Automatically<![CDATA[ ## Vulnerability Details **File Location**: `scripts/weibo-utils.ts:118-120`; related execution instructions at `SKILL.md:21-26` **Vulnerability Type**: Untrusted remote package retrieval and execution **Risk Level**: High ### Vulnerable Code ```ts function runBunScript(scriptPath: string, args: string[]): boolean { const result = spawnSync('npx', ['-y', 'bun', scriptPath, ...args], { stdio: 'inherit' }); return result.status === 0; } ``` The Skill instructions explicitly authorize the same fallback: ```markdown **Agent Execution Instructions**: 1. Determine this SKILL.md file's directory path as `{baseDir}` 2. Script path = `{baseDir}/scripts/<script-name>.ts` 3. Replace all `{baseDir}` in this document with the actual path 4. Resolve `${BUN_X}` runtime: if `bun` installed → `bun`; if `npx` available → `npx -y bun`; else suggest installing bun ``` ### Technical Analysis The helper invokes `npx -y bun` rather than a locally verified Bun executable. If the package is absent from the local npm cache, `npx` may retrieve it from the configured package registry and execute it automatically. The `-y` option suppresses the interactive installation prompt. No exact package version, package integrity value, trusted registry configuration, or executable checksum is specified at this execution point. Consequently, the effective executable can change after the Skill has been audited. This creates a remote code execution channel dependent on mutable registry content and local npm configuration. Although `bun.lock` pins the project libraries, it does not pin or verify the `bun` package downloaded by this `npx` invocation. ### Attack Path 1. A user invokes the Skill on a system where a trusted local `bun` executable is unavailable. 2. The Skill follows its documented fallback or calls a clipboard helper through `runBunScript`. 3. `npx -y bun` resolves the package using the user's configured npm registry. 4. A compromised registry, compromised package pu ...[truncated 879 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the automatic `npx -y bun` fallback from normal execution. 2. Require a locally installed Bun executable and fail with explicit installation instructions when it is unavailable. 3. Resolve the executable through a trusted absolute path rather than relying solely on `PATH`. 4. If automatic retrieval is unavoidable: - Pin an exact audited version, such as `bun@<exact-version>`. - Restrict downloads to an explicitly trusted registry. - Verify the downloaded artifact against a maintained cryptographic checksum or signature. - Do not use `-y`; require informed user confirmation before downloading executable code. 5. Invoke local helper scripts through the already running Bun process where possible instead of launching `npx` for every clipboard operation. 6. Update `SKILL.md` so its execution instructions do not direct agents to retrieve and run an unpinned package. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/paste-from-clipboard.ts:58
Finding
AppleScript Injection Through the macOS Target Application Argument<![CDATA[ ## Vulnerability Details **File Location**: `scripts/paste-from-clipboard.ts:58-79`; attacker-controlled input is accepted at `scripts/paste-from-clipboard.ts:156-174` **Vulnerability Type**: Command injection through dynamically generated AppleScript **Risk Level**: High ### Vulnerable Code ```ts function pasteMac(retries: number, delayMs: number, targetApp?: string): boolean { for (let i = 0; i < retries; i++) { // Build script that activates app (if specified) and sends keystroke in one atomic operation const script = targetApp ? ` tell application "${targetApp}" activate end tell delay 0.3 tell application "System Events" keystroke "v" using command down end tell ` : ` tell application "System Events" keystroke "v" using command down end tell `; const result = spawnSync('osascript', ['-e', script], { stdio: 'pipe' }); ``` The value is taken directly from a command-line argument: ```ts let targetApp: string | undefined; for (let i = 0; i < args.length; i++) { const arg = args[i] ?? ''; if (arg === '--help' || arg === '-h') { printUsage(0); } if (arg === '--retries' && args[i + 1]) { retries = parseInt(args[++i]!, 10) || 3; } else if (arg === '--delay' && args[i + 1]) { delayMs = parseInt(args[++i]!, 10) || 500; } else if (arg === '--app' && args[i + 1]) { targetApp = args[++i]; } else if (arg.startsWith('-')) { ``` ### Technical Analysis The `--app` value is inserted directly into an AppleScript source string delimited by double quotes. The implementation does not escape quotation marks, backslashes, line breaks, or AppleScript syntax. Passing the generated source as an argument to `osascript` avoids shell metacharacter interpretation, but it does not prevent AppleScript-language injection. A crafted application name can terminate the intended string and insert additional AppleScript state ...[truncated 1584 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not interpolate an application name into AppleScript source. 2. Pass the value as a separate `osascript` argument and access it through an AppleScript `on run argv` handler. Treat it only as data. 3. Since the article workflow only requires Chrome, apply an explicit allowlist of accepted application identifiers or names, such as `Google Chrome`, `Chromium`, and other deliberately supported browsers. 4. Prefer stable application bundle identifiers over display names where possible. 5. Reject values containing control characters and enforce a conservative maximum length as defense in depth. 6. Add regression tests using quotation marks, backslashes, line breaks, and AppleScript keywords to confirm that inputs cannot alter program structure. 7. Consider removing the public `--app` option if arbitrary application selection is not required by the declared Skill functionality. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/weibo-article.ts:68
Finding
Predictable Shared Temporary File Permits Symlink Overwrite and Content Races<![CDATA[ ## Vulnerability Details **File Location**: `scripts/weibo-article.ts:68-70` **Vulnerability Type**: Insecure temporary-file creation **Risk Level**: Medium ### Vulnerable Code ```ts const htmlPath = path.join(os.tmpdir(), 'weibo-article-content.html'); await writeFile(htmlPath, parsed.html, 'utf-8'); console.log(`[weibo-article] HTML saved to: ${htmlPath}`); ``` The file is subsequently trusted and read back: ```ts const htmlContent = fs.readFileSync(htmlPath, 'utf-8'); ``` It is also passed to the clipboard helper: ```ts copyHtmlToClipboard(htmlPath); ``` ### Technical Analysis Every invocation uses the same predictable filename inside the operating system's shared temporary directory. The code neither creates a private per-run directory nor opens the file with exclusive-creation and no-follow protections. On systems where another local account or process can create entries in the temporary directory, an attacker can pre-create `weibo-article-content.html` as a symbolic link. Standard `writeFile` behavior follows an existing symbolic link, allowing the victim process to truncate and replace a different file writable by the victim. The fixed filename also creates a time-of-check/time-of-use race. Another process or concurrent Skill invocation can replace or overwrite the file after it is written but before it is read or copied to the clipboard. This can cause unintended content to be inserted into an authenticated Weibo article and can expose one concurrent invocation's generated article to another. The file is not deleted in the shown workflow, so generated article HTML may remain in the temporary directory after execution. ### Attack Path #### Symlink overwrite 1. A local attacker predicts the fixed path in the shared temporary directory. 2. The attacker creates that path as a symbolic link to another file writable by the victim. 3. The victim runs the article-composition script. 4. `writeFile` follows the symbolic link and truncates o ...[truncated 1186 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a unique private directory for each invocation with `fs.promises.mkdtemp`. 2. Write the HTML file inside that private directory using restrictive permissions, such as mode `0o600`. 3. Use exclusive creation (`O_CREAT | O_EXCL`) and, where supported, no-follow semantics to prevent symbolic-link traversal. 4. Retain the generated HTML in memory where possible instead of writing it to a shared filesystem path. 5. If a file is required by the clipboard integration, pass a file descriptor or a uniquely generated private path. 6. Remove the private temporary directory in a `finally` block so cleanup occurs on success and failure. 7. Ensure concurrent invocations never share a filename or directory. 8. Avoid logging the complete temporary path unless required for troubleshooting. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (34)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
If the skill only drafts content and requires manual publish, or lacks the claimed article/Markdown support, that is primarily a trust and correctness issue rather than direct code-execution risk. However, misleading capability claims can still cause users to grant broader trust or permissions than warranted.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
If the skill only drafts content and requires manual publish, or lacks the claimed article/Markdown support, that is primarily a trust and correctness issue rather than direct code-execution risk. However, misleading capability claims can still cause users to grant broader trust or permissions than warranted.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the skill only drafts content and requires manual publish, or lacks the claimed article/Markdown support, that is primarily a trust and correctness issue rather than direct code-execution risk. However, misleading capability claims can still cause users to grant broader trust or permissions than warranted.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The manifest states support for 'headline articles (头条文章) with Markdown input via Chrome CDP'. This file defines options only for text, images, and videos, navigates to the standard Weibo home composer, and contains no Markdown processing or article publishing flow, which is a direct mismatch with the claimed capability.

Lp3

Medium
Category
MCP Least Privilege
Confidence
79% confidence
Finding
The skill instructs use of external runtimes, environment-dependent path resolution, and local configuration discovery, but it does not declare any explicit tool scope or permissions boundaries. That makes the skill's execution capabilities under-specified, increasing the risk that an agent may invoke broader local environment access than the user expects.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
Using `npx -y bun` without a pinned version allows retrieval of whatever package version is current at execution time, creating a supply-chain and reproducibility risk. If the upstream package is compromised or changes behavior, the skill could execute unintended code on the host.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
**CRITICAL**: Never kill all Chrome processes (`pkill -f "Google Chrome"`). Only kill Chrome instances launched by CDP with the baoyu-skills profile directory. The user may have regular Chrome windows open.

**Important**: This should be done automatically -- when encountering this error, kill the CDP Chrome instances and retry the command without asking the user.

## Notes
Confidence
92% confidence
Finding
The instruction to automatically kill processes and retry without asking the user authorizes autonomous host-side actions beyond simple content composition. Unattended remediation steps can magnify mistakes, especially when they affect local applications and state outside the browser session.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill directs automatic termination of Chrome processes without user confirmation, even if narrowly scoped to CDP instances. Process-killing is a disruptive host action that can cause data loss, interrupt active workflows, or be misapplied if the match pattern is broader than intended.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/copy-to-clipboard.ts:59

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/paste-from-clipboard.ts:107

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/weibo-utils.ts:45