Back to skill

Security audit

Tavily Search Optimized

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent Tavily web-search skill, but it needs Review because verbose/debug paths can expose the API key and cache clearing can delete an arbitrary configured directory.

Install only if you are comfortable sending search queries to Tavily and storing cached query/results locally. Avoid --verbose until the API key is redacted, do not follow troubleshooting commands that print the key, and do not set TAVILY_CACHE_DIR to any directory containing non-cache data because --clear-cache can recursively delete it.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/tavily_search.py:285
Finding

Verbose Mode Logs the Tavily API Key in Plaintext

Content
View full analysis

Vulnerability Details

File Location: scripts/tavily_search.py, lines 285-298
Vulnerability Type: Sensitive credential exposure through diagnostic logging
Risk Level: High

Vulnerable Code

python
payload = {
    "api_key": key,
    "query": query,
    "max_results": min(max_results, 10),
    "search_depth": search_depth,
    "include_answer": bool(include_answer),
    "include_images": False,
    "include_raw_content": False,
}

if verbose:
    print(f"发送请求到Tavily API...", file=sys.stderr)
    print(f"查询: {query}", file=sys.stderr)
    print(f"参数: {json.dumps(payload, indent=2)}", file=sys.stderr)

Technical Analysis

The request payload contains the complete Tavily API key. When the documented --verbose option is enabled, the entire payload is serialized and written to standard error without redaction.

Standard error is commonly captured by CI systems, agent execution traces, shell-session recorders, container logging drivers, and centralized logging platforms. Consequently, a diagnostic operation can transform a credential that was originally held in an environment variable or protected configuration file into persistent plaintext log data.

Although the key is legitimately required for requests to Tavily, exposing it in diagnostics is unnecessary for the Skill's declared functionality and violates secret-handling best practices.

Attack Path

  1. A user or automated agent configures a valid TAVILY_API_KEY.
  2. The user runs the documented command with --verbose.
  3. The script constructs payload with the complete API key.
  4. json.dumps(payload, indent=2) writes that key to standard error.
  5. A local user, CI operator, log aggregation service, or other party with access to captured output retrieves the key.
  6. The exposed key can be reused to issue Tavily requests under the victim's account.

Impact Assessment

An attacker who obtains the logged key ...[truncated 344 chars]

Remediation
View remediation

Remediation Suggestions

  • Never serialize a secret-bearing payload directly into logs.

  • Create a redacted diagnostic copy before logging:

    python
    if verbose:
        safe_payload = {**payload, "api_key": "***REDACTED***"}
        print("Sending request to Tavily API...", file=sys.stderr)
        print(f"Query: {query}", file=sys.stderr)
        print(f"Parameters: {json.dumps(safe_payload, indent=2)}", file=sys.stderr)
    
  • Prefer logging only non-sensitive fields instead of copying the payload.

  • Add automated tests that run verbose mode with a sentinel key and assert that the sentinel never appears in stdout or stderr.

  • Review historical logs generated by verbose mode and remove or rotate exposed keys where necessary.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:213
Finding

Troubleshooting Documentation Prints the Complete API Key

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 213-216
Vulnerability Type: Unsafe secret-disclosure instruction
Risk Level: Medium

Vulnerable Code

bash
# 检查API密钥
python3 -c "import os; print('TAVILY_API_KEY:', os.environ.get('TAVILY_API_KEY', '未设置'))"

Technical Analysis

The documented troubleshooting command prints the complete value of TAVILY_API_KEY. Users and automated agents are reasonably likely to execute this command when diagnosing configuration problems.

Terminal output may be retained in screenshots, support tickets, shell transcripts, agent conversation traces, CI output, or centralized logs. Checking whether a credential exists does not require revealing its value, so this behavior exceeds the minimum disclosure necessary for troubleshooting.

Attack Path

  1. A user exports a valid TAVILY_API_KEY.
  2. The user encounters a configuration issue and follows the troubleshooting instructions.
  3. The command prints the entire key to the terminal.
  4. The terminal output is observed directly or copied into a log, transcript, screenshot, or support request.
  5. A party with access to that output extracts and reuses the credential.

Impact Assessment

Disclosure permits unauthorized use of the victim's Tavily API account, including quota consumption, possible financial costs, rate-limit exhaustion, and activity attributed to the victim.

The issue does not itself provide local system privileges. Exposure scope depends on where terminal and agent output is retained or shared.

Remediation
View remediation

Remediation Suggestions

