T09 · Insecure Skill Coding Practices
- Location
scripts/config.py:10- Finding
API Credential Can Be Redirected to an Attacker-Controlled Endpoint
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill appears to be a real remote persona-service wrapper, but it asks users for an API key and stores it insecurely in a local plaintext .env file.
Install only if you are comfortable giving this skill a XiaoBenYang API key and having that key sent to the remote MCP service. Prefer configuring the key through a trusted secret manager or environment outside chat, ensure any .env file is private and excluded from git/backups, and avoid overriding the API base URL unless you fully trust the destination.
scripts/config.py:10API Credential Can Be Redirected to an Attacker-Controlled Endpoint
scripts/config.py:40API Key Is Persisted in a Plaintext File Without Explicit Permission Hardening
requirements.txt:1Dependencies Are Not Reproducibly Pinned
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.
The document claims to provide a multi-persona MCP collaboration service, but its structure and instructions point to unrelated high-school exam tooling and local API-key persistence. This mismatch is dangerous because it can mislead users and reviewers about what the skill really does, masking sensitive credential handling and broader capabilities not disclosed in the description.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
model_config = SettingsConfigDict(
env_prefix="XBY_GAOKAO_",
env_file=".env",
env_file_encoding="utf-8",
extra="ignore",
)
The code manually parses .env and force-loads a secret key outside the normal typed settings flow, creating a second secret-loading path that may bypass expected validation and secret-handling controls. In an agent skill context, direct local file secret access increases risk because the component is explicitly designed for multi-agent collaboration, making accidental propagation or misuse of loaded credentials more dangerous if other parts of the system can access the resulting settings object.
default_year: int = 2025
def model_post_init(self, __context):
# 强制从 .env 文件读取 XBY_APIKEY
env_path = Path(".env")
if env_path.exists():
content = env_path.read_text(encoding="utf-8")
Opening and reading the .env file directly exposes all file contents to application code, which is broader access than necessary when only one secret is needed. In a multi-persona/agent server, any later bug, debug print, exception path, or object sharing could leak secrets that were unnecessarily brought into process memory from a local credential store.
def model_post_init(self, __context):
# 强制从 .env 文件读取 XBY_APIKEY
env_path = Path(".env")
if env_path.exists():
content = env_path.read_text(encoding="utf-8")
for line in content.splitlines():
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
if line.startswith("XBY_APIKEY="):
self.api_key = line.split("=", 1)[1].strip()
break
# 如果环境变量有值,覆盖 .env 的值
env_val = os.getenv("XBY_APIKEY", "")
if env_val:
self.api_key = env_val
This function persists an API key in plaintext to a local .env file and mirrors it into process environment variables, increasing the exposure window and the number of places the secret may be recovered. In the context of an agent skill/server, storing credentials this way is more dangerous because such systems often run with plugins, shared workspaces, logs, backups, or multiple operators, any of which can lead to unauthorized secret disclosure.
def save_api_key_to_env(api_key: str) -> bool:
"""将API key保存到.env文件"""
try:
env_path = Path(".env")
lines = []
if env_path.exists():
lines = env_path.read_text(encoding="utf-8").splitlines()
The skill declares no explicit tool scope or permission boundaries despite documented capabilities that include environment access, file read/write, and network usage. In an agent setting, missing scope declarations increase the chance of over-privileged execution and make it harder for users or hosting platforms to constrain sensitive operations such as secret persistence and outbound API calls.
The skill explicitly instructs the model to ask the user for an API key and then save it locally. Normalizing conversational collection and persistence of secrets is risky because it encourages users to disclose credentials in chat and creates a local secret-storage path that may be exposed to logs, other tools, or unintended file access.
The workflow reiterates that the model must solicit and persist the user's API key before proceeding, reinforcing secret-collection behavior as a required operating pattern. Repetition increases the likelihood that agents will request credentials even in unsafe contexts and store them insecurely, broadening the chance of leakage or misuse.
The project structure and documentation reference gaokao-related modules while the skill is presented as an AI persona service. Internal contradictions like this reduce trustworthiness and can conceal unexpected behavior, making security review and safe deployment significantly harder.
L09 的类文档字符串写的是“"小笨羊高考Skill配置"”,而当前技能清单声明的名称与用途是“AI人格服务”,用于多AI人格召唤与协作。该注释不是简单遗漏,而是明确表述了一个不同的技能意图,和本文件中实际配置的远程服务/API key 逻辑一起看,会误导审计者对该技能真实目的的判断。
The class docstring is written as Chinese-only text ("小笨羊高考Skill配置"), indicating a language-specific presentation without any visible option or note allowing the user to choose another language. The policy for this audit flags natural-language locale constraints when they are imposed without opt-in or justification visible in the file.
The user-facing natural-language docstrings are written entirely in Chinese, including action descriptions and persona examples, with no indication that another language is supported or that Chinese is required for a specific regional purpose. This can violate language/locale policy because the skill presents a single forced language without opt-in or documented justification.
The dependency uses a lower-bound specifier (requests>=2.31.0) rather than an exact pinned version, which makes builds non-reproducible and can cause the environment to resolve to an unexpected or newly introduced vulnerable release. In a network-facing AI/MCP service, requests is commonly used for outbound HTTP, so supply-chain drift can affect runtime security and reliability.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
The manifest does not pin requests, and the package has multiple known advisories across versions, so it is impossible to verify from this file whether deployments are using a safe release. Given that requests is typically used for external HTTP interactions, an affected resolved version could expose credential leakage, TLS/session issues, or other client-side security weaknesses.
pydantic>=2.7.0 is unpinned, so installations may resolve to different versions over time, preventing reproducible builds and making it harder to verify whether a deployed version contains known vulnerabilities. Because pydantic processes structured input and configuration, unexpected version changes can alter validation behavior in security-relevant ways.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
Because pydantic is unpinned and has known advisories in some versions, the security posture of the installed package cannot be verified from this requirements file alone. For a service that validates untrusted input, using an affected version could lead to denial-of-service or unsafe parsing behavior.
pydantic-settings>=2.2.0 allows dependency resolution to float to newer versions without review, which creates a supply-chain and reproducibility risk. Since this package handles application settings, version drift can affect secret loading and configuration parsing in ways that may expose or mishandle sensitive data.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
The file allows any pydantic-settings version at or above 2.2.0, but known advisories exist for some releases, making the actual deployed risk unverifiable. Since this library manages settings and potentially secrets sources, a vulnerable version could impact confidentiality or integrity of configuration handling.
python-dotenv>=1.0.1 is not pinned, so future installs may pull different releases, including ones with unresolved advisories or behavior changes. In an AI service that may rely on environment-based secrets, uncontrolled upgrades to dotenv-related tooling can increase risk around configuration and secret management.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
python-dotenv has known advisories in some versions, and the unpinned requirement prevents verification that deployed environments avoid affected releases. Because dotenv tooling often reads and writes files tied to environment secrets, a vulnerable version could contribute to file overwrite or secret-handling issues depending on usage.
The class docstring is written only in Chinese, and additional user-facing exception and status messages in this file are also Chinese-only. Under the stated policy, forcing a specific language without user opt-in or documented justification is a natural-language policy violation.
The raised error message "API密钥未设置,请先调用 set_api_key()" is user-facing and provides no language choice. This violates the language/locale policy unless the skill explicitly documents that it is intended only for Chinese-language usage.
The function docstring and especially the returned message "API调用失败" are part of the user-visible interface and are hardcoded in Chinese. The policy requires either user choice of language or documented justification for a fixed locale.