T09 · Insecure Skill Coding Practices
- Location
SKILL.md:38- Finding
API Key Exposure Through Credential File Display Instructions
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill appears to be a legitimate paid company-shareholder lookup tool, but it handles API credentials in ways that can expose or persist secrets unsafely.
Review before installing. Use this skill only if you trust the Upkuajing service and are comfortable with paid API calls. Do not run commands that print `~/.upkuajing/.env`; configure the key through a safer secret mechanism or verify only that it exists. If using file storage, restrict `~/.upkuajing` and `.env` to owner-only permissions, and explicitly confirm any billable query, key creation, recharge-order creation, or error report.
SKILL.md:38API Key Exposure Through Credential File Display Instructions
scripts/auth.py:67Credential File Created Without Explicit Restrictive Permissions
requirements.txt:1Unbounded and Unpinned Third-Party HTTP Dependency
The declared purpose is shareholder and beneficial-owner lookup, but the skill also includes API key issuance, local secret storage, account information access, recharge order creation, and pricing queries. This expands the trust boundary far beyond the advertised business function, increasing the chance of unexpected charges, credential handling, and privileged account actions under a misleading description.
The declared purpose is shareholder and beneficial-owner lookup, but the skill also includes API key issuance, local secret storage, account information access, recharge order creation, and pricing queries. This expands the trust boundary far beyond the advertised business function, increasing the chance of unexpected charges, credential handling, and privileged account actions under a misleading description.
The declared purpose is shareholder and beneficial-owner lookup, but the skill also includes API key issuance, local secret storage, account information access, recharge order creation, and pricing queries. This expands the trust boundary far beyond the advertised business function, increasing the chance of unexpected charges, credential handling, and privileged account actions under a misleading description.
The skill explicitly instructs the agent to display the contents of ~/.upkuajing/.env with cat, which can reveal the API key in plaintext. Exposing secrets in chat or logs enables credential theft, unauthorized API use, account abuse, and downstream billing or data-access compromise.
This finding is a true credential-access issue because the skill directs access to a local .env file storing UPKUAJING_API_KEY. Accessing secret material from a home-directory file materially increases the risk of disclosure through agent output, logs, or misuse by other instructions.
使用此技能需要API密钥。API密钥保存在 ~/.upkuajing/.env 文件中:
cat ~/.upkuajing/.env
文件内容示例:
The skill instructs checking a local secret file for the API key and then potentially initiating key-management flows. Even if the intent is setup assistance, combining local secret inspection with credential lifecycle actions broadens exposure and can lead to accidental disclosure or unauthorized provisioning.
### **未设置API密钥**
请先检查 `~/.upkuajing/.env` 文件是否有 UPKUAJING_API_KEY;
如果未设置 UPKUAJING_API_KEY API密钥,请提示并让用户选择:
1. 用户有,由用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有,你可使用接口进行申请(`auth.py --new_key`),申请到新密钥后,会自动保存到 ~/.upkuajing/.env
等待用户选择;
The instruction to apply for a new API key and automatically save it into ~/.upkuajing/.env introduces credential creation and local persistence in a skill that is presented as a data-query tool. That increases the blast radius if the environment is compromised and creates opportunities for silent credential issuance or misuse if user consent boundaries are unclear.
请先检查 `~/.upkuajing/.env` 文件是否有 UPKUAJING_API_KEY;
如果未设置 UPKUAJING_API_KEY API密钥,请提示并让用户选择:
1. 用户有,由用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有,你可使用接口进行申请(`auth.py --new_key`),申请到新密钥后,会自动保存到 ~/.upkuajing/.env
等待用户选择;
### **账户充值**
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 code writes a newly issued API key into a plaintext .env file under the user’s home/application directory without setting restrictive permissions. If the file is readable by other local users, included in backups, or accidentally exposed, the API key can be stolen and used to access the associated account or consume paid API balance.
"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 skill declares capabilities that imply reading secrets, writing local files, and making network requests, but it does not explicitly constrain or disclose tool scope via permissions or allowed-tools. This weakens least-privilege boundaries and makes it harder to reason about or enforce what the skill is allowed to do, especially because the skill also references credential files and external API operations.
The skill description and all operational instructions are written entirely in Chinese, and the skill name is suffixed with 'zh', indicating a fixed language/locale behavior. There is no statement offering the user a language choice or documenting that the language restriction is required for a specific compliance or regional context.
The API documentation explicitly encourages sending request parameters, response payloads, and exception context to a central error-reporting endpoint. Even though it says sensitive fields will be automatically masked, it does not define the masking scope or require callers to minimize data before submission, creating a real risk of leaking personal, commercial, or authentication-related data through logs and diagnostics. In this skill’s context, the system handles corporate ownership and beneficial-owner information, so exception traces and payloads may contain sensitive investigative or regulated data, making the telemetry channel more dangerous.
The module docstring and user-facing descriptions are written entirely in Chinese, and the CLI help/messages continue this pattern throughout the file. Under the policy, forcing a specific language without user opt-in or justification is a natural-language policy violation.
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:
This code file contains natural-language documentation and operational messages entirely in Chinese, starting with the module docstring and continuing throughout user-visible output. Under the policy, forcing a specific language without user opt-in or a documented regional justification is a natural-language policy violation.
技能描述聚焦于调取企业资料库、查询股东和实际受益所有人并梳理股权关系,但这一段代码额外实现了任务ID生成、任务目录管理、元数据保存和结果追加写入等本地持久化能力。虽然辅助缓存并非一定异常,但清单并未表明该技能会在本地创建和维护任务数据,因此行为范围明显宽于所宣称的查询分析功能。
The file docstring and implementation show that it reports invocation exceptions via '/agent/skill/error/report' and handles report IDs, rather than querying enterprise/shareholder/beneficial-owner data or analyzing ownership structures. This is a semantic mismatch between the skill's advertised function and actual implemented behavior in this file.
The manifest describes a skill for querying global company shareholder information, beneficial owners, and ownership/investment relationships. This file instead collects runtime error context and sends it to a platform error-reporting endpoint, which is an operational telemetry capability rather than a direct requirement of the stated business purpose.