Back to skill

Security audit

Tavily AI搜索

Security checks for vulnerabilities and agentic risk

Overview

This is mostly a legitimate Tavily search tool, but it ships and stores a Tavily API key in plaintext.

Review this skill before installing. Remove and rotate the bundled Tavily key, avoid committing config.json, and prefer an environment variable or private secret store for your own API key. Expect search queries to be sent to Tavily when the tool is used.

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:1
Finding

Hardcoded Tavily API Credential Stored in Plaintext

Content
View full analysis

Vulnerability Details

File Location: config.json:1-3
Vulnerability Type: Hardcoded secret and plaintext credential storage
Risk Level: High

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

Technical Analysis

The project contains a Tavily API credential directly in a distributed configuration file. Anyone with access to the project package, source repository, backup, build artifact, or repository history can retrieve the credential without authentication.

The application loads this value from config.json and includes it in requests to the Tavily API. In addition, tavily.py:13-16 persists user-supplied credentials to the same repository-local file without explicitly applying owner-only file permissions:

python
def save_config(api_key):
    with open(CONFIG_PATH, "w", encoding="utf-8") as f:
        json.dump({"api_key": api_key}, f, ensure_ascii=False, indent=2)
    print(f"[成功] API密钥已保存到: {CONFIG_PATH}")

This design exposes credentials both through source distribution and through potentially permissive filesystem permissions. The audit did not validate whether the embedded credential remains active; however, its format and direct use by the application require it to be treated as compromised.

Attack Path

  1. An attacker obtains the project archive, checks out the repository, accesses a deployment artifact, or reads a backup containing the project.
  2. The attacker opens config.json and extracts the plaintext Tavily API key.
  3. The attacker submits requests directly to the Tavily API using the extracted key.
  4. If the key is active, the requests are attributed to the credential owner and consume the associated quota or account resources.
  5. The attacker may automate requests to exhaust available quota, interfere with legitimate use, or cause usage-based charges where applicable.
  6. Merely deleting the current file may not end expos ...[truncated 681 chars]
Remediation
View remediation

Remediation Suggestions

  1. Revoke the exposed Tavily API key immediately and issue a replacement. Rotation is required even if the current key appears unused.
  2. Remove the credential from the current project and purge it from version-control history, release archives, build artifacts, backups, and cached packages where feasible.
  3. Obtain the API key at runtime from an environment variable or an operating-system secret manager rather than shipping it in the Skill package.
  4. Add config.json and equivalent local secret files to .gitignore and packaging exclusion rules. Distribute a credential-free template such as config.example.json.
  5. If local file persistence must be supported, store secrets outside the project directory and create the file with owner-only permissions, such as mode 0600 on POSIX systems.
  6. Validate configuration structure without printing or logging the key. Error messages should not include credential values.
  7. Enable provider-side usage monitoring, restrictive quotas, and alerts for abnormal request volume.
  8. Review Tavily account activity for unauthorized use of the exposed credential.
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 (7)

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding

整体上,这段代码的主要目的与声明较为接近:它确实是一个基于 Tavily API 的联网搜索工具,支持基础搜索、较深搜索(通过 research 命令映射为 advanced depth)以及图片返回,也能输出结构化 JSON 结果。但仍存在一定描述与实现不一致之处。最明显的是“引用生成”能力:代码只是打印来源详情(标题、URL、发布时间、摘要),没有看到专门的 citation/reference generation 功能。其次,声明强调“返回结构化搜索结果”,而代码的默认行为是文本格式输出,结构化结果仅是可选 JSON 模式。另一个未声明但实际存在的行为是将 API 密钥写入本地 config.json。这不属于恶意或明显偏离主用途的行为,但属于未声明的资源访问/持久化细节。综合判断,存在轻度到中度不匹配。

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
78% confidence
Finding

The skill advertises networked search and shows local configuration that persists an API key to config.json, but it declares no explicit tool scope or permissions. In an agent environment, missing scope boundaries can cause the host to grant broader file and network access than users expect, increasing the chance of unintended local file reads/writes or unrestricted outbound requests.

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.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
95% confidence
Finding

The tool writes the API key in cleartext to a local config.json file without warning the user or restricting file permissions. On multi-user systems, shared workspaces, backups, or source-control mistakes, this can expose the credential and allow unauthorized use of the Tavily account.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 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
97% confidence
Finding

User-facing strings throughout the script, including the CLI description, help text, prompts, and errors, are hard-coded in Chinese. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The manifest describes a Tavily-powered search capability with features like real-time search, research, image search, and citations. Persisting credentials to a local config file is not part of that user-facing purpose and introduces a local state-management capability unrelated to searching itself.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.