T09 · Insecure Skill Coding Practices
- Location
scripts/config.py:10- Finding
Configurable API Endpoint Enables Credential and User Data Disclosure
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is an external API wrapper, but it asks for an API key, stores it in a plaintext local .env file, and can be redirected by configuration, so users should review it before installing.
Install only if you trust the Xiaobenyang service and are comfortable giving this skill an API key. Treat the key as sensitive: avoid using this in shared or synced workspaces, check whether .env could be committed or archived, and prefer a scoped or disposable key that can be rotated. Also note that the included tools.py has a syntax error, so the skill may not run as packaged.
scripts/config.py:10Configurable API Endpoint Enables Credential and User Data Disclosure
scripts/config.py:45API Key Is Persisted in a Plaintext Workspace File Without Enforced Restrictive Permissions
The skill is presented as a generic 'cognitive enhancement/MCP server' capability, but the content actually instructs the model to collect, persist, and use a third-party API key and manage local runtime configuration. This mismatch can mislead users and reviewers about the real trust boundary, causing them to approve a skill with credential-handling and local state mutation they did not expect.
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",
)
This code manually reads the .env file to extract XBY_APIKEY, bypassing a more controlled settings abstraction and directly handling secret material in plaintext. Manual secret parsing increases the chance of unsafe storage assumptions, accidental exposure, and inconsistent secret handling across the application.
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")
The explicit existence check and subsequent plaintext read of .env are part of direct credential handling logic. In the context of a skill not clearly scoped for local secret management, this makes credential exposure more dangerous because it normalizes local secret harvesting from a common file path.
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 is expressly designed to save an API key into a plaintext .env file, creating a durable local copy of a secret. Plaintext persistence materially increases the risk of credential compromise through source control mistakes, local multi-user access, backups, or later exfiltration by other software.
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 while the documented project structure and workflow imply access to environment variables, local file reads/writes, and networked API calls. In an agent setting, missing scope declarations increases the chance of overbroad tool access and unintended credential or filesystem exposure, especially because the skill also instructs persistence of an API key.
The skill name and full operating instructions are presented only in Chinese, while the embedded tool description remains in English, creating an implicit language policy that is fixed by the author rather than chosen by the user. Under the policy, forcing a specific language or locale without user opt-in is a natural-language violation.
The document claims to provide a broad set of cognitive-enhancement tools, but the operational instructions focus on a specific external service and API-key workflow. This inconsistency is risky because it obscures the actual function of the skill, making users more likely to disclose secrets or authorize behavior under false assumptions.
The skill explicitly instructs the model to request a user API key through natural-language interaction and then persist it via local configuration. This creates a sensitive-credential collection and retention flow that can expose secrets to logs, transcripts, prompt history, local files, or other tools, and it lacks any visible safeguards such as secure secret storage, masking, limited retention, or explicit consent for persistence.
This code retrieves an API key and sends it along with the provided parameters in an outbound HTTP POST request. Although errors and success are logged, there is no confirmation prompt, print statement, or explanatory comment/docstring warning users that data and credentials will be transmitted to an external service.
The module persists an API key to a local .env file and updates process environment state, which is more capability than a passive configuration helper for a cognitive-enhancement skill. Persisting secrets locally can expose credentials through weak file permissions, accidental commits, workspace sharing, or later exfiltration by other components.
The skill implements local credential persistence despite its stated purpose being cognitive tools, increasing the attack surface without clear necessity from the manifest. This mismatch matters because users may not expect the skill to write secrets to disk, reducing informed consent and making credential leakage more likely.
The function writes the provided API key to .env immediately and silently, with no user-facing warning or confirmation. Silent secret persistence is dangerous because users may believe a key is transient while it is actually stored on disk, where it can be discovered by local users, backups, logs, or accidental repository inclusion.
The dependency specification uses a lower-bound version constraint instead of pinning an exact version, which makes builds non-reproducible and can result in installation of unexpected or later vulnerable releases. In a service that provides model tooling, this increases supply-chain uncertainty even though the file itself does not prove exploitation.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
Requests has multiple known advisories, and because the manifest does not pin a specific version, there is no way to verify from this file alone whether deployment will use a patched or affected release. The danger is indirect but real: an environment could resolve to a vulnerable version and expose network-facing behavior to known issues.
Using pydantic>=2.7.0 allows any newer version to be installed, preventing reproducible environments and making it unclear whether a deployed build includes a vulnerable release. This is a supply-chain hygiene weakness rather than an immediate exploit by itself.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
Pydantic has known advisories, and the absence of an exact version means the risk posture cannot be verified from the manifest. In code that parses model or user-provided data, unresolved version ambiguity can expose the service to parser or validation vulnerabilities if an affected release is installed.
The unpinned pydantic-settings dependency permits drift across environments and time, which can silently introduce vulnerable or incompatible versions. For infrastructure-facing tooling, this weakens dependency integrity and change control.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
The manifest references pydantic-settings without pinning, while advisories exist for that package, so the deployed version may be unverifiably vulnerable. Given this library often handles configuration and secrets loading, version ambiguity can matter if affected functionality is used elsewhere in the skill.
python-dotenv>=1.0.1 does not constrain the installed release to a specific vetted version, so builds may resolve to different packages over time, including potentially vulnerable ones. This is especially relevant for configuration-loading libraries that may touch sensitive files and environment values.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
python-dotenv has known advisories and is not version-pinned, so the environment may install an affected release without visibility in the manifest. Because dotenv tooling can read or modify configuration files, using an unverifiable version increases the chance of file-handling or configuration-related security issues.
The class and function docstrings and error text are written only in Chinese, which imposes a specific language on users without any visible opt-in or alternative. Under the language/locale policy, locale constraints should either be optional, justified, or offer user choice.
The file's human-facing docstrings and status/error text are written only in Chinese, such as the configuration description and failure message. This can amount to a language-policy issue when the skill does not offer any language choice or document that it is intentionally limited to a Chinese-speaking context.
L31 注释描述为“强制从 .env 文件读取 XBY_APIKEY”,但类配置在 L12 指定 env_prefix 为 XBY_GAOKAO_,而手工读取与覆盖逻辑使用的是不同名称 XBY_APIKEY。该注释会让读者误以为配置来源和键名与设置体系一致,实际代码却绕过了声明的设置约定。