Back to skill

Security audit

Web Intel

Security checks for vulnerabilities and agentic risk

Overview

This web research skill is coherent, but it needs review because deep mode can use a logged-in Chrome session to read arbitrary page text.

Review before installing. Use this only if you are comfortable with a tool that can route URLs to third-party extraction services and, in deep mode, can use your logged-in Chrome context through a local CDP proxy. Avoid using deep mode on private accounts, internal dashboards, localhost services, or URLs containing tokens unless the skill is updated with explicit confirmation and destination allowlists.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/web_intel.py:113
Finding

Unrestricted URL Fetching Through the User's Authenticated Browser Session

Content
View full analysis

Vulnerability Details

File Location: scripts/web_intel.py:113-140, 225-229, 280-284
Vulnerability Type: Server-Side Request Forgery and authenticated-browser data exposure
Risk Level: High

Vulnerable Code

python
def _cdp_fetch(url: str, timeout: int = 15) -> str | None:
    """Extract page content through the web-access CDP Proxy."""
    target_id = None
    try:
        # Create a background tab
        new_resp = urllib.request.urlopen(
            f"{CDP_PROXY_URL}/new?url={urllib.parse.quote(url, safe=':/?=#&')}",
            timeout=timeout,
        )
        data = json.loads(new_resp.read())
        target_id = data.get("targetId") or data.get("id")
        if not target_id:
            return None

        # Extract page body through JavaScript evaluation
        eval_req = urllib.request.Request(
            f"{CDP_PROXY_URL}/eval?target={target_id}",
            data=b"document.body ? document.body.innerText : ''",
            method="POST",
        )
        content = urllib.request.urlopen(eval_req, timeout=timeout).read().decode(
            "utf-8", errors="replace"
        )
        return content[:12000] if content else None
python
else:  # deep: prefer CDP, then use fallback services
    if cdp:
        full_content = _cdp_fetch(url)
        tool = "web_access_cdp"
python
p.add_argument("--url", help="Directly extract the specified URL and skip search")

Technical Analysis

The --url argument is passed into _cdp_fetch() without validating its scheme, hostname, resolved IP address, port, or redirect destination. When deep mode is selected and the local CDP proxy is available, the URL is opened in the user's Chrome environment. The Skill documentation states that this browser environment carries the user's authenticated session.

URL encoding does not establish a security boundary. The implementation does not rest ...[truncated 2412 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse targets with a strict URL parser and permit only explicitly required schemes, normally https and optionally http.
  2. Reject URLs containing user-information components, malformed hosts, ambiguous numeric IP representations, or unsupported ports.
  3. Resolve the hostname before navigation and reject every address in loopback, private, link-local, multicast, reserved, unspecified, and other non-public ranges for both IPv4 and IPv6.
  4. Explicitly block known metadata destinations, including link-local metadata addresses and provider-specific metadata hostnames.
  5. Disable automatic redirects or validate every redirect target using the same scheme, hostname, DNS, and IP-address checks before following it.
  6. Protect against DNS rebinding by binding validation to the address actually used for the connection rather than trusting a single preliminary DNS lookup.
  7. Prefer an approved-domain allowlist for authenticated CDP extraction.
  8. Require explicit, informed user confirmation before opening a target through a browser context that carries authentication state.
  9. Use an isolated, unprivileged browser profile without personal cookies for general-purpose extraction. Reserve authenticated profiles for narrowly scoped, user-approved domains.
  10. Apply authorization and origin checks to the local CDP proxy and ensure it is not accessible to untrusted local or remote processes.
  11. Avoid returning authenticated page content by default. Redact sensitive values, minimize output, and clearly identify when content came from an authenticated session.
  12. Add automated tests covering loopback addresses, private IPv4 and IPv6 ranges, metadata endpoints, encoded IP forms, alternate ports, redirects to internal destinations, and DNS-rebinding scenarios.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (10)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

Deep mode can drive a local browser/CDP proxy using existing login state and retrieve page body text, which may expose authenticated content, personal data, or corporate data far beyond what a normal unauthenticated fetch would reveal. Because the tool is designed for broad delegation by other agents, using login-state browsing without strong warning, consent, and destination restrictions materially raises the risk of unauthorized data access and exfiltration.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill advertises and orchestrates network and shell-capable operations but does not declare any explicit tool scope such as permissions or allowed-tools. That creates an authorization and review gap: downstream callers may invoke web access, shell commands, and local proxy checks without a clear policy boundary, increasing the chance of unintended command execution or overly broad network use.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill states that deep mode can connect to a localhost CDP proxy attached to the user's Chrome and 'naturally' carry the user's logged-in session, but it does not present this as a prominent user warning or consent boundary. This is dangerous because a caller may trigger authenticated browsing and extract data from private accounts or session-scoped pages without the user understanding that their existing browser identity is being reused.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The natural-language interface, usage examples, and user-facing descriptions are written entirely in Chinese, with no indication that other languages are supported or that language is user-selectable. Under the policy, forcing a specific language without user opt-in is a language/locale policy concern.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The Jina Reader path sends user-supplied URLs to an external third-party service for content extraction, which can disclose sensitive targets, tokens in URLs, or internal resources if the caller passes them. Because this skill is a generic web-intel entry point likely used by other agents, silent transmission to external services increases privacy and data-handling risk in normal operation.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/web_intel.py (reported line 76)May include surrounding context.

python
if scrape:
        cmd.append("--scrape")
    try:
        r = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
        text = r.stdout.strip()
        for i, ch in enumerate(text):
            if ch in ("[", "{"):

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/web_intel.py (reported line 96)May include surrounding context.

python
def _fc_scrape(url: str) -> str | None:
    """通过 firecrawl CLI 抓取单页内容"""
    try:
        r = subprocess.run(
            ["firecrawl", "scrape", url],
            capture_output=True, text=True, timeout=30,
        )

Tainted flow: 'eval_req' from urllib.request.urlopen (line 125, network input) → urllib.request.urlopen (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/web_intel.py (reported line 130)May include surrounding context.

python
data=b"document.body ? document.body.innerText : ''",
            method="POST",
        )
        content = urllib.request.urlopen(eval_req, timeout=timeout).read().decode(
            "utf-8", errors="replace"
        )
        return content[:12000] if content else None

Tainted flow: 'target_id' from urllib.request.urlopen (line 120, network input) → urllib.request.urlopen (network output)

Medium
Category
Data Flow
Confidence
87% confidence
Finding

The code takes target_id from a network response returned by the local CDP proxy and interpolates it directly into a follow-up request URL without validation or encoding. If the local proxy is compromised or spoofed, a malicious target_id could alter request parameters or trigger unintended actions against the proxy endpoint.

Content

Scanner excerpt · scripts/web_intel.py (reported line 141)May include surrounding context.

python
# 关闭 tab,保持环境整洁
        if target_id:
            try:
                urllib.request.urlopen(
                    f"{CDP_PROXY_URL}/close?target={target_id}", timeout=5
                )
            except Exception:

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The script invokes an external CLI via subprocess to perform web search and scraping, but there is no explicit warning that running this tool will execute another installed program and may perform outbound network activity. The stated purpose is web retrieval, so the execution is somewhat expected, but the absence of any disclosure still leaves users uninformed about the delegated operation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.