T09 · Insecure Skill Coding Practices
- Location
SKILL.md:39- Finding
API Credential Exposure Through Unsafe Documentation and File Permissions
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill performs the advertised LinkedIn work-history lookup, but it also handles API-key storage, account/payment flows, error reporting, and automatic version checks in ways users should review carefully before installing.
Install only if you are comfortable giving this skill an Upkuajing API key, using a paid external API, and potentially creating recharge/payment URLs through its helper script. Do not print or paste the contents of ~/.upkuajing/.env into chats or logs; prefer a scoped environment variable or a securely permissioned credential file. Review any error report before sending because it may include request, response, or context data.
SKILL.md:39API Credential Exposure Through Unsafe Documentation and File Permissions
requirements.txt:1Unbounded Dependency Version Permits Unreviewed Package Updates
The findings indicate additional undeclared behaviors such as version checks, cache reads/writes, and remote update queries that are outside the stated purpose of retrieving work-experience data. Hidden local persistence and update checks increase exposure to privacy leaks and supply-chain style risks because user queries and metadata may be stored or transmitted under the guise of a simple lookup skill.
The findings indicate additional undeclared behaviors such as version checks, cache reads/writes, and remote update queries that are outside the stated purpose of retrieving work-experience data. Hidden local persistence and update checks increase exposure to privacy leaks and supply-chain style risks because user queries and metadata may be stored or transmitted under the guise of a simple lookup skill.
The findings indicate additional undeclared behaviors such as version checks, cache reads/writes, and remote update queries that are outside the stated purpose of retrieving work-experience data. Hidden local persistence and update checks increase exposure to privacy leaks and supply-chain style risks because user queries and metadata may be stored or transmitted under the guise of a simple lookup skill.
The findings indicate additional undeclared behaviors such as version checks, cache reads/writes, and remote update queries that are outside the stated purpose of retrieving work-experience data. Hidden local persistence and update checks increase exposure to privacy leaks and supply-chain style risks because user queries and metadata may be stored or transmitted under the guise of a simple lookup skill.
The skill instructs reading ~/.upkuajing/.env directly to access the API key, which is a credential-access pattern. In context this is especially sensitive because the same skill also includes network and account-management operations, so exposing or mishandling that secret could enable unauthorized third-party API use, billing abuse, or further account compromise.
使用此技能需要API密钥。API密钥保存在 ~/.upkuajing/.env 文件中:
cat ~/.upkuajing/.env
文件内容示例:
The skill explicitly tells the agent to check the .env file for UPKUAJING_API_KEY, which promotes direct access to stored secrets. This is dangerous because agents may surface file contents, mishandle the key, or normalize credential-file inspection for a task that should only need a pre-provisioned secret at execution time.
### **未设置API密钥**
请先检查 `~/.upkuajing/.env` 文件是否有 UPKUAJING_API_KEY;
如果未设置 UPKUAJING_API_KEY API密钥,请提示并让用户选择:
1. 用户有,由用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有,你可使用接口进行申请(`auth.py --new_key`),申请到新密钥后,会自动保存到 ~/.upkuajing/.env
等待用户选择;
The instruction to request a new API key and automatically save it into ~/.upkuajing/.env combines credential generation with plaintext local storage. This increases the chance of secret leakage through file access, backups, logs, or later unrelated tasks, and it extends the skill’s power well beyond a simple profile-query tool.
请先检查 `~/.upkuajing/.env` 文件是否有 UPKUAJING_API_KEY;
如果未设置 UPKUAJING_API_KEY API密钥,请提示并让用户选择:
1. 用户有,由用户提供(手动添加到 ~/.upkuajing/.env 文件)
2. 用户没有,你可使用接口进行申请(`auth.py --new_key`),申请到新密钥后,会自动保存到 ~/.upkuajing/.env
等待用户选择;
### **账户充值**
The file implements authentication, account balance lookup, recharge ordering, and pricing queries for an unrelated third-party platform, which materially diverges from the declared skill purpose of retrieving LinkedIn work-history information. This kind of capability mismatch is dangerous because it expands the skill's privilege and business scope, may trick users into provisioning credentials or funds, and can conceal unauthorized monetization or data-access behavior behind a benign-looking skill description.
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 script writes a newly issued API key into a .env file without any visible permission hardening or use of a secure secret store. In a multi-user or poorly configured environment, plaintext secret storage can allow local disclosure of the credential, enabling unauthorized API use and possible billing 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")
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'
# 日志开关
技能清单描述其用途是获取并梳理 LinkedIn 用户任职履历,用于背景分析;但此文件实际将调用异常及上下文信息上报到平台接口。异常遥测/上报并非该业务能力的直接组成部分,属于与声明目的明显不同的行为。
The skill declares capabilities that imply reading environment variables, reading/writing local files, and making network requests, but it does not constrain or document tool scope with an explicit allowlist. In a skill that also handles API keys and payment-related flows, missing scope boundaries increases the chance that an agent could access sensitive local data or perform unintended remote actions beyond the user’s expectation.
The skill description is entirely presented in Chinese and the skill name suffix -zh suggests a Chinese-only locale expectation, but the document does not state that language choice is optional or limited to a justified region-specific context. Under the policy, forcing a specific language without user opt-in is a natural-language policy concern.
The skill documentation mixes identity-data lookup with account administration, billing, and exception escalation flows. This violates separation of duties and makes the skill more dangerous in context, because a user seeking profile data could be steered into credential, account, or spending operations through the same trust channel.
Allowing the skill to apply for a new API key and save it locally expands it from a query tool into a credential-lifecycle manager. In context, this is more dangerous because credential issuance and storage can create unauthorized access paths, persistence of secrets on disk, and confusion about who authorized creation and use of the new key.
Creating recharge orders and directing the user to payment URLs is not necessary for a work-history lookup function and introduces financial-action capability into a data-retrieval skill. If abused or triggered unexpectedly, this could manipulate users into payments or create unwanted orders under the cover of routine profile queries.
The document explicitly instructs reporting requestParams, responseData, and context to a centralized error-reporting API, which can contain personal data, authentication artifacts, business inputs, or stack traces. Although it states sensitive fields will be automatically masked, it does not define masking scope, prohibit secrets/PII submission, or require user/operator warning and minimization, creating a realistic privacy and data-exposure risk.
The module title and user-facing descriptions are entirely in Chinese, and the CLI help/output strings throughout the file are also fixed to Chinese. This imposes a language choice on users without opt-in or any documented locale constraint, which matches the language/locale policy violation criteria.
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:
Detected: suspicious.exposed_secret_literal