T09 · Insecure Skill Coding Practices
- Location
scripts/auth.py:63- Finding
API Key Exposure Through Terminal Output and Insecure File Permissions
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill mostly matches its paid customs-ranking purpose, but it needs Review because it exposes API-key handling too directly and performs an automatic version-check/cache write that is not clearly disclosed.
Review before installing. Use an environment variable or a protected secret store instead of printing or sharing `~/.upkuajing/.env`, rotate the key if it appears in logs, confirm every paid query deliberately, and avoid sending raw request or response data in error reports unless necessary.
scripts/auth.py:63API Key Exposure Through Terminal Output and Insecure File Permissions
requirements.txt:1Unbounded Third-Party Dependency Version
The skill is presented as a ranking query tool but appears to perform version-check requests, parse local metadata from SKILL.md, and write a cache file under ~/.upkuajing. This undisclosed update-check and local cache behavior introduces extra network and file-write side effects unrelated to the claimed task, which can surprise users and widen the available execution surface.
The skill is presented as a ranking query tool but appears to perform version-check requests, parse local metadata from SKILL.md, and write a cache file under ~/.upkuajing. This undisclosed update-check and local cache behavior introduces extra network and file-write side effects unrelated to the claimed task, which can surprise users and widen the available execution surface.
The skill is presented as a ranking query tool but appears to perform version-check requests, parse local metadata from SKILL.md, and write a cache file under ~/.upkuajing. This undisclosed update-check and local cache behavior introduces extra network and file-write side effects unrelated to the claimed task, which can surprise users and widen the available execution surface.
The skill is presented as a ranking query tool but appears to perform version-check requests, parse local metadata from SKILL.md, and write a cache file under ~/.upkuajing. This undisclosed update-check and local cache behavior introduces extra network and file-write side effects unrelated to the claimed task, which can surprise users and widen the available execution surface.
The skill instructs reading ~/.upkuajing/.env directly, including a literal cat command against a secrets file. In an agent environment, encouraging direct file reads of credential stores can expose API keys to the model, logs, or unintended outputs, and the context makes this especially dangerous because the skill already combines networked operations with paid actions.
本技能需要API密钥。API密钥存储在 ~/.upkuajing/.env 文件中:
cat ~/.upkuajing/.env
文件内容示例:
This section directs the workflow to inspect a local .env file for the API key and to persist newly issued keys there automatically. That creates a credential-access and credential-persistence path outside a controlled secret store, increasing the risk of accidental disclosure, improper file permissions, or reuse by unrelated tools.
### **API密钥未设置**
首先检查 `~/.upkuajing/.env` 文件中是否有 UPKUAJING_API_KEY;
如果未设置,请让用户选择:
1. 用户已有密钥:用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有密钥:通过界面申请(`auth.py --new_key`),新密钥会自动保存到 ~/.upkuajing/.env
等待用户选择;
The skill explicitly tells the user to manually add a provided API key into ~/.upkuajing/.env and notes that a generated key will be auto-saved there. This normalizes local plaintext secret storage and increases the chance of credential theft, leakage through backups/logs, or unintended disclosure to the agent during later file reads.
首先检查 `~/.upkuajing/.env` 文件中是否有 UPKUAJING_API_KEY;
如果未设置,请让用户选择:
1. 用户已有密钥:用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有密钥:通过界面申请(`auth.py --new_key`),新密钥会自动保存到 ~/.upkuajing/.env
等待用户选择;
### **账户充值**
The file implements API key issuance, account information retrieval, and recharge order creation, which materially exceeds the declared skill purpose of returning Top-N supplier/buyer rankings. This scope mismatch increases the attack surface by bundling credential lifecycle and billing operations into a data-query skill, making it easier for a caller or downstream agent to invoke sensitive capabilities unexpectedly.
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 directly to a .env file in the user's home configuration directory without showing any permission hardening or atomic secure creation. Storing long-lived credentials in plaintext can expose them to other local users, backups, logs, or accidental inclusion in support artifacts, especially in agent environments where files may be broadly accessible.
"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")
The error handling and surrounding flow reinforce a design that expects operators to manage the API key as an environment variable or plaintext file, which encourages insecure secret handling. In the context of an agent skill, promoting manual secret placement increases the chance of accidental disclosure through shell history, process environments, screenshots, or shared configuration files.
except IOError as e:
return {
"success": False,
"message": f"API密钥申请成功,但保存到 .env 文件失败:{str(e)}。\n请手动设置环境变量 {API_KEY_ENV}。",
"envFilePath": str(env_file)
}
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 file header states the code reports agent/skill exceptions to a remote platform, which does not align with the advertised Top-N supplier/buyer ranking functionality. This mismatch is dangerous because hidden or unrelated network behavior in a narrowly scoped skill undermines trust boundaries and can conceal data collection not expected by users or integrators.
This file adds a remote error-reporting capability to a skill whose declared purpose is trade ranking, creating a clear scope mismatch and an unexpected outbound data flow. Because the reported payload includes request metadata and free-form context, it can exfiltrate operational or user-derived data to the platform without clear minimization or user awareness.
The skill advertises only a trade-ranking lookup but declares no explicit tool/permission boundaries while the content clearly expects environment access, local file access, and networked operations. In an agent setting, missing scope declarations increase the chance that the skill is granted broader capabilities than users expect, enabling unintended secret access or side effects.
L003 中的 Trigger 列出“供应商排名、采购商排名、贸易量排名、公司TopN”等短语,但未限定必须与海关/国家贸易概览/年份国家维度相关,容易与一般商业分析或任意排名查询场景重叠。描述中也没有给出不应触发的负例或排除条件,因此触发范围不够具体。
The documentation explicitly allows sending request parameters, response data, and exception context to an error-reporting endpoint. Although it notes that sensitive fields are 'automatically masked,' there is no clear requirement for data minimization, explicit user/operator warning, or prohibition on including commercially sensitive or personal data in stack traces and payloads. In a trade/customs skill, these fields can contain company identifiers, transaction details, and operational context, making unintended disclosure to platform-side logging a realistic privacy and confidentiality risk.
The module docstring and user-facing descriptions are entirely in Chinese, which imposes a specific language on users without any opt-in or fallback. Under the policy, forced language selection is a natural-language policy violation unless the locale restriction is explicitly documented and justified.
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:
The module docstring is written as a Chinese-only description, and the rest of the user-facing strings in the file are also Chinese-only. This indicates a language/locale constraint without any visible opt-in, choice mechanism, or documented region-specific justification, which matches the language policy violation criteria.