T09 · Insecure Skill Coding Practices
- Location
SKILL.md:36- Finding
Credential File Disclosure Through Documented Output Command
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill performs the advertised customs statistics query, but it also handles API keys, paid account actions, telemetry, and update checks with unsafe or under-disclosed credential handling.
Review this skill before installing. Do not let an agent print `~/.upkuajing/.env`; only check whether the required key exists. Use a dedicated, least-privilege API key, protect the file with owner-only permissions, confirm every paid action separately, and avoid sending raw business data or secrets in error reports.
SKILL.md:36Credential File Disclosure Through Documented Output Command
scripts/auth.py:61API Key Stored Without Enforced Owner-Only File Permissions
requirements.txt:1Unbounded Third-Party Dependency Version
The finding indicates auxiliary behavior such as remote version checks, local cache reads/writes, and parsing local skill files, none of which are part of the declared customs-statistics purpose. These hidden background actions expand the trust boundary and introduce unnecessary file and network access that could expose metadata or enable silent changes in runtime behavior.
The finding indicates auxiliary behavior such as remote version checks, local cache reads/writes, and parsing local skill files, none of which are part of the declared customs-statistics purpose. These hidden background actions expand the trust boundary and introduce unnecessary file and network access that could expose metadata or enable silent changes in runtime behavior.
The finding indicates auxiliary behavior such as remote version checks, local cache reads/writes, and parsing local skill files, none of which are part of the declared customs-statistics purpose. These hidden background actions expand the trust boundary and introduce unnecessary file and network access that could expose metadata or enable silent changes in runtime behavior.
The skill instructs reading the entire ~/.upkuajing/.env file with cat, which can expose the API key and any other secrets stored in that file to the agent output or logs. In this context, the danger is elevated because the skill itself also performs paid API actions and account operations, so disclosure of the key could directly enable unauthorized usage and billing.
使用此技能需要API密钥。API密钥保存在 ~/.upkuajing/.env 文件中:
cat ~/.upkuajing/.env
文件内容示例:
The skill directs the agent to inspect a local secret file and, if no key exists, to request creation of a new API key that will be automatically saved to ~/.upkuajing/.env. This combines secret discovery, credential issuance, and local persistence in a single workflow, which is risky because it can create or overwrite credentials on the user's system beyond the expected scope of a trade-stats query.
### **未设置API密钥**
请先检查 `~/.upkuajing/.env` 文件是否有 UPKUAJING_API_KEY;
如果未设置 UPKUAJING_API_KEY API密钥,请提示并让用户选择:
1. 用户有,由用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有,你可使用接口进行申请(`auth.py --new_key`),申请到新密钥后,会自动保存到 ~/.upkuajing/.env
等待用户选择;
Automatically saving newly issued API keys into a plaintext local .env file creates a persistent credential exposure risk, especially on shared systems or in environments with loose file permissions, backups, or logging. Because this skill also supports billing-related and account-related actions, compromise of that key could lead to unauthorized charges and access to account data.
请先检查 `~/.upkuajing/.env` 文件是否有 UPKUAJING_API_KEY;
如果未设置 UPKUAJING_API_KEY API密钥,请提示并让用户选择:
1. 用户有,由用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有,你可使用接口进行申请(`auth.py --new_key`),申请到新密钥后,会自动保存到 ~/.upkuajing/.env
等待用户选择;
### **账户充值**
The file implements account-management behavior such as API key issuance, account information retrieval, recharge order creation, and pricing lookup, which is materially outside the declared purpose of a customs trade statistics skill. This scope mismatch increases supply-chain and trust risk because a user invoking a data-analysis skill may unknowingly trigger credential provisioning or billing-related actions.
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 secure storage controls. If the file permissions are weak or the host is shared, this can expose reusable credentials to other local users or backup/sync tooling.
"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 path returns and may print the full environment file path associated with secret storage, which can aid local reconnaissance, and the surrounding logic normalizes plaintext secret handling in .env. In the context of an unrelated statistics skill, exposing secret-storage details is unnecessary and increases risk if outputs are logged or surfaced to untrusted parties.
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'
# 日志开关
技能清单声明该技能用于调取海关进出口数据并整理企业贸易统计,但此文件实现的是向平台上报 Agent/Skill 异常信息,请求路径为 /agent/skill/error/report。该行为属于平台遥测/运维支持,而不是企业贸易统计查询或汇总,和技能对外宣称的核心功能存在明显偏离。
The skill declares capabilities that clearly involve reading environment variables, accessing local files, writing configuration, and making network calls, but it does not declare any explicit tool scope or permission boundaries. This increases the chance that an agent runtime will execute sensitive operations without clear user-visible constraints or policy enforcement.
The skill name, description, headings, examples, and operating instructions are entirely in Chinese, with no indication that users may choose another language or locale. Per the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is explicitly documented and justified.
This markdown file presents all user-facing instructions and API documentation solely in Chinese, with no indication that the skill is region-specific or that users can opt into another language. Under the language/locale policy, forcing a specific language without user choice or clear justification is a natural-language policy violation.
The documentation explicitly instructs agents to send request parameters, response data, and exception context to a remote error-reporting endpoint. Even though it states that sensitive fields are automatically redacted, it does not define what is redacted, require minimization, or warn operators that stack traces, request payloads, and response bodies may still contain personal, commercial, or secret data. In a customs/trade-statistics skill, these fields can plausibly contain company trade data, identifiers, and operational details, making unintended data disclosure a realistic privacy and confidentiality risk.
The module description and all user-facing help/messages in this file are written only in Chinese, which imposes a specific language on users without any opt-in or alternative locale support. Under the policy, language-specific behavior is a violation unless the skill offers a choice or clearly justifies the locale restriction.
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 script exposes recharge-order and pricing operations in a skill meant for customs company statistics, creating unjustified financial functionality. Even without direct code injection, this broadens the attack surface and can lead to unexpected charges or abuse if the skill is invoked in an automated agent context.
This code file contains natural-language documentation and user-facing output in Chinese, beginning with the module docstring, and the pattern continues throughout the file. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is clearly documented and justified, which is not present here.
Detected: suspicious.exposed_secret_literal