T09 · Insecure Skill Coding Practices
- Location
SKILL.md:65- Finding
API Key Exposed Through a Documented Credential-File Display Command
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill mostly matches its trade-data purpose, but it handles API keys and local persistence in ways users should review carefully before installing.
Install only if you are comfortable with a paid remote API service storing an API key in a plaintext home-directory file and persisting search results locally. Do not run the documented `cat ~/.upkuajing/.env` command or share its output; use a non-disclosing presence check instead, lock down file permissions, and rotate the API key if it was printed into a transcript or logs.
SKILL.md:65API Key Exposed Through a Documented Credential-File Display Command
scripts/auth.py:63API Key File Is Created Without Explicit Restrictive Permissions
requirements.txt:1Third-Party HTTP Dependency Is Not Reproducibly Pinned
If the skill performs remote version checks, parses local metadata, and reads or writes cache files unrelated to trade search, those behaviors exceed the documented business purpose and introduce additional hidden network and filesystem activity. Undisclosed auxiliary behaviors are dangerous because they can enable tracking, unexpected data persistence, or covert update logic outside the user's expectations.
If the skill performs remote version checks, parses local metadata, and reads or writes cache files unrelated to trade search, those behaviors exceed the documented business purpose and introduce additional hidden network and filesystem activity. Undisclosed auxiliary behaviors are dangerous because they can enable tracking, unexpected data persistence, or covert update logic outside the user's expectations.
The skill instructs reading a local credential file at ~/.upkuajing/.env, which contains the API key, and even shows a command to print the file contents. Directly exposing or encouraging access to raw secret storage is dangerous because it can leak credentials into logs, transcripts, or downstream tools, enabling unauthorized API use and account abuse.
This skill requires an API key. The API key is stored in the ~/.upkuajing/.env file:
cat ~/.upkuajing/.env
Example file content:
The workflow explicitly checks the local ~/.upkuajing/.env for UPKUAJING_API_KEY and directs users to add credentials there or create a new key that will be automatically saved. This normalizes local secret-file handling by the skill and increases the risk of credential exposure, insecure storage, and accidental persistence beyond user intent.
### **API Key Not Set**
First check if the `~/.upkuajing/.env` file has UPKUAJING_API_KEY;
If UPKUAJING_API_KEY is not set, prompt the user to choose:
1. User has one: User provides it (manually add to ~/.upkuajing/.env file)
2. User doesn't have one: You can apply using the interface (`auth.py --new_key`), the new key will be automatically saved to ~/.upkuajing/.env
Wait for user selection;
Automatically saving newly created API keys into ~/.upkuajing/.env creates a persistent local secret that may be readable by other processes, backed up unintentionally, or exposed through future file-inspection steps. In a skill that also performs network and account operations, this materially increases the blast radius of a compromise.
First check if the `~/.upkuajing/.env` file has UPKUAJING_API_KEY;
If UPKUAJING_API_KEY is not set, prompt the user to choose:
1. User has one: User provides it (manually add to ~/.upkuajing/.env file)
2. User doesn't have one: You can apply using the interface (`auth.py --new_key`), the new key will be automatically saved to ~/.upkuajing/.env
Wait for user selection;
### **Account Top-up**
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 in plaintext to a .env file under the user's home directory. Storing long-lived credentials unencrypted on disk can lead to credential compromise if local permissions are weak, the file is accidentally committed, backed up insecurely, or read by other local processes.
"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 advertises executable behaviors that access environment variables, read and write local files, and make network requests, but it does not declare any explicit tool scope or permission boundaries. This creates an authorization gap where a user or platform cannot easily understand or constrain the skill's capabilities, increasing the risk of unintended credential access, filesystem modification, and remote API interaction.
The skill offers retrieval of contact information including email, phone, social media, and website data without presenting a user-facing privacy or acceptable-use warning. Because the skill is explicitly designed for lead generation and contact enrichment, the absence of privacy safeguards increases the risk of misuse, non-compliant data handling, and unwanted outreach.
The note says product names and industry names must be in English, which is a language constraint expressed in natural language. The file does not present this as an optional requirement, ask for user opt-in, or justify it as a documented technical limitation tied to a region-specific compliance need.
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('/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('/auth/create', {}, require_auth=False)
# 检查是否申请成功
if response.get('code') != 0:
This code constructs authenticated HTTP requests to an external API, including request parameters and a Bearer token derived from local credentials, but provides no user-facing notice at the point of transmission. While the function has an internal docstring, there is no confirmation prompt or visible disclosure to the user that data will be sent off-system.
This code file sends company identifiers to an external API endpoint to retrieve contact details, which can involve handling and transmitting potentially sensitive business contact data. Although the module and function docstrings describe the purpose, there is no explicit user-facing warning, confirmation, or disclosure at the point of execution about the network transmission of this data.
This Python skill presents its description, argument help, progress messages, and error output entirely in Chinese, beginning with the module docstring and continuing throughout the CLI interface. Under the language/locale policy rule, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified.
The script persists retrieved trade records to a task result file via append_result_data() and later exposes the file path/URL through get_task_result_file(task_id), but it does not provide any explicit warning, consent flow, retention policy, or access-control indication for this local persistence. Because the data described by the skill includes trade order details and business contact information, silent storage increases the risk of unintended disclosure, over-retention, or access by other local users/processes.
The module docstring and later user-facing notice text are written only in Chinese, indicating the skill's user communication is fixed to a specific language. Under the policy, forcing a specific language without user opt-in or documented regional justification is a natural-language policy violation.
The workflow and decision guide map general requests like "Find companies purchasing XXX" and "Get contact information" directly to this skill, but do not define boundaries or exclusion conditions for when another company-search or contact-related skill should be used instead. In a markdown skill description, this kind of broad trigger guidance can contribute to unintended invocation because the activation scope is not narrowly constrained.
This markdown file presents the skill documentation entirely in Chinese and does not indicate that users may choose another language or that the locale restriction is required for a region-specific purpose. Under the policy, forcing a specific language without user opt-in is a natural-language policy concern.
No suspicious patterns detected.