Back to skill

Security audit

tavily-extract-zh

Security checks for vulnerabilities and agentic risk

Overview

This skill is presented as a URL text extractor, but it bundles and points users to a broader search and AI synthesis client that can use the same API key for unrelated external requests.

Review before installing. The extraction feature itself is coherent and I found no malware-like persistence or local compromise behavior, but the package exposes broader API-backed search and AI synthesis actions than the skill description says. Only use it if you are comfortable with AISA_API_KEY being available to those broader commands, and avoid passing private URLs or sensitive queries unless the publisher narrows or clearly documents the client behavior.

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

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/search_client.py:186
Finding

Bundled client exceeds the Skill's declared URL-extraction scope

Content
View full analysis

Vulnerability Details

File Location: scripts/search_client.py, lines 186-260
Vulnerability Type: Undeclared API capability and excessive use of delegated credentials
Risk Level: Medium

Technical Analysis

SKILL.md declares a narrowly scoped Tavily URL-extraction Skill whose core capability is converting user-provided URLs into clean text. However, the bundled client also provides a verity operation that sends a user query to four separate search services and subsequently submits all returned results to an AI synthesis endpoint.

Relevant code:

python
def cmd_verity(args: argparse.Namespace) -> None:
    """Multi-source search with confidence scoring."""
    api_key = get_api_key()
    count = args.count

    print(f"\nSearching across multiple sources for: \"{args.query}\"\n")

    # Phase 1: Parallel retrieval
    sources: dict[str, dict[str, Any]] = {}
    tasks = {
        "Web": ("/scholar/search/web", {"query": args.query, "max_num_results": count}),
        "Smart": ("/scholar/search/smart", {"query": args.query, "max_num_results": count}),
        "Scholar": ("/scholar/search/scholar", {"query": args.query, "max_num_results": count}),
        "Tavily": ("/tavily/search", {"query": args.query, "max_results": count, "include_answer": True}),
    }

    def fetch(name: str, endpoint: str, body: dict[str, Any]) -> tuple[str, dict[str, Any]]:
        return name, aisa_post(api_key, endpoint, body)

    with ThreadPoolExecutor(max_workers=4) as pool:
        futures = {
            pool.submit(fetch, name, ep, body): name
            for name, (ep, body) in tasks.items()
        }
        for future in as_completed(futures):
            name = futures[future]
            try:
                _, data = future.result()
                sources[name] = data
                print(f"  [OK] {name}")
            except Exception as e:
                print(f"  [FAIL] {na
...[truncated 3592 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace the multi-purpose client in this Skill with a minimal extraction-only implementation that exposes only /tavily/extract.
  2. Remove the web, scholar, smart, tavily, sonar, and verity handlers and their argument-parser registrations from the extraction package.
  3. If broader capabilities are intentional, publish them as separate Skills with accurate descriptions, explicit activation conditions, and separate credentials or API scopes.
  4. Configure server-side credentials with endpoint-level restrictions so an extraction credential cannot invoke search, deep-research, or synthesis APIs.
  5. Before transmission, clearly disclose the destination, request type, number of URLs or queries, and whether returned content will be submitted for secondary synthesis.
  6. Add conservative request-count and input-size limits to prevent accidental quota exhaustion.
  7. Reject empty URLs and validate URL schemes and maximum list length before sending extraction requests.
  8. Document that user-provided URLs, queries, and extracted or aggregated content are transmitted to https://api.aisa.one.
  9. Add automated tests that compare exposed CLI commands against the capabilities declared in SKILL.md, preventing future scope drift.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (9)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared purpose is narrow URL extraction, but the detected behavior indicates broader search, synthesis, model-query, and aggregation capabilities. This mismatch is dangerous because users, reviewers, or automated policy systems may authorize the skill for low-risk extraction while it can actually initiate wider network activity, process more data than expected, and produce AI-generated outputs beyond the stated scope.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The file implements a broad multi-search CLI with web, scholar, smart, tavily, sonar, and verity modes, which materially exceeds the declared skill purpose of extracting clean body text from provided URLs. In an agent environment, this expands the tool’s authority from narrow retrieval to general search and AI synthesis, increasing the chance of unintended data egress, scope creep, and misuse under a misleading skill description.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The verity workflow performs parallel multi-source searches and then sends the aggregated results to a synthesis endpoint, which is fundamentally different from simple URL content extraction. This creates a hidden secondary behavior path where user queries and retrieved content are transmitted to multiple external services and reprocessed, increasing exposure and violating least privilege for the stated skill context.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding

The skill declares access to an API key and implicitly requires network use, but it does not declare any explicit tool scope such as allowed-tools or permissions. That weakens policy enforcement and review because the runtime capabilities are broader than what the manifest clearly communicates, increasing the chance of unintended external requests or secret exposure through under-scoped execution.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The run instructions point to a search client even though the skill is described as a page-extraction utility. Operationally, this can cause invocation of a broader-capability client than intended, leading to unexpected network actions, data flows, or feature activation that bypasses the user's understanding of the skill's function.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest sets the skill language to "zh", which indicates a fixed language/locale choice. There is no accompanying opt-in, alternative language option, or region-specific justification in this file, so it appears to impose a locale choice unconditionally.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
86% confidence
Finding

The code transmits user-supplied queries, URLs, and potentially retrieved content to an external API endpoint. External transmission is expected for this kind of networked skill, but in this case it is more sensitive because the implementation includes broader search and synthesis capabilities than the skill metadata suggests, so more user data may leave the environment than intended.

Content

Scanner excerpt · scripts/search_client.py (reported line 28)May include surrounding context.

python
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import Any

AISA_BASE = "https://api.aisa.one/apis/v1"


def get_api_key() -> str:

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
75% confidence
Finding

For this skill's narrow declared purpose, environment-based credential handling is an additional capability not mentioned in the manifest. While needed for the current API-backed implementation, it is not justified by the stated extraction-only scope as presented to users.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code hard-codes the explanation request language to "en", which imposes a specific language/locale on users. The file does not offer an opt-in choice or document a region-specific reason for restricting output to English.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.