Replace the command with a presence-only check:

bash
python3 -c "import os; print('TAVILY_API_KEY is set' if os.environ.get('TAVILY_API_KEY') else 'TAVILY_API_KEY is not set')"

If key identification is operationally necessary, display only a short fingerprint derived from a cryptographic hash rather than any portion of the secret. Documentation should explicitly warn users not to publish environment-variable values, .env contents, verbose output, or screenshots containing credentials.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/tavily_search.py:543
Finding

Configurable Cache Path Enables Unsafe Recursive Directory Deletion

Content
View full analysis

Vulnerability Details

File Location: scripts/tavily_search.py, lines 543-552
Related Configuration Source: scripts/tavily_search.py, lines 129-145
Vulnerability Type: Unrestricted recursive deletion using an externally configurable path
Risk Level: High

Vulnerable Code

The cache directory can be supplied through an environment variable:

python
env_mapping = {
    "TAVILY_API_KEY": "api_key",
    "TAVILY_KEY": "api_key",
    "TAVILY_CACHE_DIR": "cache_dir",
    "TAVILY_DEFAULT_TIMEOUT": "default_timeout",
    "TAVILY_CACHE_TTL": "default_cache_ttl",
    "TAVILY_MAX_RESULTS": "default_max_results",
    "TAVILY_SEARCH_DEPTH": "default_search_depth"
}

for env_var, config_key in env_mapping.items():
    value = os.environ.get(env_var)
    if value:
        if config_key == "api_key":
            config[config_key] = value.strip()
        elif config_key == "cache_dir":
            config[config_key] = pathlib.Path(value.strip())

The configured path is recursively deleted without containment or safety checks:

python
if args.clear_cache:
    try:
        import shutil
        cache_dir = config["cache_dir"]
        if cache_dir.exists():
            shutil.rmtree(cache_dir)
            print(f"✅ 缓存已清除: {cache_dir}", file=sys.stderr)
        else:
            print(f"ℹ️  缓存目录不存在: {cache_dir}", file=sys.stderr)
            return

Technical Analysis

TAVILY_CACHE_DIR can point to an arbitrary filesystem directory. When --clear-cache is used, the script passes that path directly to shutil.rmtree, which recursively removes the directory and its contents.

The implementation does not resolve and validate the path, require it to remain under an approved cache root, reject dangerous targets such as the user's home directory, or verify that the target contains only Skill-generated cache files.

Exploitation is limited to paths writable by ...[truncated 1231 chars]

Remediation
View remediation

Remediation Suggestions

  • Resolve the cache path with Path.resolve() before using it.
  • Restrict deletion to a dedicated Skill cache root, such as ~/.openclaw/cache/tavily.
  • Explicitly reject dangerous targets, including filesystem roots, the user's home directory, the .openclaw root, and directories outside the approved cache parent.
  • Store a Skill-specific marker file in cache directories and require that marker before deletion.
  • Delete only recognized cache files, such as expected hash-named JSON files, rather than recursively deleting the entire directory.
  • Consider removing arbitrary cache-directory configuration from --clear-cache, or require explicit confirmation when a non-default path is used.
  • Add tests covering malicious values such as /, the home directory, parent-directory traversal, symlinks, and unrelated project directories.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (27)

Tainted flow: 'req' from os.environ.get (line 51, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/tavily_search_legacy.py (reported line 58)May include surrounding context.

python
method="POST",
    )

    with urllib.request.urlopen(req, timeout=30) as resp:
        body = resp.read().decode("utf-8", errors="replace")

    try:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 23)May include surrounding context.

md
# Tavily Search 配置示例
# 复制此文件为 .env 并填入你的配置

# ========== 必需配置 ==========

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 24)May include surrounding context.

md
# Tavily Search 配置示例
# 复制此文件为 .env 并填入你的配置

# ========== 必需配置 ==========

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · config.example.env (reported line 2)May include surrounding context.

text
# Tavily Search 配置示例
# 复制此文件为 .env 并填入你的配置

# ========== 必需配置 ==========

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · config.example.env (reported line 42)May include surrounding context.

text
# Tavily Search 配置示例
# 复制此文件为 .env 并填入你的配置

# ========== 必需配置 ==========

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/tavily_search.py (reported line 158)May include surrounding context.

python
# Tavily Search 配置示例
# 复制此文件为 .env 并填入你的配置

# ========== 必需配置 ==========

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/tavily_search.py (reported line 272)May include surrounding context.

