Back to skill

Security audit

Web to Excel

Security checks for vulnerabilities and agentic risk

Overview

This skill can perform web-to-Excel filling, but it uses automatic package installation, local browser-session access, and workbook mutation with insufficient scoping and confirmation.

Review before installing. Only use this with trusted URLs and non-sensitive browser sessions, keep a backup of the workbook, and avoid running it where missing dependencies would trigger automatic pip installs. A safer version would require explicit confirmation before browser access and saving, use pinned reviewed dependencies, isolate the browser context, verify the CDP client, and sanitize spreadsheet formula-like values.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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 (3)

T08 · Insecure Dependencies

Warning
Location
scripts/web_scraper.py:20
Finding

Unpinned Dependencies Are Installed Automatically at Runtime

Content
View full analysis

Vulnerability Details

File Location: scripts/web_scraper.py:20-23
Vulnerability Type: Supply-chain exposure through unpinned runtime package installation
Risk Level: Medium

python
# ── 自动安装依赖 ──────────────────────────────────────────────────────────
for pkg in ['websockets', 'openpyxl']:
    if importlib.util.find_spec(pkg) is None:
        subprocess.check_call([sys.executable, '-m', 'pip', 'install', pkg, '-q'])

The same insecure installation pattern is also presented as recommended behavior in SKILL.md:127-130.

Technical Analysis

When either dependency is unavailable, the script invokes pip and installs the package using only its unversioned package name. It does not use exact version constraints, integrity hashes, a lock file, a verified package source, or an isolated environment.

Consequently, the code installed during a future invocation may differ from the code that existed at audit time. The selected package and its transitive dependencies are determined by the active Python and pip configuration, including any configured package index or mirror. Python packages may execute code during installation or later when imported.

This finding does not establish that websockets or openpyxl is malicious. The vulnerability is the unrestricted and mutable supply-chain trust introduced by automatic installation.

Attack Path

  1. One of the required modules is absent from the Python environment.
  2. An attacker compromises a selected package release, one of its transitive dependencies, or a package index or mirror configured for pip.
  3. The user invokes web_scraper.py.
  4. The script silently executes python -m pip install for the unpinned package.
  5. The compromised package is installed and subsequently imported or otherwise executed.
  6. The malicious package code runs with the same operating-system identity and permissions as the invoking user or agent.

Impact Assessmen

