Back to skill

Security audit

HTML Text Extract

Security checks for vulnerabilities and agentic risk

Overview

This HTML extractor is mostly purpose-aligned, but it automatically installs unpinned Python packages into the active environment and can fetch unrestricted URLs from the host network.

Install only in an isolated environment you are comfortable modifying. Avoid running it on sensitive networks or with privileged accounts, and prefer a version that declares and pins dependencies ahead of time, removes automatic pip install, and restricts or clearly controls remote 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 (2)

T08 · Insecure Dependencies

Error
Location
html_extract.py:26
Finding

Automatic Installation of Unpinned Dependencies into the Active Python Environment

Content
View full analysis
None: """Install any required packages that are missing.""" missing = [ pip_name for module, pip_name in REQUIRED_PACKAGES.items() if importlib.util.find_spec(module) is None ] if not missing: return warn(f"Installing missing packages: {', '.join(missing)}...") try: subprocess.check_call( [sys.executable, "-m", "pip", "install", *missing, "--break-system-packages"] ) except subprocess.CalledProcessError: # --break-system-packages may not be supported (e.g. macOS, older pip). Retry without it. try: subprocess.check_call( [sys.executable, "-m", "pip", "install", *missing] ) except subprocess.CalledProcessError: warn(f"Failed to install: {', '.join(missing)}") sys.exit(1) ``` The installation function is automatically invoked at program startup: ```python if __name__ == "__main__": ensure_dependencies() main() ``` ### Technical Analysis The script checks whether `trafilatura` is importable and, if not, automatically invokes pip to install it. No package version or artifact hash is pinned. Consequently, the package version and its transitive dependency graph can change after the skill has been reviewed. Python package installation may execute package build hooks or other installation-time code. If the package index, named package, maintainer account, distribution artifact, or a transitive dependency is compromised, attacker-controlled code could execute with the same privileges as the skill process. The `--break-system-packages` option further weak ...[truncated 1649 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
html_extract.py:51
Finding

Server-Side Request Forgery Through Unrestricted URL Fetching

Content
View full analysis
bool: try: parsed = urlparse(value) except ValueError: return False return parsed.scheme in ("http", "https") and bool(parsed.netloc) def fetch_html(url: str) -> str: import trafilatura downloaded = trafilatura.fetch_url(url) if not downloaded: warn(f"Error: failed to fetch {url}") sys.exit(1) return downloaded ``` User-controlled input is passed directly to the fetch operation: ```python def read_input(source: str) -> tuple[str, str | None]: """Return (html, source_url). source_url is set only when input was a URL.""" if source == "-": return sys.stdin.read(), None if looks_like_url(source): warn(f"Fetching {source}...") return fetch_html(source), source try: with open(source, encoding="utf-8") as f: return f.read(), None ``` ### Technical Analysis The URL check verifies only that the scheme is HTTP or HTTPS and that the parsed URL contains a network location. It does not restrict the destination host, resolved IP address, port, embedded credentials, or redirect destination. As a result, a caller can direct the skill's network client toward loopback services, private network addresses, link-local addresses, cloud instance metadata services, or other HTTP services reachable from the execution environment. Hostnames that resolve to restricted addresses and DNS-rebinding patterns are also not addressed by the validation. The application delegates fetching to `trafilatura.fetch_url()` without application-level destination controls. The retrieved response is then passed to the extractor and printed to standard output, potentially exposing readable data from an internal endpoint. The statement in `SKILL.m ...[truncated 1552 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
Findings (8)

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill's stated purpose is HTML text extraction, but it also installs packages and executes subprocesses, which materially exceeds that role. Capability mismatch is dangerous because users and orchestrators may grant the skill trust or permissions based on its benign description, while the code performs privileged environment changes.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Automatic pip installation is unjustified for this skill and introduces a direct supply-chain risk: running the tool can download and execute package installation code from remote sources. In the context of an HTML extractor, this additional capability is especially suspicious because it is unnecessary to the core function and can modify the host system.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill documentation indicates capabilities that can access both network resources and local files, but it does not declare an explicit permission or allowed-tools scope. That creates an avoidable trust gap: an agent may invoke the skill in contexts where users or orchestrators do not expect outbound fetching or shell execution, increasing the chance of unintended data access or exfiltration paths.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script modifies the system by installing packages after only a generic stderr notice, without requiring affirmative user consent or making the consequences explicit. This can surprise users, break managed environments, and violate least-privilege expectations, especially because it uses --break-system-packages in one path.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
97% confidence
Finding

This subprocess call invokes pip to install packages at runtime, which gives the skill an unexpected system-modifying capability unrelated to simple HTML extraction. Even though the command is not shell-injected, it can pull and execute unpinned third-party package code from package indexes, expanding supply-chain and environment-compromise risk.

Content

Scanner excerpt · html_extract.py (reported line 38)May include surrounding context.

python
return
    warn(f"Installing missing packages: {', '.join(missing)}...")
    try:
        subprocess.check_call(
            [sys.executable, "-m", "pip", "install", *missing, "--break-system-packages"]
        )
    except subprocess.CalledProcessError:

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
97% confidence
Finding

The retry path performs another runtime pip installation, preserving the same unsafe capability while broadening compatibility for system modification. This increases the chance the skill will alter the host environment and execute unreviewed package installation logic without explicit prior consent.

Content

Scanner excerpt · html_extract.py (reported line 44)May include surrounding context.

python
except subprocess.CalledProcessError:
        # --break-system-packages may not be supported (e.g. macOS, older pip). Retry without it.
        try:
            subprocess.check_call(
                [sys.executable, "-m", "pip", "install", *missing]
            )
        except subprocess.CalledProcessError:

Vague Triggers

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The 'When to use' section describes general situations like wanting readable text or preparing a corpus, but it does not define specific trigger phrases, scope boundaries, or negative examples. In a markdown skill description, this can make activation criteria overly broad and increase the chance of unintended invocation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

When the input looks like a URL, the script fetches it over the network using trafilatura.fetch_url. The code logs that it is fetching the URL, but it does not disclose that this causes a network request and may transmit user-provided targets or related request metadata to remote systems.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.