T09 · Insecure Skill Coding Practices
- Location
scripts/config.py:10- Finding
API Credential and User Query Data Can Be Redirected to an Arbitrary Endpoint
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill appears to fetch Kubernetes runbooks through an external API, but its mismatched Gaokao/XBY code and plaintext API-key handling need review before installation.
Review this before installing. Only use a low-scope Xiaobenyang API key, do not run it in a repository where .env may be committed or shared, verify the API endpoint is the intended HTTPS host, and prefer a version that removes the Gaokao/XBY mismatch, avoids plaintext credential persistence, validates outbound destinations, and pins dependencies.
scripts/config.py:10API Credential and User Query Data Can Be Redirected to an Arbitrary Endpoint
scripts/config.py:42API Key Is Persisted in a Plaintext File Without Restrictive Permission Controls
requirements.txt:1Open-Ended Dependency Constraints Make Builds Non-Reproducible
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.
The documented purpose is Kubernetes runbook access, but the described behavior includes local .env persistence, API-key management, and references to an unrelated Gaokao/XBY service. This mismatch is dangerous because users and reviewers may grant trust and permissions based on the stated purpose while the skill handles secrets and potentially communicates with an unrelated external service.
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 forcibly reads XBY_APIKEY from .env during initialization, explicitly harvesting a credential from local storage for an unrelated external service. In the context of a purported Kubernetes handbook skill, this unexplained secret collection is more dangerous because it violates expected scope and can enable unauthorized outbound service use.
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 opening and parsing of .env is part of the secret-collection path and contributes to plaintext credential exposure. Manual parsing bypasses safer abstractions, increases the chance of mishandling, and normalizes reading local secrets for a service whose purpose does not match the advertised skill.
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 API keys to .env, creating a durable plaintext secret store and modifying process environment state. Because the skill claims to provide Kubernetes troubleshooting handbook access, secret persistence for an unrelated external service is especially risky: users may unknowingly entrust credentials to code outside the advertised scope, and those credentials may later be exfiltrated from disk or source control.
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 advertises access to multiple sensitive capabilities (environment access, file read/write, and network) but does not declare any tool scope or allowed-tools restrictions. In an agent setting, this weakens least-privilege boundaries and makes it easier for the skill to access or persist sensitive data, especially because the document explicitly instructs saving an API key to local configuration.
The skill claims to provide runbook access but requires collection and persistence of a third-party API key, which is not obviously necessary for static or public runbook retrieval. In this context, requesting secrets under an unrelated banner increases phishing and secret-exfiltration risk, especially since the key is to be saved locally for reuse.
The workflow section includes an example call to search_schools(...), which is unrelated to Kubernetes runbooks and indicates copy-pasted or repurposed instructions. Such inconsistencies increase the risk of accidental invocation of unintended tools, misrouting of user data, or concealment of the skill's real behavior from reviewers.
This code sends the caller-provided params payload to a remote endpoint via POST, which may include user or system data. There is logging for success and failure, but no confirmation prompt, print, or explicit user-facing disclosure that data will be transmitted off-system.
The class docstring says "小笨羊高考Skill配置", which describes a completely different skill domain from the manifest's Kubernetes troubleshooting handbook service. This is an active contradiction in code documentation rather than a mere omission, indicating the file may have been repurposed without aligning documented intent.
This skill, described as a Kubernetes troubleshooting handbook service, is configured to use credentials for an unrelated external XBY service. That scope mismatch is dangerous because it may cause users or operators to provide secrets to an unexpected third party, creating a covert data-flow and trust-boundary violation.
The inline comment and code explicitly refer to reading XBY_APIKEY, while the manifest describes a Kubernetes MCP server. This documentation and naming indicate a different product/integration intent than the stated skill, creating a clear intent-code mismatch in the file's documented purpose.
The code persists API keys into a local .env file, which creates durable plaintext secret storage on disk. In many deployments, .env files are readable by other local users, accidentally committed to source control, included in backups, or exposed through misconfiguration, making credential theft more likely.
Saving an API key to .env without clear disclosure is dangerous because users may believe the key is only used in memory while it is actually written to disk. Undisclosed persistence increases the chance of accidental leakage through repository commits, logs, workstation compromise, or shared environments.
The skill name, description, and operating instructions are presented entirely in Chinese, including imperative workflow requirements to the model. There is no indication that users may choose another language or that the locale restriction is justified as region-specific, which matches the language/locale policy concern for natural-language content.
The dependency specification uses a lower bound (requests>=2.31.0) rather than pinning an exact version, which makes builds non-reproducible and can allow installation of unexpectedly vulnerable or behavior-changing releases. In a server component that integrates with AI and Kubernetes troubleshooting workflows, this weakens supply-chain assurance even though the manifest itself is not directly exploitable code.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
The manifest includes requests without an exact version pin, and the package has multiple known advisories across its release history. Because the installed version is not fixed, it is not possible to verify from this file alone whether deployment will use a patched or vulnerable release, creating a real but low-severity supply-chain verification gap.
Using pydantic>=2.7.0 leaves the resolved version open-ended, so different environments may install different releases, including versions with newly introduced flaws or breaking changes. This is a supply-chain hardening issue rather than an immediate code execution bug, but it still increases operational and security risk.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
Pydantic has known advisories in some versions, and the open-ended requirement prevents confirmation that only patched versions will be installed. This does not prove the current deployment is vulnerable, but it does show the manifest lacks the controls needed to verify that it is safe.
The pydantic-settings dependency is unpinned, so package resolution may pull different versions over time, reducing reproducibility and making it hard to prove that deployed builds are not affected by known issues. For configuration-handling libraries, version drift can be especially risky because they often process environment variables and secrets.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
The unpinned pydantic-settings requirement makes it impossible to determine whether installs will include a version impacted by known advisories. Given that this package may influence how secrets and configuration are loaded, the lack of version certainty is a meaningful security hygiene issue.
python-dotenv>=1.0.1 is not version-pinned, which permits uncontrolled upgrades and inconsistent dependency resolution across installations. Since this library commonly interacts with local environment configuration, unreviewed version changes can have security implications if an affected release is installed.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
python-dotenv has known advisories in parts of its version history, and because the manifest does not pin a specific version, consumers may install an affected release without noticing. In a service context, configuration-loading libraries can affect local file handling and environment parsing, so unverifiable version selection increases risk.
No suspicious patterns detected.