...[truncated 444 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove automatic package installation from the runtime execution path.
  • Declare dependencies in a reviewed dependency manifest and lock them to exact versions.
  • Require cryptographic hashes for downloaded distributions, such as through a hash-locked requirements file.
  • Install dependencies during a separate, explicit setup stage in an isolated virtual environment.
  • Use an approved package index and restrict or disable untrusted pip configuration and fallback indexes.
  • Audit transitive dependencies and update them through a controlled review process.
  • If a dependency is missing at runtime, fail safely with setup instructions rather than silently downloading code.

T07 · Tool Hijacking and Spoofing

Warning
Location
scripts/web_scraper.py:164
Finding

Unverified Python Module Is Imported from a Mutable External Directory

Content
View full analysis

Vulnerability Details

File Location: scripts/web_scraper.py:164-167
Vulnerability Type: Python import-path hijacking
Risk Level: Medium

python
# ① 连接浏览器
sys.path.insert(0,
    os.path.expanduser('~/Library/Application Support/QClaw/openclaw/config/skills/browser-cdp/scripts'))
from cdp_client import CDPClient

The same external import procedure is also recommended in SKILL.md:132-134.

Technical Analysis

The script inserts a directory outside the audited project at index zero of sys.path, giving modules in that directory priority during Python import resolution. It then imports and executes cdp_client without validating the module's provenance, version, ownership, or integrity.

Because cdp_client.py is not included in the audited project, its effective behavior cannot be established from this repository. Any party or process able to write to the referenced directory can replace or create that module. Python executes top-level module code immediately during import, before CDPClient is instantiated.

This is a local tool-spoofing boundary: the script assumes that a module with the expected name is the legitimate CDP client solely because it resides at a hardcoded external path.

Attack Path

  1. An attacker obtains write access to the referenced browser-CDP scripts directory, directly or through another compromised process operating as the user.
  2. The attacker creates or replaces cdp_client.py with a module that exports a plausible CDPClient class and contains malicious top-level code.
  3. The user invokes web_scraper.py.
  4. The script places the attacker-controlled directory first in sys.path.
  5. Python resolves from cdp_client import CDPClient to the substituted module.
  6. The module's top-level code runs immediately with the Skill process's permissions.
  7. A spoofed client can additionally intercept target URLs, browser commands, tab metadata, and extracted page co ...[truncated 565 chars]
Remediation
View remediation

Remediation Suggestions

  • Do not prepend a mutable external directory to sys.path.
  • Package the CDP client as a reviewed, versioned dependency and import it through the normal package mechanism.
  • Pin the approved client version and verify its distribution with cryptographic hashes.
  • If a local module is unavoidable, resolve a fixed canonical path and verify its hash, owner, and permissions before loading it.
  • Ensure the module directory is not writable by untrusted users or unrelated processes.
  • Fail closed when the approved client is unavailable or fails integrity validation.
  • Run browser automation in a least-privileged environment with access limited to the required browser profile and files.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/web_scraper.py:89
Finding

Untrusted Webpage Values Can Be Written as Spreadsheet Formulas

Content
View full analysis

Vulnerability Details

File Location: scripts/web_scraper.py:89-96, 121-134
Vulnerability Type: Spreadsheet formula injection
Risk Level: Medium

python
def clean_val(v) -> any:
    """Clean a value by removing currency symbols, commas, and spaces."""
    if v is None: return None
    s = str(v).strip().replace('¥', '').replace(',', '').replace(' ', '')
    if s in ('-', '暂无报价', '', 'None', '—'): return None
    try: return float(s)
    except: return s.strip() or None
python
def write_row(sheet, row_num: int, field_data: dict,
              col_idx: int, field_map: dict) -> list:
    """Write data into the specified row and return the update list."""
    updates = []
    for web_field, excel_col in field_map.items():
        if web_field not in field_data: continue
        vals = field_data[web_field]
        if col_idx >= len(vals): continue
        val = clean_val(vals[col_idx])
        if val is None: continue
        col_num = col_to_num(excel_col)
        old = sheet.cell(row_num, col_num).value
        if old is None:
            sheet.cell(row_num, col_num).value = val
            ref_price = ''
            if '参考价' in field_data and col_idx < len(field_data['参考价']):
                ref_price = field_data['参考价'][col_idx]
            updates.append((row_num, excel_col, col_num, ref_price, None, val))
    return updates

Equivalent vulnerable write logic is included in SKILL.md:271-295.

Technical Analysis

Values extracted from the target webpage are considered numeric only if float accepts them. Every other nonempty value is returned as an unrestricted string and assigned directly to an openpyxl cell.

In particular, a string beginning with an equals sign is interpreted by openpyxl and spreadsheet applications as a formula rather than inert text. The code performs no formula-prefix detection, field-specific validation, allowlisting, or forced- ...[truncated 1627 chars]

Remediation
View remediation

Remediation Suggestions

  • Treat all values scraped from webpages as untrusted text.
  • Reject or neutralize strings beginning with spreadsheet formula indicators, including =, +, -, and @, before assigning them to cells.
  • Force textual fields to inert text, for example by prefixing an apostrophe where compatible, and set an explicit text number format.
  • Apply strict field-specific schemas: numeric fields should accept only validated numeric syntax and expected ranges, while textual fields should have length and character restrictions.
  • Do not attempt to preserve formulas from webpage content unless the user explicitly authorizes a reviewed formula.
  • Record rejected values in the output report so sanitization is visible to the user.
  • Add tests using formula payloads and verify that reopening the generated workbook does not classify sanitized content as a formula.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (13)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

描述将该技能表述为“从网页抓取结构化数据并填写到任意 Excel 文件的通用技能”,强调所有信息都由用户在使用时提供,且“不硬编码任何具体网址、文件名或字段映射”。但代码行为明显更窄、更具体:它通过本地 CDP 浏览器会话抓取页面 body.innerText,专门寻找“参考价”这一锚点并截取固定长度文本,再假定页面内容是制表符分隔的参数表。随后使用预置的 FIELD_MAP 将若干中文参数名写入固定 Excel 列位。这说明它并不是通用网页到 Excel 的映射引擎,而是偏向某类商品参数页(注释中也提到“摩托范网站字段”)的数据填充脚本。虽然支持用户传入 Excel 路径、Sheet、行范围和 URL,但核心字段映射与页面解析方式并不通用,且存在额外依赖(本地浏览器调试接口、固定 cdp_client 路径)未在描述中体现。因此描述与实际行为存在实质性不符。

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

Installing packages during execution is an unjustified capability for this skill and materially increases the attack surface. It allows unreviewed code retrieval and execution from package repositories at run time, which is especially dangerous in an agent skill context where users may expect only data extraction and spreadsheet updates, not system modification.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill embeds shell-capable Python code, including package installation via pip, but does not declare any tool scope or permissions. That makes the skill's effective capabilities broader and less transparent than its manifest suggests, increasing the risk of unexpected local execution and reducing opportunities for policy enforcement.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The invocation description says the skill should trigger for the listed phrases 'or any similar expression', which leaves the activation boundary undefined. In a manifest/markdown skill description, this kind of open-ended wording makes it unclear which requests should not invoke the skill and increases the chance of accidental activation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill directs immediate execution once fields are present, even though it will access a URL, attach to a browser, and modify a local Excel file. Skipping an explicit side-effect warning and confirmation increases the risk of unintentional file changes or data exposure, especially given the CDP/browser behavior in this skill.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill connects to a local CDP endpoint and enumerates/reuses existing browser tabs, granting visibility into and interaction with potentially unrelated browsing sessions. For a task that only needs one user-specified URL, this is over-privileged behavior that can expose sensitive page contents, cookies/session-bound data, or lead to unintended actions in other tabs.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Automatic dependency installation executes package-management operations on the host at runtime, which is broader than necessary for simple web-to-Excel transfer. This expands the attack surface to package supply-chain abuse, unexpected code execution during install, and environment drift on the user's machine.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring, argument descriptions, and usage guidance are entirely in Chinese, which imposes a specific language on users. The file does not provide an alternative language option or indicate that the locale restriction is intentional and justified.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
96% confidence
Finding

The script automatically executes pip install at runtime, which gives it network access and the ability to modify the local Python environment without an explicit user approval step. In a skill that is supposed to scrape a webpage and write to Excel, this is unnecessary privilege expansion and creates supply-chain and environment-tampering risk if package sources, indexes, or dependency resolution are compromised.

Content

Scanner excerpt · scripts/web_scraper.py (reported line 23)May include surrounding context.

python
# ── 自动安装依赖 ──────────────────────────────────────────────────────────
for pkg in ['websockets', 'openpyxl']:
    if importlib.util.find_spec(pkg) is None:
        subprocess.check_call([sys.executable, '-m', 'pip', 'install', pkg, '-q'])

# ── 通用字段映射(用户可在使用时追加/覆盖)──────────────────────────────────
# 用法:在调用本脚本前,在对话中确认映射关系,然后我来执行写入。

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest claims a generic skill that does not hardcode specific URLs, filenames, or field mappings, with all mappings supplied by the user at runtime. However, the script embeds a large predefined FIELD_MAP for specific motorcycle-related fields and later extracts page text by searching for the literal marker '参考价', indicating dependence on a particular site/content layout rather than a general-purpose scraper.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The manifest presents a general skill for scraping structured data from a provided URL and filling Excel, but the implementation only works by importing a local CDP client from a specific filesystem path and connecting to a browser debugging endpoint at 127.0.0.1:9334. This is a significant behavioral constraint not reflected in the skill description and makes the skill dependent on a particular local environment.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The document centers the workflow on 'standard Chinese' mappings and provides all prompts, confirmations, and interaction patterns only in Chinese, without stating that another language can be used. If organizational policy requires not forcing a specific language without opt-in, this creates a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

This markdown file contains user-facing natural-language instructions solely in Chinese, and there is no indication that the skill is region-specific or that users can opt into another language. Under the language/locale policy rule, forcing a specific language without opt-in is a policy concern.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.