T09 · Insecure Skill Coding Practices
- Location
scripts/auth.py:18- Finding
API Key Disclosure and Insecure Credential Storage
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill mostly matches its stated people-search purpose, but it handles paid API credentials, payment/order flows, hidden version checks, and retained contact-search results in ways users should review before installing.
Install only if you are comfortable giving this skill access to an UpKuaJing API key and using it for paid people-search requests. Avoid displaying the .env file contents, restrict permissions on ~/.upkuajing and saved task data, delete retained result files when no longer needed, and confirm any fee-incurring or top-up operation before it runs.
scripts/auth.py:18API Key Disclosure and Insecure Credential Storage
scripts/common.py:421Personal-Data Search Results Persist Without Explicit Access Controls or Retention
requirements.txt:1Third-Party Dependency Is Not Reproducibly Pinned
The skill also appears to perform version/update checks, local metadata reads, and cache writes in the user's home directory, none of which are disclosed in the primary purpose. Hidden update-check behavior expands the trust boundary and can create privacy leakage or unexpected filesystem changes unrelated to the user's search request.
The skill also appears to perform version/update checks, local metadata reads, and cache writes in the user's home directory, none of which are disclosed in the primary purpose. Hidden update-check behavior expands the trust boundary and can create privacy leakage or unexpected filesystem changes unrelated to the user's search request.
The skill also appears to perform version/update checks, local metadata reads, and cache writes in the user's home directory, none of which are disclosed in the primary purpose. Hidden update-check behavior expands the trust boundary and can create privacy leakage or unexpected filesystem changes unrelated to the user's search request.
The skill instructs reading ~/.upkuajing/.env directly and even shows cat ~/.upkuajing/.env, which can expose the full API key to the agent or to logs/output if mishandled. Credential access is especially dangerous here because the same skill also supports network actions, account operations, and billable API usage, creating a realistic path from secret retrieval to misuse.
This skill requires an API key. The API key is stored in the ~/.upkuajing/.env file:
cat ~/.upkuajing/.env
Example file content:
The documented flow tells the agent to check the local env file for UPKUAJING_API_KEY and, if absent, guide manual insertion or create a new key automatically saved to disk. This combines credential discovery, credential creation, and persistent local storage in a skill whose headline function is search, greatly expanding the blast radius if the skill is over-invoked or abused.
### **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 to ~/.upkuajing/.env encourages plaintext secret persistence in a predictable filesystem location. In the context of a network-enabled, file-capable agent skill, predictable local secret storage materially raises the risk of later disclosure, reuse, or unauthorized billing/account access.
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():
The code reads an existing .env file and parses out an API key, then later includes a prefix of that key in a user-visible message. Accessing and partially disclosing stored credentials increases exposure risk, especially on shared terminals, logs, screenshots, or support transcripts. In the context of a personnel-search skill, this is more dangerous because credential handling is ancillary to the core function and broadens sensitive-data processing unnecessarily.
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 the API key in plaintext to a .env file under the user's home directory. Plaintext local secret storage is vulnerable to disclosure via weak file permissions, backups, other local processes, accidental commits, or operator mishandling. Because this skill also exposes account and billing functions, compromise of the key could enable unauthorized use and financial 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'
# 日志开关
The skill declares no explicit tool scope or permission boundaries even though its documented behavior includes reading environment variables, accessing local files, writing to user directories, and making network requests. Without an allowlist, an agent may invoke broader capabilities than users expect, increasing the risk of unauthorized credential access, data exfiltration, or unintended side effects.
The manifest description lists trigger phrases such as "find international business contacts" and "contact-data enrichment," which are broad natural-language requests rather than specific invocation commands. The file does not provide exclusion conditions or negative examples, so the activation boundary is unclear and may cause unintended invocation for ordinary user requests in adjacent domains.
The skill markets person/contact-data enrichment without a clear privacy notice, retention disclosure, or warning about handling personal/business contact data. In this context, the absence of a privacy warning is more concerning because the skill is explicitly designed for recruitment and lead generation, where personal data misuse and compliance violations are realistic risks.
The API reference explicitly supports filtering for the existence of phone numbers, WhatsApp, email, websites, and social accounts for identified individuals, but provides no privacy, lawful-basis, or acceptable-use constraints. In the context of head-hunting and overseas sales-lead development, this materially enables targeted collection and prioritization of personal contact data for outreach, increasing risk of privacy violations, spam, and misuse of personal data across jurisdictions.
The returned profile fields include sensitive or privacy-relevant personal attributes such as name, country, gender, title/level, industries, contact-count indicators, and profile linkage metadata, yet the reference omits any warning about sensitive-data handling. Because the skill is specifically marketed for executive head-hunting and cross-border lead enrichment, the absence of safeguards makes profiling, discrimination, and privacy-invasive targeting more dangerous.
The file adds API-key provisioning, account lookup, pricing, and recharge/billing flows to a skill whose stated purpose is personnel search and contact enrichment. Capability expansion beyond the declared use case increases attack surface and can surprise operators by introducing credential and payment operations that are not necessary for simple lookup behavior.
The explicit unsafe default require_auth=False for key creation weakens trust boundaries and normalizes bypass of authentication for a sensitive operation. Even if intended for self-service onboarding, making the default unauthenticated increases the chance of backend misuse, mass registration, or future copy/paste of the pattern into more sensitive calls.
pass # 如果读取失败,继续执行
# 不需要认证申请新密钥
response = make_request('/agent/auth/create', {}, require_auth=False)
# 检查是否申请成功
if response.get('code') != 0:
The explicit unsafe default require_auth=False for key creation weakens trust boundaries and normalizes bypass of authentication for a sensitive operation. Even if intended for self-service onboarding, making the default unauthenticated increases the chance of backend misuse, mass registration, or future copy/paste of the pattern into more sensitive calls.
pass # 如果读取失败,继续执行
# 不需要认证申请新密钥
response = make_request('/agent/auth/create', {}, require_auth=False)
# 检查是否申请成功
if response.get('code') != 0:
Recharge-order creation is a payment-related capability that is not justified by the declared search/enrichment purpose. Embedding payment initiation inside the skill creates unnecessary financial-risk surface, including accidental charges, abuse of billing endpoints, and reduced reviewability of what the skill can do.
The code can log full API request and response bodies containing contact-search queries and returned personnel data to local log files. Even though logging is currently disabled by default, the feature exists and would create sensitive local artifacts if enabled, which is risky for a skill explicitly handling business-contact enrichment and executive search data.
The utility layer persists task metadata and search results to local files under the skill directory, which exceeds the manifest’s visible search/enrichment behavior and can retain sensitive personnel data longer than users expect. In a head-hunting/contact-enrichment context, stored result sets may include personal and business profile data, increasing privacy, compliance, and data-retention risk if the host is shared or compromised.
Detected: suspicious.exposed_secret_literal