T09 · Insecure Skill Coding Practices
- Location
config.json:1- Finding
Hard-Coded Tavily API Credential Stored in Plaintext
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is a coherent Tavily search wrapper, but it ships and stores API credentials in plaintext, so users should review it before installing.
Review before installing. Remove and revoke the bundled Tavily key, avoid sensitive search queries, and prefer an environment variable or OS credential manager instead of saving your own key in config.json.
config.json:1Hard-Coded Tavily API Credential Stored in Plaintext
代码整体确实是在调用 Tavily 搜索 API,具备联网搜索、较深搜索模式(research 通过 advanced depth 实现)、图片搜索,以及结构化 JSON 输出等能力,这些与声明大体一致。但描述中提到“引用生成”,代码并没有单独生成或格式化引用,仅打印来源标题、URL、发布时间和摘要,这更像搜索结果来源展示而非明确的 citation generation 功能。此外,描述强调“专为AI Agent设计”,而实际代码是本地命令行脚本,提供 config/search/research/image 子命令,没有体现专门的 Agent 工具封装、触发器或集成接口。因此存在轻度但明确的描述与实现不完全一致。
Without declared permissions the skill's intent is opaque and cannot be validated.
All help text, status messages, and error messages are presented only in Chinese, with no option for users to select another language. This is a natural-language policy issue because it imposes a locale-specific experience without documented opt-in or justification.
The script stores the Tavily API key in a local config.json file in plaintext without permission hardening, encryption, or user warning. On multi-user systems or in insecure workspaces, other local users, backup systems, or malware could read the credential and abuse the associated Tavily account.
The script transmits user queries and the API key to an external service at api.tavily.com as part of its intended search functionality. In the context of an agent skill, this matters because prompts, research topics, or other potentially sensitive user data may be sent off-host without explicit consent controls, redaction, or policy checks.
}
$config = Get-Content $configPath | ConvertFrom-Json
$apiKey = $config.api_key
$apiUrl = "https://api.tavily.com/search"
# 搜索功能
if ($Command -eq "search" -or $Command -eq "research" -or $Command -eq "image") {
The help text says the research command supports --max-pages 10, implying pagination or multi-page deep research behavior. However, $MaxPages is only declared as a parameter and is never used in request construction or any other logic; the research mode only switches search_depth to advanced. This is an active documentation-to-code mismatch about the skill's behavior.
This code uses Chinese for comments, CLI descriptions, prompts, and status/error messages throughout the skill, which imposes a specific language on all users. The policy allows fixed locale behavior only when it is justified or when users are given a language/locale choice, neither of which appears here.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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:
The script persistently stores the Tavily API key in a local JSON file beside the code, which increases the chance of accidental disclosure through weak filesystem permissions, backups, logs, packaging, or source-control mistakes. For a search utility, long-term credential storage is not strictly necessary and creates avoidable secret-handling risk.
The tool transmits user queries, optional raw page content requests, and the API key to an external third-party service over the network. While this is expected for a search skill, it still creates a real data-exposure boundary: sensitive prompts, research topics, or retrieved content may leave the local environment and be processed or logged by the provider.
}
try:
response = requests.post(API_URL, json=body, timeout=30)
response.raise_for_status()
result = response.json()
The manifest description is written entirely in Chinese and provides no indication that the skill supports other languages or is intentionally limited to a Chinese-speaking audience. Under the policy, language or locale constraints should be optional or explicitly justified when region-specific.