Back to skill

Security audit

webpage-reader-skill

Security checks for vulnerabilities and agentic risk

Overview

This webpage-reading skill is mostly coherent, but it can make privileged system changes and fetch arbitrary URLs with an unsandboxed browser during normal use.

Review before installing. Use this only in an isolated environment with no access to sensitive internal networks, metadata endpoints, or local services, and do not run it with sudo-capable privileges. Preinstall Chrome manually through a trusted admin process rather than allowing the skill to install packages at runtime.

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

T09 · Insecure Skill Coding Practices

Error
Location
webpage_reader.py:124
Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `webpage_reader.py:124-135` **Vulnerability Type**: Server-Side Request Forgery through unrestricted browser navigation **Risk Level**: High ### Vulnerable Code ```python # Build the Chrome command chrome_cmd = [ 'google-chrome' if platform.system() != 'Windows' else 'chrome', '--headless=new', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', '--virtual-time-budget=8000', '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36', '--hide-scrollbars', '--blink-settings=imagesEnabled=true', '--dump-dom', url ] ``` The unvalidated value reaches this function from `main` at `webpage_reader.py:232`: ```python if not download_webpage(url, output_file): result['message'] = "Failed to download webpage" return result ``` ### Technical Analysis The caller-provided `url` is passed directly to headless Chrome without validation of its scheme, hostname, resolved IP address, destination port, or redirect targets. Using a subprocess argument array prevents direct shell metacharacter injection, but it does not prevent server-side request forgery. An attacker can request resources that are accessible from the machine running the skill but are not normally accessible to the attacker. Potential targets include: - Loopback services such as `127.0.0.1` and `::1` - Private network ranges - Link-local services - Cloud instance metadata endpoints - Internal administration interfaces - Services exposed only inside the host or container network Validating only the initial hostname would not be sufficient because an attacker-controlled server could redirect Chrome to an internal address. DNS rebinding could also undermine checks that do not bind navigation to a previously validated address. ### Attack Path 1. An attacker invokes the skill with a URL targeting an internal service, localhost reso ...[truncated 1277 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only explicitly supported schemes, normally `https` and, if necessary, `http`. 2. Reject URLs containing credentials, ambiguous host syntax, or unsupported ports. 3. Resolve the destination hostname before navigation and reject every address in loopback, private, link-local, multicast, unspecified, reserved, and other non-public ranges for both IPv4 and IPv6. 4. Explicitly block cloud metadata destinations and hostnames. 5. Validate every redirect destination using the same rules. Do not rely only on validation of the initial URL. 6. Mitigate DNS rebinding by ensuring navigation uses an approved resolution or by enforcing the policy through a controlled outbound proxy. 7. Prefer a strict hostname allowlist when the business use case permits it. 8. Enforce outbound firewall or container-network rules so the browser cannot reach internal networks or metadata services even if application validation is bypassed. 9. Apply response-size and navigation limits to reduce denial-of-service risk from attacker-controlled pages. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
webpage_reader.py:128
Finding
Headless Chrome Processes Untrusted Pages with Its Sandbox Disabled<![CDATA[ ## Vulnerability Details **File Location**: `webpage_reader.py:128-131` **Vulnerability Type**: Unsafe browser security configuration **Risk Level**: Medium ### Vulnerable Code ```python 'google-chrome' if platform.system() != 'Windows' else 'chrome', '--headless=new', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', ``` ### Technical Analysis The `--no-sandbox` option explicitly disables Chrome's process sandbox while the browser renders caller-selected remote webpages. The sandbox is a principal defense that limits the access obtained when malicious web content exploits a browser or rendering-engine vulnerability. Disabling it does not itself constitute arbitrary code execution. Exploitation requires a compatible browser vulnerability or another defect in the browser attack surface. However, if such a vulnerability is triggered, the absence of sandbox isolation can substantially reduce the number of protections an attacker must bypass. The risk is amplified because the skill accepts arbitrary remote URLs and therefore allows an attacker to select the page and content processed by Chrome. ### Attack Path 1. An attacker hosts or identifies a page designed to exploit a vulnerability in the installed Chrome version. 2. The attacker supplies that page's URL to the skill. 3. The skill launches Chrome with `--no-sandbox` and navigates to the attacker-selected page. 4. The malicious content triggers the applicable browser vulnerability. 5. Because browser sandboxing is disabled, exploit code may gain the permissions of the Chrome process without requiring a separate sandbox escape. 6. The attacker can then attempt to access files, processes, credentials, or network resources available to the skill's operating-system account. ### Impact Assessment Successful exploitation could permit code execution with the privileges of the account running the skill. This could expose readable files, environment data, internal network access, and writab ...[truncated 382 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `--no-sandbox` option and configure the environment so Chrome's native sandbox operates correctly. 2. Run Chrome and the skill under a dedicated, unprivileged operating-system account. 3. Isolate browser execution inside a hardened container or equivalent sandbox with: - A read-only root filesystem - Minimal mounted directories - No host socket mounts - Dropped Linux capabilities - `no-new-privileges` - Process, memory, and CPU limits - Restricted outbound networking 4. Keep Chrome automatically patched through a trusted administrative deployment process. 5. Do not run the skill or browser as root. 6. Use an ephemeral browser profile for each invocation and remove it after completion. 7. Consider adding an additional OS-level sandbox such as seccomp and mandatory access controls. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
webpage_reader.py:78
Finding
Normal Skill Execution Can Trigger Privileged System Package Installation<![CDATA[ ## Vulnerability Details **File Location**: `webpage_reader.py:78-101` **Vulnerability Type**: Runtime privilege escalation and unsafe host mutation **Risk Level**: Medium ### Vulnerable Code ```python elif system == 'Darwin': # macOS # macOS installation using Homebrew try: subprocess.run(['brew', 'install', 'google-chrome'], check=True) return True except subprocess.CalledProcessError: logger.error("Homebrew not found. Please install Homebrew first or manually install Chrome.") return False elif system == 'Linux': # Linux installation distro = platform.dist()[0].lower() if hasattr(platform, 'dist') else 'unknown' if 'ubuntu' in distro or 'debian' in distro: subprocess.run(['sudo', 'apt-get', 'update'], check=True) subprocess.run(['sudo', 'apt-get', 'install', '-y', 'google-chrome-stable'], check=True) return True elif 'fedora' in distro or 'centos' in distro or 'rhel' in distro: subprocess.run(['sudo', 'dnf', 'install', '-y', 'google-chrome-stable'], check=True) return True else: logger.error("Unsupported Linux distribution. Please manually install Chrome.") return False else: logger.error(f"Unsupported operating system: {system}") return False ``` The privileged operation is reached automatically from `webpage_reader.py:220-224`: ```python # Check if Chrome is installed if not check_chrome_installed(): logger.info("Chrome not found, attempting to install...") if not install_chrome(): result['message'] = "Chrome installation failed. Please install Chrome manually." return result ``` ### Technical Analysis Ordinary invocation of the webpage-reading function automatically enters an installation routine when Chrome detection fails. On supported Linux distributions, that routine invokes the system package manager through `sudo`. Package installation is an administrative provisioning operation ...[truncated 2016 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all package-installation behavior from the runtime execution path. 2. Treat Chrome as an administrator-provisioned prerequisite and return a clear error when it is unavailable. 3. Provide a separate, explicit installation procedure that administrators can review and execute outside the skill. 4. Never invoke `sudo`, Homebrew, `apt-get`, or `dnf` from a normal webpage-processing request. 5. Pin approved Chrome versions and obtain them only through organization-controlled, authenticated repositories. 6. Verify the browser executable path and version during startup without modifying the system. 7. Run the deployed skill under an account that has no sudo rights. 8. If automated provisioning is required, perform it in an image-build or deployment stage with package signature verification, version pinning, audit logs, and administrative approval. ]]>
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (18)

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The README states that Chrome may be installed automatically, but it does not clearly warn users that running the skill can modify the host system by installing software and invoking package managers. In an agent-skill context, undocumented system modification is security-relevant because users may grant execution assuming the skill is read-only, which can lead to unexpected package installation and trust-boundary violations.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The README explicitly advertises automatic Chrome installation and webpage downloading, which implies both system modification and outbound network access, but it does not clearly warn users about those behaviors before use. In a skill context, undisclosed package installation and network retrieval increase the risk of unexpected changes to the host and accidental use in restricted or sensitive environments.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill documentation describes downloading and analyzing webpages but does not clearly warn users that arbitrary external URLs will be contacted, causing network requests to be sent to third-party sites. In an agent/skill context, this can lead to unintended data disclosure, SSRF-like access to internal resources, or privacy risks if users provide sensitive or internal URLs without understanding the network impact.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The documentation notes that Chrome may be automatically installed, but it does not sufficiently emphasize that this changes the local system by installing software and potentially invoking package managers with elevated privileges. In an agent environment, automatic dependency installation increases supply-chain and system-integrity risk, especially if users do not expect software installation as part of normal skill execution.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The documentation claims the skill only downloads webpage content, but the implementation also installs Chrome and invokes system package managers. This mismatch is security-relevant because it conceals host-modifying behavior from reviewers and users, undermining informed consent and making dangerous side effects easier to smuggle into agent workflows.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return False
        else:
            # For macOS and Linux, use which command
            result = subprocess.run(
                ['which', 'google-chrome'] if platform.system() != 'Darwin' else ['which', 'chrome'],
                capture_output=True,
                text=True
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
elif system == 'Darwin':  # macOS
            # macOS installation using Homebrew
            try:
                subprocess.run(['brew', 'install', 'google-chrome'], check=True)
                return True
            except subprocess.CalledProcessError:
                logger.error("Homebrew not found. Please install Homebrew first or manually install Chrome.")
Confidence
88% confidence
Finding
This code performs software installation as a side effect of a webpage-reading skill, which exceeds the declared functionality and modifies the host environment. Even with fixed arguments, auto-installing software can introduce unreviewed system changes, supply-chain exposure, and unexpected privilege escalation paths depending on how the skill is executed.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
distro = platform.dist()[0].lower() if hasattr(platform, 'dist') else 'unknown'
            
            if 'ubuntu' in distro or 'debian' in distro:
                subprocess.run(['sudo', 'apt-get', 'update'], check=True)
                subprocess.run(['sudo', 'apt-get', 'install', '-y', 'google-chrome-stable'], check=True)
                return True
            elif 'fedora' in distro or 'centos' in distro or 'rhel' in distro:
Confidence
97% confidence
Finding
Running 'sudo apt-get update' from a content-processing skill causes privileged system modification without interactive confirmation or clear operator consent. In an agent context, this is dangerous because a simple request to read a webpage can unexpectedly trigger privileged package-manager activity and broaden the attack surface through repository trust and dependency changes.

Missing User Warnings

Medium
Confidence
99% confidence
Finding
Automatic package installation via sudo without explicit warning or approval is a genuine security issue in an agent skill. It can perform privileged changes on the host merely because a user asked to read a webpage, violating least surprise and enabling dangerous environment drift or abuse if the skill is invoked in sensitive systems.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if 'ubuntu' in distro or 'debian' in distro:
                subprocess.run(['sudo', 'apt-get', 'update'], check=True)
                subprocess.run(['sudo', 'apt-get', 'install', '-y', 'google-chrome-stable'], check=True)
                return True
            elif 'fedora' in distro or 'centos' in distro or 'rhel' in distro:
                subprocess.run(['sudo', 'dnf', 'install', '-y', 'google-chrome-stable'], check=True)
Confidence
98% confidence
Finding
This call attempts to install Chrome system-wide with sudo, which is a high-risk side effect for a webpage downloader. It can change the host state, pull packages from external repositories, and may execute with elevated privileges in environments where the agent already has broad access.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
subprocess.run(['sudo', 'apt-get', 'install', '-y', 'google-chrome-stable'], check=True)
                return True
            elif 'fedora' in distro or 'centos' in distro or 'rhel' in distro:
                subprocess.run(['sudo', 'dnf', 'install', '-y', 'google-chrome-stable'], check=True)
                return True
            else:
                logger.error("Unsupported Linux distribution. Please manually install Chrome.")
Confidence
97% confidence
Finding
This privileged package installation on RPM-based systems has the same risk profile as the apt-based path: unexpected host modification, supply-chain exposure, and possible privilege misuse. The danger is amplified because the skill's stated purpose does not justify package-manager execution.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
logger.info(f"Running Chrome command: {' '.join(chrome_cmd)}")
        
        # Execute the command and capture output
        result = subprocess.run(
            chrome_cmd,
            capture_output=True,
            text=True,
Confidence
93% confidence
Finding
This subprocess call launches a full headless browser against an attacker-controlled URL, which creates meaningful risk beyond a normal HTTP fetch. A remote page can trigger browser-level exploitation, internal network access/SSRF-like behavior from the host, and excessive resource consumption; the use of '--no-sandbox' materially increases the impact of any browser compromise.

Intent-Code Divergence

Medium
Confidence
92% confidence
Finding
The main function is described as webpage processing, but it can trigger system-wide dependency installation as part of normal execution. In an agent skill, this hidden side effect is dangerous because downstream orchestrators may treat it as a read-only capability when it actually performs administrative changes.

Natural-Language Policy Violations

Low
Confidence
78% confidence
Finding
文档内容全部以中文呈现,没有说明这是面向特定中文用户群体,也没有提供其他语言选项或用户可选择语言的提示。按照语言/locale政策,若强制单一语言且无明确限定或用户选择,可能构成自然语言策略问题。

Missing User Warnings

Low
Confidence
86% confidence
Finding
The README describes downloading and analyzing arbitrary webpages but does not clearly warn that the skill will make outbound network requests and retrieve remote content. In an agent environment, this can expose user IP, trigger access to sensitive/internal URLs if misused, and create privacy or SSRF-like risk if operators assume the skill is local-only.

Natural-Language Policy Violations

Low
Confidence
74% confidence
Finding
整个技能文档仅以中文呈现,未说明这是面向特定中文用户群的区域性技能,也未提供语言选择或英文替代。根据语言/区域政策,若技能对语言有实际约束,应提供用户选择或明确且合理的限制说明。

Missing User Warnings

Low
Confidence
87% confidence
Finding
The manifest explicitly states that the skill downloads webpage content and returns that content, but it does not provide any user-facing warning about outbound network access, what remote data is fetched, or that fetched content may be transmitted back into the agent workflow. This is a real transparency and consent issue: users may invoke the skill without understanding that arbitrary URLs can be contacted and remote content ingested, which can expose internal browsing targets, sensitive query parameters, or untrusted prompt-bearing content.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The download function launches Chrome headlessly against the supplied URL, which causes external network access and transmission of request metadata such as IP, user agent, and possibly ambient browser behavior. The code states it downloads webpage content, but it does not present a specific warning or confirmation around contacting third-party sites.

Static analysis

No suspicious patterns detected.