T09 · Insecure Skill Coding Practices
- Location
SKILL.md:37- Finding
Credential Exposure Through Documented Shell Output
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is mostly a disclosed paid API integration, but it handles billing and local API keys in ways users should review before installing.
Install only if you are comfortable with a Chinese-language paid Upkuajing API skill that stores an API key locally. Do not run or share output from `cat ~/.upkuajing/.env`; prefer a securely managed environment variable or secret store, confirm every paid query or recharge action explicitly, and review any error report before sending it to avoid including sensitive business data.
SKILL.md:37Credential Exposure Through Documented Shell Output
scripts/auth.py:62API Key File Created Without Explicit Restrictive Permissions
requirements.txt:1Unbounded Third-Party Dependency Installation
Version checking, parsing local metadata, caching version information, and contacting a remote version endpoint are behaviors outside the skill's declared purpose of returning trade overview data. These extra behaviors widen the attack surface and can expose local state or create unexpected outbound traffic not anticipated by the user.
Version checking, parsing local metadata, caching version information, and contacting a remote version endpoint are behaviors outside the skill's declared purpose of returning trade overview data. These extra behaviors widen the attack surface and can expose local state or create unexpected outbound traffic not anticipated by the user.
Version checking, parsing local metadata, caching version information, and contacting a remote version endpoint are behaviors outside the skill's declared purpose of returning trade overview data. These extra behaviors widen the attack surface and can expose local state or create unexpected outbound traffic not anticipated by the user.
Version checking, parsing local metadata, caching version information, and contacting a remote version endpoint are behaviors outside the skill's declared purpose of returning trade overview data. These extra behaviors widen the attack surface and can expose local state or create unexpected outbound traffic not anticipated by the user.
The skill instructs reading the full ~/.upkuajing/.env file using cat, which can expose the API key and any other secrets stored in that file to the agent, logs, or user-facing output. Direct secret file access is especially risky in a skill whose declared purpose is merely querying overview data, making the credential access broader than necessary.
本技能需要API密钥。API密钥存储在 ~/.upkuajing/.env 文件中:
cat ~/.upkuajing/.env
文件内容示例:
The skill directs the workflow to inspect whether UPKUAJING_API_KEY exists in a local .env file and to obtain or save a new key there. This creates a pattern of local credential discovery and persistence that can expose secrets, normalize unsafe handling practices, and allow unrelated agent logic to access them.
### **API密钥未设置**
首先检查 `~/.upkuajing/.env` 文件中是否有 UPKUAJING_API_KEY;
如果未设置,请让用户选择:
1. 用户已有密钥:用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有密钥:通过界面申请(`auth.py --new_key`),新密钥会自动保存到 ~/.upkuajing/.env
等待用户选择;
The instructions explicitly contemplate manually adding secrets to ~/.upkuajing/.env or auto-saving newly created API keys there. Plaintext storage of long-lived credentials on disk increases the risk of disclosure through file reads, backups, logs, multi-user access, or later compromise of the host environment.
首先检查 `~/.upkuajing/.env` 文件中是否有 UPKUAJING_API_KEY;
如果未设置,请让用户选择:
1. 用户已有密钥:用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有密钥:通过界面申请(`auth.py --new_key`),新密钥会自动保存到 ~/.upkuajing/.env
等待用户选择;
### **账户充值**
The file implements authentication management, API key issuance, account lookup, recharge ordering, and pricing queries, which are materially outside the declared skill purpose of report-overview/statistics retrieval. In an agent-skill context, excess capabilities expand the attack surface and can enable unauthorized financial or account operations if the skill is invoked unexpectedly or chained by another component.
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 code opens and reads the local .env file to inspect an existing API key, which means this skill directly handles stored credentials. In this context, a report-query skill should not need to read long-lived secrets from plaintext files; doing so increases exposure to accidental leakage, overbroad access, and secret reuse by unrelated functionality.
env_file = UPKUAJING_ENV_FILE
if env_file.exists():
# 读取现有的 .env 文件
try:
with open(env_file, 'r', encoding='utf-8') as f:
content = f.read()
The code writes a newly issued API key directly into a plaintext .env file under the user's home directory. Persisting long-lived credentials in plaintext materially increases the chance of compromise through local disclosure, backups, logs, developer tooling, or other processes that can read user files.
"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")
Creating recharge/payment orders is a financial action unrelated to the advertised report overview functionality. Exposing purchase/payment primitives inside a data-query skill increases the risk of confused-deputy behavior, misuse by downstream agents, or unauthorized charges if the script is accessible through broader automation.
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'
# 日志开关
技能清单声明该技能用于“查询分析报告-概览数据”,按国家维度获取供应商/采购商数量等信息并支持分页;但此文件核心行为是收集 skillId、requestId、requestPath、context 并调用 /agent/skill/error/report 上报异常。异常遥测上报并不是“报告概览查询”语义下显式声明的功能,和清单描述的业务能力明显不一致。
The skill declares no explicit tool scope even though its instructions require reading environment files, writing local credential/config files, and making networked API calls. Without a clear allowlist of permitted capabilities, an agent may grant broader access than users expect, increasing the risk of unintended file access, credential handling, and outbound requests.
The skill name, description, examples, workflow guidance, and user-facing instructions are entirely Chinese, with no indication that the user can choose another language or locale. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy concern.
The manifest description advertises trigger phrases such as “国家统计数据” and “报告概览”, which are broad and not clearly constrained to this specific customs-analysis skill. The file does not provide exclusion conditions or negative examples to clarify when these phrases should or should not invoke the skill.
The document instructs agents to send request parameters, response data, and error context to an error-reporting endpoint, which can include sensitive business data, identifiers, or stack traces. Although it says sensitive fields are 'automatically desensitized,' it does not define the protection scope, obtain user consent, or require explicit minimization, creating a real privacy and data-leakage risk if operators forward raw payloads during failures.
The module docstring and all user-facing CLI descriptions/messages are written only in Chinese, which indicates a fixed language choice for the skill's interface. The file does not offer any user opt-in, locale selection, or justification that the skill is intended only for a Chinese-language or region-specific audience.
The code can request a new API key and persist it locally, which is far more sensitive than the declared read-only analytics use case. Combining credential provisioning with a reporting skill creates an unnecessary credential-access path and may let an agent obtain long-lived secrets that can later be abused for broader API access.
Disabling authentication for the '/agent/auth/create' request is an unsafe default in the context of a narrowly scoped analytics skill. It enables a capability escalation path where the component can obtain credentials without prior trust establishment, which is unnecessary for simple report retrieval and widens the attack surface.
pass # 如果读取失败,继续执行
# 不需要认证申请新密钥
response = make_request('/agent/auth/create', {}, require_auth=False)
# 检查是否申请成功
if response.get('code') != 0:
Detected: suspicious.exposed_secret_literal