T09 · Insecure Skill Coding Practices
- Location
SKILL.md:36- Finding
API Key Exposure Through Documentation and Insufficiently Protected Credential Persistence
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill mostly does what it says, but it handles API keys and paid account actions in ways users should review carefully before installing.
Review this skill before installing if you are not comfortable with an agent reading or creating `~/.upkuajing/.env`, using a paid Upkuajing API key, creating recharge payment links, and optionally sending diagnostic reports. Do not let the agent print the full API key; prefer setting it securely in the environment and rotate the key if it is ever shown in logs or chat output.
SKILL.md:36API Key Exposure Through Documentation and Insufficiently Protected Credential Persistence
requirements.txt:1Unpinned Third-Party HTTP Dependency
The skill claims to search company data but also includes exception reporting that transmits request identifiers and execution context to a platform endpoint. Sending operational context off-box is a materially different behavior from simple search and can expose user queries, identifiers, or workflow metadata if users are not clearly informed.
The skill claims to search company data but also includes exception reporting that transmits request identifiers and execution context to a platform endpoint. Sending operational context off-box is a materially different behavior from simple search and can expose user queries, identifiers, or workflow metadata if users are not clearly informed.
The skill claims to search company data but also includes exception reporting that transmits request identifiers and execution context to a platform endpoint. Sending operational context off-box is a materially different behavior from simple search and can expose user queries, identifiers, or workflow metadata if users are not clearly informed.
The documentation explicitly instructs reading ~/.upkuajing/.env with cat, which exposes the API key in plaintext to the agent/session output. Credential display is dangerous because secrets can be logged, echoed back to the user, or reused for unauthorized API calls and billing-related actions.
使用此技能需要API密钥。API密钥保存在 ~/.upkuajing/.env 文件中:
cat ~/.upkuajing/.env
文件内容示例:
The skill directs the agent to inspect a local secret file for UPKUAJING_API_KEY and to participate in credential setup. Accessing local credential stores increases exposure risk, and coupling that with account actions makes compromise more damaging in this skill context because the same key governs paid API usage.
### **未设置API密钥**
请先检查 `~/.upkuajing/.env` 文件是否有 UPKUAJING_API_KEY;
如果未设置 UPKUAJING_API_KEY API密钥,请提示并让用户选择:
1. 用户有,由用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有,你可使用接口进行申请(`auth.py --new_key`),申请到新密钥后,会自动保存到 ~/.upkuajing/.env
等待用户选择;
The skill can apply for a new API key and automatically save it into ~/.upkuajing/.env, introducing both credential creation and local secret persistence. Automatic secret generation/storage by a broadly scoped skill is risky because it expands the blast radius from simple search to account provisioning and leaves reusable credentials on disk.
请先检查 `~/.upkuajing/.env` 文件是否有 UPKUAJING_API_KEY;
如果未设置 UPKUAJING_API_KEY API密钥,请提示并让用户选择:
1. 用户有,由用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有,你可使用接口进行申请(`auth.py --new_key`),申请到新密钥后,会自动保存到 ~/.upkuajing/.env
等待用户选择;
### **账户充值**
技能清单声明该技能用于基于企业数据库筛选目标公司,服务于外贸客户/供应商挖掘;但该文件的模块说明和实现均围绕“跨境魔方认证管理”、API 密钥申请、账户余额查询和充值订单创建展开。这不是企业搜索能力的明显实现细节,而是独立的账户与计费管理功能,和声明用途存在明显语义偏离。
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""
申请新的 API 密钥。
"""
# 检查是否已存在 .env 文件和 API key
env_file = UPKUAJING_ENV_FILE
if env_file.exists():
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""
申请新的 API 密钥。
"""
# 检查是否已存在 .env 文件和 API key
env_file = UPKUAJING_ENV_FILE
if env_file.exists():
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""
申请新的 API 密钥。
"""
# 检查是否已存在 .env 文件和 API key
env_file = UPKUAJING_ENV_FILE
if env_file.exists():
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""
申请新的 API 密钥。
"""
# 检查是否已存在 .env 文件和 API key
env_file = UPKUAJING_ENV_FILE
if env_file.exists():
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""
申请新的 API 密钥。
"""
# 检查是否已存在 .env 文件和 API key
env_file = UPKUAJING_ENV_FILE
if env_file.exists():
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""
申请新的 API 密钥。
"""
# 检查是否已存在 .env 文件和 API key
env_file = UPKUAJING_ENV_FILE
if env_file.exists():
The script writes a newly issued API key to a plaintext .env file under the user's home-managed directory without any visible permission hardening. If that file is created with overly permissive defaults or later exposed through backups, logs, or shared environments, the API key could be stolen and abused.
"envFilePath": str(env_file)
}
# 保存到 .env 文件
try:
with open(env_file, 'w', encoding='utf-8') as f:
f.write(f"{API_KEY_ENV}={api_key}\n")
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
API_BASE_URL = "https://openapi.upkuajing.com"
API_KEY_ENV = "UPKUAJING_API_KEY"
UPKUAJING_DIR = Path.home() / '.upkuajing'
UPKUAJING_ENV_FILE = UPKUAJING_DIR / '.env'
UPKUAJING_LOGS_DIR = UPKUAJING_DIR / 'logs'
# 日志开关
The manifest says this skill helps users search global companies by product category, industry, and company size to identify customers or suppliers. This file instead collects invocation error details and sends them to an '/agent/skill/error/report' endpoint for platform-side tracking, which is operational telemetry rather than company-search functionality.
The skill invokes capabilities that can read environment-backed secrets, read/write local files, and make network requests, but it does not declare any explicit tool scope or permissions boundary. That weakens reviewability and increases the chance an agent will grant broader access than users expect, especially because the skill also documents reading ~/.upkuajing/.env and writing API keys locally.
The markdown instructs that industry and product names '需使用英文' / '需要使用英文', which imposes a language requirement in the skill's natural-language behavior. Under the policy, forcing a specific language without user choice or a clearly documented justification is a locale/language policy violation.
The API reference explicitly exposes employee and person contact-related fields such as existPersonContact and person_contact_show without any accompanying privacy, consent, or acceptable-use guidance. In a lead-generation and company-search skill, this materially increases the risk of scraping, profiling, or misuse of personal contact data, especially across jurisdictions with data protection requirements.
The documentation explicitly encourages sending requestParams, responseData, and context to an error-reporting endpoint, which can contain user inputs, backend responses, stack traces, and operational details. Although it notes that sensitive fields are 'automatically desensitized,' it does not define scope, guarantees, or require user/operator caution, so this creates a real privacy and data-leakage risk if secrets, personal data, or proprietary business information are included in error reports.
The module docstring and all user-facing descriptions are written only in Chinese, which signals a fixed language/locale for the skill. Under the policy, forcing a specific language without user opt-in or a documented justified locale constraint is a natural-language policy violation.
new_key() 不仅向认证接口申请新的 API 密钥,还将密钥写入本地 .env 文件。这属于凭证生命周期管理能力,而不是企业搜索筛选功能本身;在当前 manifest 描述下,该能力缺乏充分的用途说明。
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.
pass # 如果读取失败,继续执行
# 不需要认证申请新密钥
response = make_request('/agent/auth/create', {}, require_auth=False)
# 检查是否申请成功
if response.get('code') != 0:
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.
pass # 如果读取失败,继续执行
# 不需要认证申请新密钥
response = make_request('/agent/auth/create', {}, require_auth=False)
# 检查是否申请成功
if response.get('code') != 0:
new_rec_order() 调用 /agent/auth/pay/url 创建充值订单并返回支付地址,这是资金/计费相关能力。对于一个声明为“通过产品品类、行业、企业规模筛选目标公司”的搜索技能而言,充值下单并非完成其核心目的所直接必需的能力。
Detected: suspicious.exposed_secret_literal