python
# Tavily Search 配置示例
# 复制此文件为 .env 并填入你的配置

# ========== 必需配置 ==========

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

Reading a local ~/.openclaw/.env file gives the skill access to secrets outside its explicit inputs, which can unintentionally broaden secret exposure in shared or multi-skill environments. Even though it appears intended for convenience, local credential harvesting from a home-directory file is sensitive behavior and can undermine secret isolation expectations.

Content

Scanner excerpt · scripts/tavily_search_legacy.py (reported line 18)May include surrounding context.

python
if key:
        return key.strip()

    env_path = pathlib.Path.home() / ".openclaw" / ".env"
    if env_path.exists():
        try:
            txt = env_path.read_text(encoding="utf-8", errors="ignore")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/tavily_search.py (reported line 159)May include surrounding context.

python
key = load_key()
    if not key:
        raise SystemExit(
            "Missing TAVILY_API_KEY. Set env var TAVILY_API_KEY or add it to ~/.openclaw/.env"
        )

    payload = {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/tavily_search_legacy.py (reported line 37)May include surrounding context.

python
key = load_key()
    if not key:
        raise SystemExit(
            "Missing TAVILY_API_KEY. Set env var TAVILY_API_KEY or add it to ~/.openclaw/.env"
        )

    payload = {

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill exposes capabilities that involve environment access, file reads/writes, and network use, but it does not declare any explicit tool scope or allowed-tools policy. This weakens least-privilege controls and makes it easier for the skill to access sensitive data or perform unintended actions if invoked in a broader runtime context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill description does not clearly warn users that their search queries will be transmitted to a third-party service, Tavily. This creates a privacy and data-handling risk because users may unknowingly send sensitive prompts, internal project names, credentials, or personal information to an external API.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The main body of the skill documentation is written in Chinese even though the manifest description above is in English, and there is no indication that the skill is intentionally region-specific or that users may choose their preferred language. This is a natural-language locale policy concern because it imposes a specific language without opt-in or justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The instructions, comments, and usage guidance are written exclusively in Chinese, with no bilingual alternative or indication that the skill is intentionally region-specific. This can violate language/locale policy when users are not given an explicit language choice or opt-in.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill writes search queries and results to a persistent local cache directory, which expands its behavior beyond transient web search and can store potentially sensitive user data on disk. In an agent setting, undisclosed local persistence increases privacy and data-handling risk, especially if users search for confidential topics.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The cache stores raw queries and returned data on disk without explicit notice or consent, which can preserve sensitive searches, URLs, and snippets locally. On shared systems or in multi-user environments, this creates avoidable privacy exposure beyond the expected network search function.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

Verbose mode prints the full outbound JSON payload, which includes the Tavily API key in cleartext. Logs are often retained, shared, or visible to operators, so this can directly expose credentials and allow unauthorized API use.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The cache-clearing feature recursively deletes the configured cache directory with shutil.rmtree, which is a destructive filesystem capability not obvious from a search skill. Because the cache path is configurable from environment or config, a misconfiguration could cause deletion of an unintended directory.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/tavily_search.py (reported line 21)May include surrounding context.

python
import sys
import urllib.request

TAVILY_URL = "https://api.tavily.com/search"


def load_key():

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/tavily_search_legacy.py (reported line 10)May include surrounding context.

python
import sys
import urllib.request

TAVILY_URL = "https://api.tavily.com/search"


def load_key():

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown file uses Chinese throughout, including the title and all change descriptions, with no indication that users can choose another language or that the skill is intentionally limited to a Chinese-speaking audience. Under the policy rule for language or locale constraints, forcing a specific language without opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The changelog text is written entirely in Chinese, and this metadata file provides no indication that the skill is region-specific or that users can opt into a preferred language or locale. Under the policy for natural-language violations, forcing a specific language without user opt-in can be a compliance issue.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

This markdown file includes an example command to clear all cached results, which is a destructive operation affecting stored data. Although the command is labeled '清除所有缓存', the documentation does not include an explicit warning about irreversibility or loss of cached data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The troubleshooting example reads TAVILY_API_KEY from the environment and prints a visible prefix of the secret. For markdown files, credential-related behavior should be accompanied by a warning when it could affect privacy or leak sensitive data, but no such warning is present here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

Natural-language strings throughout this file, including the module description, help text, and runtime messages, are presented only in Chinese. Under the stated policy, forcing a specific language without offering the user a choice is a locale/language policy violation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.