T09 · Insecure Skill Coding Practices
- Location
scripts/auth.py:62- Finding
API Key Stored Without Enforced Restrictive File Permissions
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill appears to perform paid LinkedIn people search as described, but it needs review because it handles API keys unsafely and processes sensitive people/contact data.
Review before installing. Only use this skill if you trust UpKuaJing with your searches and account data, understand that API calls may incur fees, and have a lawful basis for processing LinkedIn-derived people/contact data. Do not print or paste `~/.upkuajing/.env`; prefer a protected environment variable or secret store, and if using the file, restrict `~/.upkuajing` and `.env` to owner-only permissions. Avoid sending raw request parameters, responses, profile data, or credentials in error reports.
scripts/auth.py:62API Key Stored Without Enforced Restrictive File Permissions
SKILL.md:37Documentation Instructs the Agent to Print the Credential File
requirements.txt:1Unbounded Third-Party Dependency Version
The documented purpose does not mention remote version checks, local metadata parsing, or version cache file reads/writes. These undeclared behaviors expand the attack surface and can surprise users or reviewers, especially when combined with network and filesystem access.
The documented purpose does not mention remote version checks, local metadata parsing, or version cache file reads/writes. These undeclared behaviors expand the attack surface and can surprise users or reviewers, especially when combined with network and filesystem access.
The documented purpose does not mention remote version checks, local metadata parsing, or version cache file reads/writes. These undeclared behaviors expand the attack surface and can surprise users or reviewers, especially when combined with network and filesystem access.
The documented purpose does not mention remote version checks, local metadata parsing, or version cache file reads/writes. These undeclared behaviors expand the attack surface and can surprise users or reviewers, especially when combined with network and filesystem access.
The skill instructs reading ~/.upkuajing/.env directly, including an example using cat, which can expose the full API key value to the agent, logs, or user-visible output. Credential material should not be displayed or broadly read unless strictly necessary, because compromise of the API key can enable unauthorized use, billing abuse, and access to associated account functions.
This skill requires an API key. The API key is stored in the ~/.upkuajing/.env file:
cat ~/.upkuajing/.env
Example file content:
The workflow directs checking the user's ~/.upkuajing/.env and potentially writing a provided or newly created API key there. This creates a direct credential-handling path in a skill whose main advertised function is search, increasing the risk of secret exposure, accidental overwrite, insecure storage, or misuse of billing-enabled credentials.
### **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 a newly applied API key into ~/.upkuajing/.env couples network-based key issuance with local plaintext credential persistence. In the context of a lead-generation/search skill, this is more dangerous because users may not expect credential enrollment and local secret storage as part of ordinary search operations.
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**
The file implements API-key issuance, account lookup, pricing, and recharge flows for a third-party service, which is materially unrelated to the declared LinkedIn people-search purpose. In a skill presented as lead-search/headhunting functionality, this mismatch is dangerous because it can conceal undisclosed monetization, account-linking, or external platform dependency that users did not consent to.
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():
Writing an API key in plain text to a .env file under the user's home directory creates a local secret-exposure risk if file permissions are weak, backups are shared, or other processes/users can read the file. In combination with an unrelated skill context, this undisclosed credential persistence increases the risk of hidden long-lived access to an external platform.
"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'
# 日志开关
This script reports execution metadata and arbitrary error context to a remote platform endpoint, and that behavior is unrelated to the declared LinkedIn person-search purpose of the skill. In a lead-generation/headhunting context, the reported request identifiers, paths, and context may contain sensitive operational data or user/business information, creating an unnecessary data-exfiltration channel.
The skill declares executable behaviors involving environment access, local file reads/writes, and network use, but does not declare any tool scope or permission boundaries. That makes the effective trust boundary opaque, increasing the chance of unintended credential access, filesystem interaction, or outbound requests without clear review or runtime restriction.
The trigger list is broad and includes generic lead-generation and targeting phrases that could invoke the skill in contexts broader than the user intended. Because the skill can touch credentials, billing flows, and external APIs, accidental invocation has more consequence than a purely informational tool.
The instruction says industry names must be in English, which is a language constraint presented as a requirement rather than a user choice. There is no opt-in, alternative language handling, or documented justification for forcing English input in this skill description.
The notes section repeats that industry names must be in English, again imposing a specific language requirement without offering the user a choice or documenting a justified regional limitation. This is a natural-language policy issue because it constrains user language unexpectedly.
The API reference explicitly supports filtering for the existence of phone numbers, WhatsApp, email, websites, and social accounts, which enables targeted discovery of individuals with reachable contact data. In the stated context of headhunting, lead generation, and contact-data enrichment, exposing this capability without any privacy, lawful-basis, anti-spam, or sensitive-data handling guidance materially increases the risk of misuse for unsolicited outreach, scraping, profiling, or privacy-invasive targeting.
The documented response fields include demographic and person-profile attributes such as gender, country, job titles, industries, work-history counts, and multiple contact-signal indicators. Providing these profiling attributes in a people-search skill for global lead generation and executive targeting, without any warning about sensitivity, discrimination risk, or appropriate use, creates a meaningful risk of invasive profiling, biased targeting, and privacy harm.
The document explicitly encourages sending request parameters, response payloads, and exception context to an error-reporting endpoint, and although it mentions automatic masking of sensitive fields, it does not define what is masked or require minimization before transmission. In a lead-generation/headhunting skill that may process personal and contact data, this can result in unintended disclosure of personal data, tokens, query terms, or internal error details to logging infrastructure without clear user awareness or strict scoping.
The file’s user-facing description and CLI help/messages are entirely in Chinese, indicating the skill is designed to operate in a single language. Under the policy, forcing a specific language without user opt-in is a natural-language policy concern unless the locale restriction is explicitly justified.