Back to skill

Security audit

tavily-search

Security checks for vulnerabilities and agentic risk

Overview

This Tavily search skill mostly matches its stated search purpose, but it ships a plaintext API key and handles credentials and third-party query transmission with weak disclosure.

Review before installing. Do not rely on the bundled API key; revoke or remove it and configure your own credential through a safer storage method. Avoid sending secrets, private business terms, or regulated data in search queries unless Tavily use is approved for that data. The skill appears purpose-aligned, but its credential handling and disclosure should be fixed before broad deployment.

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
config.json:2
Finding

Hard-Coded Tavily API Credential in Distributed Configuration

Content
View full analysis

Vulnerability Details

File Location: config.json:2
Vulnerability Type: Hard-coded service credential
Risk Level: High

Vulnerable code:

json
{
  "api_key": "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"
}

Technical Analysis

The project distributes a Tavily API key in plaintext within config.json. Anyone able to download, clone, inspect, or otherwise access the Skill package can recover the credential without authentication or additional exploitation.

The credential is operationally integrated into both implementations:

  • tavily.py:57-60 loads config.json and reads config["api_key"].
  • tavily.py:79-88 places the key in the JSON request body sent to https://api.tavily.com/search.
  • tavily.ps1:44-45 reads the same configuration and extracts $config.api_key.
  • tavily.ps1:59-72 places it in the request body sent to the Tavily API.

This crosses the trust boundary between a credential owner’s private service authorization and arbitrary recipients of the distributable project artifact. The evidence establishes insecure credential exposure, but does not establish credential theft or malicious intent by the project author.

Attack Path

  1. An attacker obtains the published Skill package or reads its project files.
  2. The attacker opens config.json and copies the plaintext API key.
  3. The attacker submits requests to the Tavily API using that key, either through the included scripts or a separate HTTP client.
  4. Tavily processes those requests under the exposed credential owner’s account until the key is revoked, expires, or reaches its service limits.

No execution of project code, local privilege, or modification of user-controlled input is required.

Impact Assessment

An attacker gains the service-level authorization associated with the exposed Tavily API key. This may permit unauthorized search requests, consumption of the account’s API quot ...[truncated 308 chars]

Remediation
View remediation

Remediation Suggestions

  1. Revoke and rotate the exposed Tavily API key immediately.
  2. Remove the credential from the distributed package and all reachable version-control history.
  3. Replace config.json with a non-secret example such as config.example.json, containing only a placeholder value.
  4. Load the credential from an environment variable or a protected, user-specific secret store rather than a project file.
  5. If file-based configuration remains supported, create it outside the package directory and apply owner-only permissions.
  6. Add config.json and other secret-bearing local configuration files to ignore and packaging-exclusion rules.
  7. Add automated secret scanning to the publication workflow and reject releases containing live credential patterns.
  8. Review Tavily usage records for unauthorized activity and apply service-side quota or scope restrictions where supported.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

代码整体与“联网搜索工具”描述大体一致:它确实调用 Tavily API 进行实时搜索,支持基础搜索、研究模式(通过 advanced depth)、图片搜索,并可输出 JSON 结果。但声明中提到“引用生成”,代码仅打印来源标题、URL、发布时间和摘要,没有专门的引用生成/格式化引用功能。此外,声明强调“返回结构化搜索结果”,而代码默认输出为人类可读文本,只有在 --format json 时才返回结构化 JSON。因此描述与实际行为部分一致,但存在功能夸大,属于轻度到中度不匹配。

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill declares networked search behavior and configuration that writes an API key to a local config file, but it does not define any explicit permission or allowed-tool scope. In an agent environment, missing scope boundaries can let the runtime grant broader file/network capabilities than users expect, increasing the chance of unintended data access or outbound transmission.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documentation promotes external search and research features but does not warn that user queries and retrieved content are sent to a third-party service and may be logged, retained, or further processed remotely. Users or calling agents may therefore submit sensitive prompts, internal terms, or proprietary research topics without informed consent, causing avoidable privacy and confidentiality exposure.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

All natural-language strings in the script, including help, errors, and status messages, are presented only in Chinese. The policy forbids forcing a specific language without user opt-in unless the locale restriction is clearly documented and justified, which is not present here.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script stores the API key in plain form in a local config.json under the skill directory, without warning the user or applying any protection. On multi-user systems, shared workspaces, backups, or accidental repository inclusion, this can expose the credential and allow unauthorized use of the Tavily account/API quota.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest description says the skill supports '引用生成' and returns structured search results. In code, the only implemented commands are config, search, research, and image, and the non-JSON path formats results for console display; there is no dedicated citation-generation logic or citation-oriented output transformation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script's descriptions, help text, status messages, and output are written in Chinese throughout, which imposes a specific language on users. There is no option to select another language or indication that the tool is intentionally limited to a Chinese-speaking context.

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 · tavily.ps1 (reported line 42)May include surrounding context.

text
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

CONFIG_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.json")
API_URL = "https://api.tavily.com/search"

def save_config(api_key):
    with open(CONFIG_PATH, "w", encoding="utf-8") as f:

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 · tavily.py (reported line 13)May include surrounding context.

python
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

CONFIG_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.json")
API_URL = "https://api.tavily.com/search"

def save_config(api_key):
    with open(CONFIG_PATH, "w", encoding="utf-8") as f:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The API key is stored in a local JSON file in the skill directory without any permission hardening, secure storage mechanism, or warning to the user. On multi-user systems or when the skill directory is synced, backed up, or committed to source control, the credential can be exposed and abused for unauthorized API use.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

The skill transmits user queries and the API key to an external third-party service. In this skill context that behavior is expected, but it still creates real data-exposure risk if users submit sensitive prompts or if operators are not clearly informed that inputs leave the local environment.

Content

Scanner excerpt · tavily.py (reported line 81)May include surrounding context.

python
}

        try:
            response = requests.post(API_URL, json=body, timeout=30)
            response.raise_for_status()
            result = response.json()

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The natural-language content in the description and usage sections is consistently Chinese, while the skill does not state that it is Chinese-only or provide an opt-in language choice. This can violate language/locale policy when a skill forces a specific language without user consent or justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The manifest description is written entirely in Chinese and does not indicate that language selection is optional or limited to a justified region-specific context. This can violate language/locale policy expectations when a skill is presented to a broader audience without opt-in.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script defines a MaxPages parameter and the help text documents it for 'research', implying page-depth behavior. However, the request body sent to Tavily never includes MaxPages, so the documented behavior is not implemented.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest description says the skill supports '引用生成' and returns structured search results, but the code only exposes config, search, research, and image commands and prints answer/result fields from Tavily responses. There is no explicit citation-generation mode, formatting, or dedicated handling of citations in either text or JSON output.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.