Back to skill

Security audit

fp-skill

Security checks for vulnerabilities and agentic risk

Overview

This invoice-checking skill needs Review because it handles sensitive invoice data with unsafe browser and file behaviors that are not clearly controlled by the user.

Install only after reviewing the code and running it in a tightly isolated, non-root environment. Do not use it with real invoices unless the file path, destination domain, certificate validation, screenshot handling, and upload confirmation behavior are fixed. Avoid running patch_fp.py because it rewrites an installed skill file and adds unverified URL fetching.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
skill.py:43
Finding
Automatic Bypass of Browser TLS Certificate Warnings<![CDATA[ ## Vulnerability Details **File Location**: `skill.py`, lines 43–68 **Vulnerability Type**: TLS certificate validation bypass **Risk Level**: High ### Vulnerable Code ```python # 告警页面处理 def handle_warning(driver): try: # 等待"高级"按钮出现并点击 driver.find_element(By.ID, "details-button").click() print("点击'高级'按钮成功") # 等待"继续访问"链接出现 time.sleep(1) # 点击"继续访问"链接 driver.find_element(By.ID, "proceed-link").click() print("点击'继续访问'链接成功") # 等待页面跳转 time.sleep(1) except Exception as e: print(f"处理安全警告时出错: {e}") # 备选方案:使用JavaScript点击 try: print("尝试使用JavaScript点击...") driver.execute_script("document.getElementById('details-button').click();") time.sleep(1) driver.execute_script("document.getElementById('proceed-link').click();") print("JavaScript点击成功") except Exception as js_error: print(f"JavaScript点击也失败了: {js_error}") ``` ### Technical Analysis The function explicitly interacts with Chrome's certificate-error page and selects the option to continue to the destination despite the TLS warning. It includes both normal DOM interactions and a JavaScript fallback, showing that bypassing the browser warning is intentional and resilient to ordinary interaction failures. The function is called after navigating to the invoice verification site and before uploading the invoice document. Consequently, the workflow may continue even when the remote endpoint cannot prove its identity through a valid certificate. TLS certificate validation is the control that prevents an active network attacker or incorrectly routed endpoint from impersonating the intended website. Automatically bypassing this control eliminates meaningful server authentication. ### Attack Path 1. An attacker gains a network interception position or manipulates DNS or routing for the invoice verification endpoint. 2. Th ...[truncated 1149 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove `handle_warning()` and all automated interactions with `details-button` and `proceed-link`. - Treat any certificate warning as a fatal verification failure. - Require the destination to use a valid certificate issued for the expected hostname. - Verify that the browser remains on the exact expected HTTPS origin before locating the upload field or transmitting an invoice. - Report certificate failures to the caller without retrying through an insecure path. - If a private certificate authority is legitimately required, install and manage that authority through the operating system or browser trust store rather than bypassing validation in application code. - Add an integration test confirming that invalid, expired, mismatched, and self-signed certificates stop the workflow before document upload. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
skill.py:153
Finding
Chrome Browser Sandbox Disabled During Remote Content Processing<![CDATA[ ## Vulnerability Details **File Location**: `skill.py`, lines 153–154 **Vulnerability Type**: Disabled browser process isolation **Risk Level**: Medium ### Vulnerable Code ```python chrome_options.add_argument('--no-sandbox') chrome_options.add_argument('--disable-gpu') ``` ### Technical Analysis The `--no-sandbox` argument disables an important Chrome security boundary. Chrome's sandbox normally limits the operating-system resources available to compromised renderer processes. The Skill processes content received from a remote website and interacts with an uploaded PDF while running Chrome in this reduced-security configuration. Disabling the sandbox does not itself execute arbitrary code. Exploitation requires a separate browser or renderer vulnerability. However, if such a vulnerability is triggered, the absence of sandboxing can substantially increase the attacker’s ability to affect the host process environment. ### Attack Path 1. The Skill opens the remote invoice verification website. 2. The legitimate site is compromised, or traffic is redirected to a malicious endpoint. 3. The endpoint delivers content crafted to exploit a vulnerability in the installed Chrome version. 4. Chrome processes the malicious content while started with `--no-sandbox`. 5. Successful browser exploitation may execute with the operating-system privileges of the account running the Skill rather than remaining confined to a renderer sandbox. 6. The attacker may access files, environment data, and network resources available to that account, subject to other host controls. ### Impact Assessment The potential scope is the operating-system account under which the Skill and browser execute. Depending on that account's permissions, successful exploitation could expose local files, invoice documents, environment variables, browser-session information, and reachable network services. This setting does not by itself grant root privileges. The resulting privilege level ...[truncated 192 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the `--no-sandbox` Chrome argument. - Run Chrome under a dedicated, unprivileged operating-system account. - If the Skill operates in a container, configure the container and kernel features so Chrome's sandbox can remain enabled. - Apply additional containment through a read-only filesystem, minimal mounted directories, restricted Linux capabilities, seccomp, and constrained outbound networking. - Keep Chrome and its driver updated through a controlled and tested release process. - Do not run this workflow as `root`. - Add a startup check that fails securely if Chrome cannot launch with its sandbox enabled. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
patch_fp.py:3
Finding
Patch Introduces Unverified Remote Image Retrieval and Rewrites an External Skill File<![CDATA[ ## Vulnerability Details **File Location**: `patch_fp.py`, lines 3–34 **Vulnerability Type**: Unverified network retrieval and unsafe fixed-path file modification **Risk Level**: High ### Vulnerable Code ```python with open('/root/.openclaw/workspace/skills/fp-skill/skill.py', 'r', encoding='utf-8') as f: content = f.read() old_func = '''# 将 base64 字符串转换成图片 def base64_to_image(base64_str): base64_data = re.sub('^data:image/.+;base64,', '', base64_str) byte_data = base64.b64decode(base64_data) image_data = BytesIO(byte_data) img = Image.open(image_data) img = img.convert("RGB") return img''' new_func = '''# 将 base64 字符串或 URL 转换成图片 def base64_to_image(base64_str): # 如果是 URL,下载图片 if base64_str.startswith('http'): print(f"从 URL 下载验证码图片...") response = requests.get(base64_str, timeout=10, verify=False) byte_data = response.content else: # 是 base64 字符串 base64_data = re.sub('^data:image/.+;base64,', '', base64_str) byte_data = base64.b64decode(base64_data) image_data = BytesIO(byte_data) img = Image.open(image_data) img = img.convert("RGB") return img''' content = content.replace(old_func, new_func) with open('/root/.openclaw/workspace/skills/fp-skill/skill.py', 'w', encoding='utf-8') as f: f.write(content) ``` ### Technical Analysis The patch replaces the local Base64-only decoder with code that accepts any string beginning with `http` and passes it to `requests.get()`. The request uses `verify=False`, disabling TLS certificate validation. There is no destination allowlist, scheme restriction to HTTPS, redirect policy, private-address rejection, response-size limit, content-type validation, or HTTP status validation. If the CAPTCHA source attribute can be influenced, the patched code can make server-side requests to attacker-selected or internal addresses. This creates a server-side request forgery exposure in environments where the Skill ca ...[truncated 2279 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove `patch_fp.py` and incorporate reviewed changes directly into the maintained source tree. - Do not overwrite fixed files outside the project. If a migration tool is necessary, require an explicit path, resolve it canonically, verify it remains inside an approved root, create a backup, and require user confirmation. - Prefer handling only Base64 data URLs for CAPTCHA images. - If remote image retrieval is required: - Permit only `https`. - Allowlist the exact expected hostname and port. - Keep certificate verification enabled. - Resolve the destination and reject loopback, private, link-local, multicast, and reserved addresses. - Disable redirects or validate every redirect destination. - Set connection and read timeouts. - Stream the response and enforce a small maximum size. - Require a successful HTTP status and an expected image content type. - Validate the decoded image dimensions before OCR processing. - Import and pin `requests` explicitly if it remains necessary. - Run image decoding in a constrained process and keep Pillow updated. - Add tests covering malicious URLs, redirects to private addresses, oversized bodies, invalid certificates, and non-image responses. ]]>

T08 · Insecure Dependencies

Warning
Location
requirements.txt:4
Finding
Contradictory, Duplicated, and Loosely Pinned Third-Party Dependencies<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt`, lines 4–9; installation instruction in `README.md`, lines 5–8 **Vulnerability Type**: Uncontrolled and non-reproducible dependency installation **Risk Level**: Medium ### Vulnerable Code ```text numpy~=2.0.2 numpy~=1.26.4 Pillow>=9.5.0 selenium~=4.36.0 webdriver_manager>=4.0.0 opencv-python-headless==4.8.1.78 ``` The OpenCV dependency is also duplicated in the complete file: ```text opencv-python-headless==4.8.1.78 ... opencv-python-headless==4.8.1.78 ``` The documented installation command is: ```bash pip install -r requirements.txt ``` ### Technical Analysis The two NumPy compatible-release constraints are mutually incompatible: `numpy~=2.0.2` requires a 2.0-compatible release, while `numpy~=1.26.4` requires a 1.26-compatible release. This can cause dependency resolution failure. `Pillow>=9.5.0` and `webdriver_manager>=4.0.0` have no upper bound, while compatible-release constraints still permit later patch or minor releases within their allowed ranges. As a result, future installations may retrieve code that was not part of the audited dependency set. Python package installation can execute package build and installation logic with the privileges of the invoking user. The duplicate OpenCV declaration creates maintenance ambiguity. Additionally, `webdriver_manager` is imported but the executed setup uses a hard-coded `Service` path instead of `ChromeDriverManager`, unnecessarily increasing dependency and supply-chain surface. No malicious dependency is proven in the audited file. The vulnerability is the absence of a reproducible, internally consistent, hash-verified dependency policy. ### Attack Path 1. A user follows the README and invokes `pip install -r requirements.txt`. 2. Pip contacts the configured package index and resolves packages allowed by the mutable version ranges. 3. Installation may fail because of contradictory NumPy requirements, encouraging ad hoc const ...[truncated 981 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Select one tested NumPy version compatible with OpenCV, ONNX Runtime, OCR, and the supported Python version. - Remove the duplicate OpenCV entry. - Remove `webdriver_manager` and its import if the project continues to use a managed local ChromeDriver path. - Pin every direct and transitive dependency to an exact reviewed version. - Generate a lock file containing hashes for all approved artifacts. - Install with hash verification, for example through a lock workflow that supports `pip install --require-hashes`. - Use a trusted, explicitly configured package index and avoid fallback to untrusted indexes. - Install in an isolated virtual environment or minimally privileged container rather than as `root`. - Add automated dependency compatibility, vulnerability, and license checks. - Regenerate and review the lock file through a controlled update process rather than permitting versions to change during ordinary installation. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (18)

Missing User Warnings

High
Confidence
99% confidence
Finding
Automatically bypassing the browser's security warning removes the user's opportunity to evaluate a potentially unsafe or spoofed destination and causes the automation to continue despite a failed trust check. In this skill, that is especially dangerous because the workflow then uploads a local file and interacts with the remote site, compounding the risk of data disclosure to an untrusted endpoint.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The README content is presented in Chinese and does not offer an alternative language or state that the language is region-specific by design. This can violate language or locale policy when users are not given a choice or informed of the constraint.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The skill description invites activation from a very broad natural-language request such as asking to verify an invoice, without clearly constraining when the skill should run or what confirmations are required. Broad triggers can cause unintended invocation on ambiguous user input, leading the agent to collect and transmit invoice data to an external site without sufficient user awareness or scope control.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The description says the skill will access the national VAT invoice platform to verify invoices, but it does not warn users that invoice details will be sent to an external government-operated website. This omission can cause unintentional disclosure of sensitive financial or business data and prevents informed consent before transmission.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The patch description and surrounding comments frame the change as adding image input support, but the actual code also introduces outbound network access by fetching arbitrary URLs. This is security-relevant because it silently expands the trust boundary and can enable SSRF-style behavior, unexpected data exfiltration paths, or access to internal resources if the modified skill later processes attacker-controlled input.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
# 如果是 URL,下载图片
    if base64_str.startswith('http'):
        print(f"从 URL 下载验证码图片...")
        response = requests.get(base64_str, timeout=10, verify=False)
        byte_data = response.content
    else:
        # 是 base64 字符串
Confidence
99% confidence
Finding
Using requests.get(..., verify=False) disables TLS certificate validation, allowing man-in-the-middle interception and tampering of downloaded image data. Because this patch introduces remote fetching into a skill workflow, an attacker on the network path could substitute malicious or unexpected content, defeat HTTPS protections, and potentially influence downstream image processing.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The script overwrites another skill file at `/root/.openclaw/workspace/skills/fp-skill/skill.py` using write mode, which is a potentially impactful file operation. There is no confirmation prompt or prior user-facing warning before the write occurs; the only message is a success print after the modification is complete.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill automatically uploads a hardcoded local PDF to a remote government website without any user-facing notice, consent, or validation of what file is being sent. In an agent or shared environment, this creates a data exfiltration risk because local workspace files may contain sensitive invoice or business information and are transmitted off-host automatically.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The function explicitly clicks through the browser's TLS/security interstitial by activating the 'details-button' and 'proceed-link', and even falls back to JavaScript to force the bypass. This defeats an important browser trust boundary and can expose uploaded documents and session data to man-in-the-middle attacks or malicious endpoints if the certificate warning is legitimate.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The code saves a full-page screenshot to a persistent local path during processing without disclosure or access controls. Screenshots can capture sensitive invoice details, verification results, and other page content, creating residual data exposure on disk even after the browser session ends.

Missing User Warnings

Low
Confidence
86% confidence
Finding
The README explicitly describes Selenium-based browser automation that can open pages, fill forms, click buttons, and take screenshots, but it gives no warning about interacting with third-party sites, submitting data, or triggering unintended actions. In documentation for an automation skill, that omission can lead users to run actions against external websites without understanding the consequences, increasing the chance of accidental data disclosure or unauthorized interactions.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
All user-facing text in this skill file is presented in Chinese, and the file does not state that the skill is China-specific or that language selection is optional. This can amount to a language or locale policy issue because the skill appears to force a specific language without explicit user opt-in or justification.

Unverifiable Dependency: numpy has 16 known advisory(ies) (CVE-2014-1859 (Numpy arbitrary file write via symlink attack); CVE-2021-41495 (NumPy NULL Pointer Dereference); CVE-2021-33430 (NumPy Buffer Overflow (Disputed)) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
91% confidence
Finding
The requirement `numpy~=2.0.2` is only partially pinned, so the exact installed release is not fixed and may vary within the allowed range. Because NumPy has historical advisories, the lack of an exact version prevents reliable verification that the resolved package is outside affected versions.

Unverifiable Dependency: numpy has 16 known advisory(ies) (CVE-2014-1859 (Numpy arbitrary file write via symlink attack); CVE-2021-41495 (NumPy NULL Pointer Dereference); CVE-2021-33430 (NumPy Buffer Overflow (Disputed)) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
99% confidence
Finding
The file declares NumPy twice with incompatible version constraints: `numpy~=2.0.2` and `numpy~=1.26.4`. This creates ambiguity or installation failure, and if resolution succeeds through manual modification or tool-specific behavior, security review becomes unreliable because the actual installed version is unclear despite multiple known NumPy advisories existing historically.

Unpinned Dependencies

Low
Category
Supply Chain
Content
onnxruntime==1.15.1
numpy~=2.0.2
numpy~=1.26.4
Pillow>=9.5.0
selenium~=4.36.0
webdriver_manager>=4.0.0
opencv-python-headless==4.8.1.78
Confidence
95% confidence
Finding
The dependency specification `Pillow>=9.5.0` is not strictly pinned, so builds may resolve to different versions over time, including versions later found vulnerable or incompatible. In a supply-chain context this weakens reproducibility and makes it harder to verify whether deployed environments are affected by known Pillow issues.

Unverifiable Dependency: Pillow has 16 known advisory(ies) (CVE-2016-2533 (Pillow buffer overflow in ImagingPcdDecode); CVE-2023-50447 (Arbitrary Code Execution in Pillow); CVE-2021-27922 (Pillow Uncontrolled Resource Consumption) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
95% confidence
Finding
Because `Pillow>=9.5.0` is open-ended, the exact Pillow release cannot be verified against known advisories. Given Pillow processes image data and has had memory-safety and resource-consumption issues, leaving the version unconstrained increases uncertainty about whether vulnerable builds may be installed.

Unverifiable Dependency: selenium has 2 known advisory(ies) (CVE-2022-28108 (Selenium Server (Grid) before 4 allows CSRF because it permits non-JSON content ); CVE-2023-5590 (NULL Pointer Dereference in GitHub repository seleniumhq/selenium prior to 4.14.)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding
`selenium~=4.36.0` permits multiple patch-level releases, so the concrete installed version is not directly auditable from this manifest alone. Since Selenium interacts with browser automation infrastructure and has known historical advisories, exact versioning is preferable for reproducibility and assurance.

Unpinned Dependencies

Low
Category
Supply Chain
Content
numpy~=1.26.4
Pillow>=9.5.0
selenium~=4.36.0
webdriver_manager>=4.0.0
opencv-python-headless==4.8.1.78
Confidence
94% confidence
Finding
`webdriver_manager>=4.0.0` allows any newer release to be installed, which introduces supply-chain and reproducibility risk because future versions may change behavior or contain malicious or vulnerable code. This is especially relevant for browser automation tooling that downloads and manages external driver binaries.

Static analysis

No suspicious patterns detected.