T09 · Insecure Skill Coding Practices
- Location
SKILL.md:38- Finding
Credential Disclosure Through Documented File Printing
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill mostly matches a paid employee-lookup service, but it exposes API-key handling and billing workflows in ways users should review carefully before installing.
Install only if you are comfortable with a paid third-party API skill that can use and store an UPKUAJING API key, create recharge payment links, and send confirmed error reports. Do not let the agent print your .env file; prefer setting the API key through a secure environment or secret manager, and review payment/order actions before approving them.
SKILL.md:38Credential Disclosure Through Documented File Printing
scripts/auth.py:63API Key File Is Created Without Explicitly Restrictive Permissions
requirements.txt:1Unbounded Third-Party Dependency Permits Unreviewed Future Releases
scripts/common.py:199Automatic Version Check Sends Skill Identity and Writes Persistent Cache Without Documentation
The advertised purpose is employee lookup, but the skill also includes API-key provisioning, local secret persistence, account inspection, billing flows, and payment-order creation. This mismatch is dangerous because users may consent to a data lookup skill without realizing it can trigger account-affecting and credential-management operations.
The advertised purpose is employee lookup, but the skill also includes API-key provisioning, local secret persistence, account inspection, billing flows, and payment-order creation. This mismatch is dangerous because users may consent to a data lookup skill without realizing it can trigger account-affecting and credential-management operations.
The advertised purpose is employee lookup, but the skill also includes API-key provisioning, local secret persistence, account inspection, billing flows, and payment-order creation. This mismatch is dangerous because users may consent to a data lookup skill without realizing it can trigger account-affecting and credential-management operations.
The advertised purpose is employee lookup, but the skill also includes API-key provisioning, local secret persistence, account inspection, billing flows, and payment-order creation. This mismatch is dangerous because users may consent to a data lookup skill without realizing it can trigger account-affecting and credential-management operations.
The skill explicitly instructs reading a local credential file with a shell command, exposing the API key stored in ~/.upkuajing/.env. Directly surfacing secrets from local files is dangerous because it normalizes credential disclosure and creates a clear path to accidental exfiltration or misuse by the skill runtime or downstream outputs.
使用此技能需要API密钥。API密钥保存在 ~/.upkuajing/.env 文件中:
cat ~/.upkuajing/.env
文件内容示例:
The skill directs the system to inspect a local .env file for the API key and to write newly issued credentials there automatically. Reading and writing secrets in a plain-text local file increases exposure risk, especially in agent environments where file access may be broader than the user expects.
### **未设置API密钥**
请先检查 `~/.upkuajing/.env` 文件是否有 UPKUAJING_API_KEY;
如果未设置 UPKUAJING_API_KEY API密钥,请提示并让用户选择:
1. 用户有,由用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有,你可使用接口进行申请(`auth.py --new_key`),申请到新密钥后,会自动保存到 ~/.upkuajing/.env
等待用户选择;
Automatically applying for a new API key and saving it to ~/.upkuajing/.env combines credential creation with local secret persistence, which can lead to unreviewed account changes and secret sprawl. In the context of a skill advertised for employee lookup, this makes the behavior more dangerous because users may not anticipate credential lifecycle operations at all.
请先检查 `~/.upkuajing/.env` 文件是否有 UPKUAJING_API_KEY;
如果未设置 UPKUAJING_API_KEY API密钥,请提示并让用户选择:
1. 用户有,由用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有,你可使用接口进行申请(`auth.py --new_key`),申请到新密钥后,会自动保存到 ~/.upkuajing/.env
等待用户选择;
### **账户充值**
The file is an authentication and billing management script that can create API keys, query balances, create recharge orders, and fetch pricing, which materially exceeds the declared skill purpose of employee/headcount lookup. In an agent skill context, hidden or unnecessary account-management capabilities increase attack surface and can enable unintended financial or credential-related actions if exposed to users or chained by other components.
The script deliberately checks for and manages API credentials in a .env file under the user’s home directory. Storing long-lived secrets in plaintext local files increases exposure to local compromise, accidental inclusion in backups, or leakage through permissive file permissions; in this skill, that risk is more concerning because credential management is unrelated to the declared employee-lookup function.
"""
申请新的 API 密钥。
"""
# 检查是否已存在 .env 文件和 API key
env_file = UPKUAJING_ENV_FILE
if env_file.exists():
Reading an existing .env to retrieve API-key material is credential-handling behavior that expands the skill’s access to secrets. Although the code only checks for presence, it still processes plaintext secret data from disk, which is risky when bundled into a skill whose stated purpose is unrelated to authentication or secret management.
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 to a .env file in plaintext. Plaintext persistence of active API credentials can lead to credential theft through local malware, shared environments, misconfigured permissions, or accidental syncing/logging, enabling unauthorized API use and account abuse.
"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 new_rec_order() function creates recharge/payment orders even though the skill is described as an employee information lookup tool. Payment initiation is a sensitive financial capability; when embedded in an unrelated skill, it creates unjustified risk of abuse, deceptive functionality, or accidental charges.
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'
# 日志开关
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def load_env_file() -> Dict[str, str]:
"""
从 ~/.upkuajing/.env 文件加载环境变量。
Returns:
环境变量字典
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def load_env_file() -> Dict[str, str]:
"""
从 ~/.upkuajing/.env 文件加载环境变量。
Returns:
环境变量字典
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def load_env_file() -> Dict[str, str]:
"""
从 ~/.upkuajing/.env 文件加载环境变量。
Returns:
环境变量字典
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def load_env_file() -> Dict[str, str]:
"""
从 ~/.upkuajing/.env 文件加载环境变量。
Returns:
环境变量字典
The skill declares executable behavior that can read environment variables, read/write local files, and access the network, yet it provides no explicit tool-scope or permission boundary. That omission increases the blast radius of misuse because a consumer cannot easily tell that credential files, local state, and remote endpoints may all be touched during normal operation.
The skill description is written as a Chinese-only audience/purpose statement and the file provides no option for the user to choose another language or locale. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is clearly documented and justified.
The document explicitly allows sending request parameters, response data, and error context to a remote error-reporting API. Even though it says sensitive fields will be desensitized automatically, it provides no concrete data-handling limits, user warning, consent flow, or guarantee that all secrets, personal data, and business-sensitive content will be removed before transmission. In the context of a skill that processes employee and company information, diagnostic payloads may contain personal or confidential data, making off-box reporting a real privacy and data-exposure risk.
This code file contains user-facing natural-language descriptions and help text that assume Chinese-only usage. Under the policy, forcing a specific language without user opt-in 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:
Account balance and platform pricing queries are not aligned with the stated purpose of enumerating employees and org structure. While less severe than payment creation, these functions expose financial/account metadata that can aid reconnaissance about the tenant’s usage, credits, or monetization setup.
The argparse description, option help text, and printed status/error messages are all in Chinese, with no language selection mechanism. This enforces a single language for user interaction and does not offer a choice or explain a necessary locale constraint.