Back to skill

Security audit

Apifox Exporter

Security checks for vulnerabilities and agentic risk

Overview

The skill’s main purpose is legitimate, but it can automate an authenticated Apifox export with weak target selection and retained local artifacts that may expose the wrong or sensitive API data.

Review before installing. Use this only in an account where exporting all visible Apifox project data is acceptable, and clear the saved chrome-profile and debug screenshots after use. Avoid broad trigger phrases with untrusted text, verify the selected team/project before export, and avoid the fallback mode unless you explicitly place the intended Apifox JSON where the tool expects it.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
skill.yaml:41
Finding
Shell Command Injection Through Unquoted Trigger Parameters<![CDATA[ ## Vulnerability Details **File Location**: `skill.yaml`, lines 41–70 **Vulnerability Type**: Untrusted command argument interpolation **Risk Level**: High ### Vulnerable Code ```yaml - trigger: "更新接口文档,用 (.+)" description: "导出指定项目的接口文档(团队用默认)" action: "node script/auto-export-playwright.js --project=$1" - trigger: "更新接口文档,团队是 (.+),项目是 (.+)" description: "导出指定团队和项目的接口文档" action: "node script/auto-export-playwright.js --team=$1 --project=$2" - trigger: "更新接口文档 - (.+)" description: "导出指定项目的接口文档(简写)" action: "node script/auto-export-playwright.js --project=$1" - trigger: "更新接口文档 - (.+) - (.+)" description: "导出指定团队和项目的接口文档(简写)" action: "node script/auto-export-playwright.js --team=$1 --project=$2" ``` ### Technical Analysis The trigger expressions use unrestricted `(.+)` capture groups and interpolate the resulting values directly into command strings. The captured project and team names are neither quoted nor validated. If the skill runtime executes the `action` field through a command shell, an attacker can include shell metacharacters, command substitutions, redirections, or additional command separators in a trigger parameter. The shell would then interpret those characters as command syntax rather than as part of a project name. The JavaScript argument parser does not mitigate this issue because command injection would occur in the shell before Node.js receives `process.argv`. ### Attack Path 1. An attacker supplies a trigger containing shell syntax in the team or project capture. 2. The unrestricted regular expression captures the complete attacker-controlled value. 3. The runtime substitutes the value into the `action` command. 4. A shell interprets the injected metacharacters. 5. The injected command executes with the privileges and environment of the Agent process. Exploitability depends on whether the skill framework evaluates `action` through a shell. If it uses direct process execution with a structured argument ar ...[truncated 439 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace shell command strings with structured executable-and-argument declarations where supported. - Pass captured values as individual argument-array elements rather than concatenating them into a command. - Restrict team and project names to a conservative allowlist of expected Unicode letters, numbers, spaces, underscores, hyphens, and parentheses. - Reject shell metacharacters, control characters, newlines, redirection operators, and command-substitution syntax. - If shell execution cannot be avoided, use a platform-appropriate escaping library rather than implementing ad hoc quoting. - Add security tests using values containing `;`, `&&`, `|`, newlines, backticks, `$()`, quotes, and redirection operators. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
script/auto-export-playwright.js:172
Finding
Hard-Coded and Ambiguous Project Selection Can Export the Wrong Project<![CDATA[ ## Vulnerability Details **File Location**: `script/auto-export-playwright.js`, lines 172–206 **Vulnerability Type**: Incorrect authorization target selection **Risk Level**: High ### Vulnerable Code ```javascript // 可能的团队列表 const teams = ['媲美智能语音', 'shanghai', '个人团队']; let projectFound = false; for (const teamName of teams) { if (projectFound) break; console.log(`🔍 尝试团队:${teamName}`); try { // 点击团队(使用 XPath 更精确匹配) const teamLink = await page.$(`xpath=//div[contains(text(),"${teamName}")]|//span[contains(text(),"${teamName}")]`); if (teamLink) { await teamLink.click(); await sleep(3000); console.log(` ✅ 已切换到:${teamName}`); // 截图确认 await page.screenshot({ path: path.join(SCRIPT_DIR, `debug-team-${teamName.replace(/[^a-zA-Z0-9]/g, '-')}.png`), fullPage: true }); } // 查找项目(使用更宽松的选择器) // 项目卡片上可能显示简称,如"媲美科技 - 短剧(公司)"或"媲美科技 - 短剧" const keywords = ['媲美科技', '短剧', '公司']; for (const keyword of keywords) { const projectCard = await page.$(`text=${keyword}`); if (projectCard) { console.log(` ✅ 在团队"${teamName}"中找到项目(关键词:${keyword})!`); projectFound = true; // 点击项目卡片 await projectCard.click(); await sleep(3000); console.log('✅ 已进入项目'); await page.screenshot({ path: path.join(SCRIPT_DIR, 'debug-entered-project.png'), fullPage: true }); break; } } if (projectFound) break; } catch (e) { console.log(` ⚠️ 团队"${teamName}"中没有找到项目`); } } ``` ### Technical Analysis The script parses `APIFOX_TEAM_NAME` and `APIFOX_PROJECT_NAME` from command-line arguments, but its primary automatic selection logic does not use those values. Instead, it searches a fixed list of teams and broad hard-coded keywords. Selectors such as `text=公司` are not ...[truncated 1319 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Build the team selector exclusively from `APIFOX_TEAM_NAME`. - Require an exact, uniquely resolved match for `APIFOX_PROJECT_NAME`. - Avoid generic substring selectors such as `text=公司`. - Scope project searches to the selected team's project container. - After navigation, read a stable project identifier, URL component, or exact heading and compare it with the requested project. - Abort if no exact match exists or if multiple matches are returned. - Display the verified team and project immediately before export and require confirmation where ambiguity remains. - Add tests involving similarly named projects and projects sharing generic words. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
script/auto-export-playwright.js:153
Finding
Authenticated Full-Page Screenshots Are Persistently Stored Without Cleanup<![CDATA[ ## Vulnerability Details **File Location**: `script/auto-export-playwright.js`, lines 153–165, 188–205, and 249–250 **Vulnerability Type**: Persistent plaintext storage of sensitive interface data **Risk Level**: Medium ### Vulnerable Code ```javascript // 截图查看当前页面 await page.screenshot({ path: path.join(SCRIPT_DIR, 'debug-step4-team.png'), fullPage: true }); // 先展开"我的团队"下拉菜单 console.log('📁 展开"我的团队"...'); try { // 点击左侧边栏的"我的团队"下拉按钮 const myTeamBtn = await page.$('button:has-text("我的团队"), .team-switcher, [class*="team"]'); if (myTeamBtn) { await myTeamBtn.click(); await sleep(2000); console.log('✅ 已展开我的团队'); await page.screenshot({ path: path.join(SCRIPT_DIR, 'debug-my-team-expanded.png'), fullPage: true }); } } catch (e) { console.log('⚠️ "我的团队"可能已展开'); } ``` ```javascript await page.screenshot({ path: path.join( SCRIPT_DIR, `debug-team-${teamName.replace(/[^a-zA-Z0-9]/g, '-')}.png` ), fullPage: true }); ``` ```javascript await page.screenshot({ path: path.join(SCRIPT_DIR, 'debug-entered-project.png'), fullPage: true }); ``` ```javascript // 截图确认当前位置 console.log('📸 截取当前页面...'); await page.screenshot({ path: path.join(SCRIPT_DIR, 'debug-in-project.png'), fullPage: true }); ``` ### Technical Analysis The automation takes several full-page screenshots after authentication and writes them to the persistent workspace directory. These captures are unconditional, are not restricted to an explicit debug mode, and are not removed after the run. Full-page captures can contain team names, project names, account details, project metadata, API navigation information, and any other content rendered in the authenticated interface. The implementation does not explicitly set restrictive file permissions or redact sensitive regions. The documented runtime-output list mentions the browser profile, `source.json`, and the final text report, but does not identify t ...[truncated 768 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Disable screenshots during normal operation. - Require an explicit opt-in debug flag before creating diagnostic images. - Capture only the smallest necessary page region instead of using `fullPage: true`. - Redact account, team, project, token, and API-related interface regions. - Store temporary captures in a private directory with owner-only permissions. - Generate unpredictable temporary filenames to prevent collisions. - Delete diagnostic images in a `finally` block after the relevant troubleshooting period. - Document all retained artifacts and provide a cleanup command. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
script/auto-export.js:55
Finding
Fallback Export Processes the Newest Arbitrary JSON File in Downloads<![CDATA[ ## Vulnerability Details **File Location**: `script/auto-export.js`, lines 55–88 **Vulnerability Type**: Unvalidated local-file selection and unintended data copying **Risk Level**: Medium ### Vulnerable Code ```javascript const DOWNLOADS_DIR = path.join(USER_HOME, 'Downloads'); let latestJson = null; let latestTime = 0; if (fs.existsSync(DOWNLOADS_DIR)) { const files = fs.readdirSync(DOWNLOADS_DIR); for (const file of files) { if (file.endsWith('.json')) { const filePath = path.join(DOWNLOADS_DIR, file); const stat = fs.statSync(filePath); if (stat.mtimeMs > latestTime) { latestTime = stat.mtimeMs; latestJson = filePath; } } } } if (!latestJson) { console.error('❌ 未找到 JSON 文件'); console.log('💡 请先在 Apifox 中手动导出一次'); process.exit(1); } console.log(`✅ 找到文件:${latestJson}`); // 步骤 3: 移动到目标位置 console.log(''); console.log('📂 步骤 3: 移动文件到正确位置...'); const targetPath = path.join(SCRIPT_DIR, 'source.json'); fs.copyFileSync(latestJson, targetPath); console.log(`✅ 已复制到:${targetPath}`); ``` ### Technical Analysis The fallback script treats the most recently modified file ending in `.json` anywhere in the user's Downloads directory as the intended Apifox export. It does not verify the filename, download origin, OpenAPI version, required schema properties, creation time relative to the export operation, or user intent. Consequently, unrelated JSON data can be copied into the OpenClaw workspace. If that JSON also has compatible `paths` and schema-like fields, `export.js` may reproduce portions of it in the desktop report. Otherwise, processing may fail after the unintended copy has already occurred. ### Attack Path 1. An unrelated or sensitive JSON file becomes the newest JSON file in Downloads. 2. The user runs the fallback export mode. 3. The script selects that file solely by modification time and extension. 4. It copies the file to ...[truncated 701 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require the user to provide an explicit input-file path. - Prefer Playwright's download object or another trusted export event rather than scanning Downloads. - If fallback discovery is necessary, restrict candidates to an expected Apifox filename pattern and a narrow time window after export. - Parse the candidate before copying it and verify required OpenAPI properties, including a supported `openapi` version and an object-valued `paths` field. - Reject symbolic links and require a regular file. - Display the resolved source path and obtain confirmation before processing. - Delete an unintended or failed workspace copy instead of retaining it. ]]>

T08 · Insecure Dependencies

Note
Location
package.json:6
Finding
Dependency Installation Is Not Reproducibly Pinned<![CDATA[ ## Vulnerability Details **File Location**: `package.json`, lines 6–12 **Vulnerability Type**: Mutable third-party dependency resolution **Risk Level**: Low ### Vulnerable Code ```json "scripts": { "start": "node script/auto-export-playwright.js", "install-playwright": "npx playwright install chromium" }, "dependencies": { "playwright": "^1.40.0" } ``` The documented installation procedure also uses: ```bash npm install npx playwright install chromium ``` No package lockfile appears in the audited project structure. ### Technical Analysis The caret range permits npm to resolve any compatible Playwright release below the next major version. Without a committed lockfile, installations at different times may obtain different package versions and transitive dependency graphs. The browser installation command also downloads executable browser artifacts. The audit found no evidence that Playwright itself is malicious or that the project uses a typosquatted package; the risk is the lack of reproducibility and review continuity rather than a confirmed malicious dependency. ### Attack Path 1. A user installs the skill according to the documentation. 2. npm resolves the mutable version range using the registry state at installation time. 3. A dependency version or transitive dependency that was not part of this audit is installed. 4. Package installation logic and downloaded browser components execute or operate with the installing user's privileges. 5. If the upstream supply chain is compromised, the unreviewed artifact can affect the local environment. ### Impact Assessment A compromised or unexpectedly changed dependency could execute with the privileges of the user installing or running the skill and could access the skill workspace and local browser data available to that account. No active dependency compromise was established during this static audit. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Pin Playwright to an exact reviewed version. - Generate and commit `package-lock.json`. - Use `npm ci` in installation documentation and automated deployment. - Enable dependency integrity, provenance, and vulnerability checks in CI. - Review package lifecycle scripts before updates. - Pin and periodically review the associated Chromium revision. - Apply dependency updates through controlled pull requests that include lockfile diffs and security testing. ]]>
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (22)

Ae1

High
Category
analysis-evasion
Content
修改 `script/auto-export-playwright.js` 开头的默认配置:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
The README instructs users to run `npx playwright install chromium` without pinning a specific Playwright version. `npx` may resolve and execute whatever package version is available at install time, which weakens reproducibility and creates a supply-chain risk if an unexpected or compromised version is fetched.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The activation phrase `更新接口文档` is a common natural-language request meaning 'update API documentation,' which can easily overlap with ordinary user conversation. Overly broad triggers increase the chance of unintended skill activation, causing actions to run in contexts the user did not explicitly intend.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger phrases are very broad, including common requests like '更新接口文档' and '导出接口', which can overlap with normal user workflow language. That increases the chance of accidental invocation of a powerful browser automation skill that logs into Apifox, navigates projects, and exports potentially sensitive API data without the user explicitly intending to launch this capability.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill says login is 'automatically saved' but does not clearly warn that browser login state will be persistently stored locally in a reusable profile directory. In this context, persistent session artifacts for a cloud API/documentation platform may expose authenticated access to other local users, malware, backups, or later unintended automation runs.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
The installation instructions use `npx playwright install chromium` without pinning a specific package version, which can pull whatever version is current at execution time. In a skill context, this weakens supply-chain integrity and reproducibility because users may execute newer or compromised dependency code than the author originally tested.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding
The install script invokes `npx playwright` without pinning an exact package version, which allows resolution of whatever version is current in the registry or otherwise available in the environment at execution time. In a package intended to automate browser-based export tasks, this increases supply-chain risk and can lead to unexpected or vulnerable code being executed during installation.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The Playwright browser is launched with a persistent profile directory, causing authentication cookies and session state to be stored and silently reused across runs. In a script that automates access to an authenticated SaaS platform and exports potentially sensitive API documentation, this increases the risk of unintended account reuse, credential theft from local disk, and unauthorized exports by any process or user with access to that profile directory.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The script invokes a second local Node.js program through child_process.execSync, which expands its capability beyond browser automation into arbitrary local code execution. In this context, the called script path is fixed rather than user-controlled, so this is not immediate command injection, but it still creates a risky execution chain because any tampering with export.js or the workspace path would run with the user's privileges and can process sensitive exported API data.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The script enumerates the user's Downloads directory, selects the most recently modified JSON file, and copies it into a workspace location without explicit user confirmation or strong validation that the file is actually the intended Apifox export. This can unintentionally collect unrelated sensitive JSON data from Downloads and move it into another tool-controlled directory, which is a privacy and data-handling risk even if the apparent goal is convenience automation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
Console messages, filenames, and inline user instructions are written in Chinese throughout the script, effectively forcing a specific language for users. The file does not provide a language selection mechanism or document that the skill is intentionally region- or locale-specific.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script unconditionally writes the generated export to a predictable file on the user's Desktop. Because the content comes from API definitions and example payloads, it may include sensitive internal endpoints, headers, request bodies, or sample data, and placing it on the Desktop increases the chance of accidental exposure to other local users, screen sharing, backup/sync tools, or shoulder surfing.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger phrase "导出接口" is very generic and can plausibly appear in ordinary conversation or broader workflow requests, causing the skill to activate unexpectedly. Because activation launches a Node.js automation script that performs browser-driven export actions, accidental invocation could expose internal API documentation or cause unintended automation against the user's Apifox account.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The parameterized triggers use broad catch-all capture groups like (.+) for team and project names, with little structural constraint on what user utterances are considered valid matches. This increases the chance of unintended activation and ambiguous parameter extraction, which is risky here because the captured values are passed into command-line arguments for an automation script that accesses and exports project data.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
The user-facing documentation is entirely in Chinese and does not indicate that other languages are supported or that Chinese is optional. This can violate language/locale policy when a skill effectively requires a specific language without offering user choice or justification.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
The package description is written as a definitive Chinese-language skill description ('全自动从 Apifox 导出接口数据并整理成标准格式的文档') with no indication that language is selectable or that the skill is region-specific. Under the policy, forcing a specific language or locale without user opt-in can be a natural-language policy violation.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"install-playwright": "npx playwright install chromium"
  },
  "dependencies": {
    "playwright": "^1.40.0"
  },
  "keywords": [
    "apifox",
Confidence
86% confidence
Finding
Using a caret range for `playwright` permits automatic installation of newer minor/patch releases, which weakens reproducibility and can unintentionally pull in a compromised or incompatible version. In an automation tool that controls a browser and processes exported data, dependency drift raises supply-chain exposure even though the manifest does not itself contain direct malicious behavior.

Unverifiable Dependency: playwright has 1 known advisory(ies) (CVE-2025-59288 (Playwright downloads and installs browsers without verifying the authenticity of)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
74% confidence
Finding
The manifest depends on Playwright without an exact pin, while the package family has a cited advisory related to browser downloads lacking authenticity verification. Because this project explicitly installs Chromium via Playwright, the skill context makes the issue more relevant: installation may fetch external browser binaries, increasing exposure if an affected Playwright release is resolved.

Natural-Language Policy Violations

Low
Confidence
85% confidence
Finding
The script's comments, UI selectors, and default values are written for a Chinese-language Apifox environment, including fixed Chinese team and project names. There is no natural-language indication that the skill is limited to this locale or any option for users to opt into a different language/context.

Natural-Language Policy Violations

Low
Confidence
94% confidence
Finding
All visible console messages are in Chinese, and the file provides no option to select another language or indication that the skill is intended only for a Chinese-speaking audience. This can violate a language/locale policy when a skill imposes a specific language without user opt-in or documented justification.

Missing User Warnings

Low
Confidence
81% confidence
Finding
The script accesses HOME/USERPROFILE/HOMEPATH to derive workspace and output locations, which is access to sensitive environment-derived user path information. There is no docstring or upfront user warning explaining that the script will inspect environment variables to locate the user's workspace and Desktop.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The natural-language content in this skill, including description and command triggers, appears to require Chinese usage without offering an alternative language or an explicit locale-specific justification. That can violate language or locale policy when users are not given a choice or informed that the skill is region-specific.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
script/auto-export-playwright.js:364

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
script/auto-export.js:28