T09 · Insecure Skill Coding Practices
- Location
scripts/config.py:12- Finding
Configurable API Endpoint Can Expose the API Credential
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This NBA data skill should be reviewed before installation because it stores an API key locally and contains mismatched configuration plus an overridable credential-bearing API endpoint.
Install only if you are comfortable giving this skill a XiaoBenYang API key and having it saved in plaintext as .env in the working directory. Review or fix the gaokao/NBA inconsistencies, pin the API origin to the intended host, avoid persistent plaintext secrets where possible, and pin dependencies before using it in a shared or sensitive workspace.
scripts/config.py:12Configurable API Endpoint Can Expose the API Credential
scripts/config.py:47API Key Is Persisted in a Predictable Plaintext File Without Enforced Permissions
requirements.txt:1Open-Ended Dependency Versions 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 English description advertises an NBA data server, but the implementation behavior includes reading and persisting API keys, managing configuration for another service, and targeting a different external endpoint. This creates a trust-boundary violation: the skill is not just fetching basketball data, it is also handling credentials and interacting with a distinct service that users may not realize they are authorizing.
The English description advertises an NBA data server, but the implementation behavior includes reading and persisting API keys, managing configuration for another service, and targeting a different external endpoint. This creates a trust-boundary violation: the skill is not just fetching basketball data, it is also handling credentials and interacting with a distinct service that users may not realize they are authorizing.
The configuration clearly targets a different service/domain ('高考' and XBY_* settings) than the declared NBA data skill. This kind of mismatched code strongly suggests code reuse or hidden functionality, increasing the risk that the skill routes data or credentials to an unrelated backend and violates user expectations about what the skill does.
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 opens and parses the .env file specifically to force-load XBY_APIKEY, bypassing the normal settings abstraction. Manual secret scraping increases the chance of mishandling credentials and is more dangerous here because it targets an unrelated key flow in an NBA skill context.
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")
This line participates in direct filesystem access to a .env file for credential extraction. While not malicious on its own, it contributes to unnecessary credential handling outside the expected NBA data functionality and increases exposure of secrets to code paths that do not need them.
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
A helper dedicated to saving API keys into .env indicates active credential collection and persistence behavior. In the context of an NBA data skill with unrelated XBY configuration, this is more suspicious and dangerous because it can retain sensitive keys locally without necessity or clear 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 even though it is documented and analyzed as having environment, file read/write, and network capabilities. In an agent setting, missing least-privilege declarations increases the chance that a seemingly simple NBA data skill can access secrets, persist data, or make unexpected outbound requests without clear user visibility.
The skill explicitly instructs the agent to ask the user for an API key and save it, but provides no safeguards around secret minimization, consent, masking, storage location, retention, or access control. In agent environments this can lead to overcollection and unsafe persistence of credentials, especially when combined with file write and environment access.
The workflow examples and project structure reference gaokao/school-search functionality, which contradicts the claimed NBA domain and suggests copy-pasted or mislabeled routing logic. Such inconsistencies are a security concern because they undermine reviewer confidence, can hide actual behavior, and may cause the agent to invoke unintended tools or pass incorrect parameters to external services.
This file contains a Chinese-only class docstring and later returns Chinese-only user-facing error/success messages, indicating the skill is designed to communicate in a fixed language. Under the policy, forcing a specific language without user opt-in or documented regional justification is a natural-language policy violation.
This code is a generic proxy to an external MCP API: it accepts arbitrary mcp_id, tool_name, and params, then forwards them directly to the upstream service with the stored API key. In a skill advertised as an NBA data service, this expands the accessible capability surface beyond the declared domain and can enable unintended tool invocation, data access, or abuse of the configured credentials if callers can influence these fields.
The raised error message is user-readable and written only in Chinese, with no indication that the user can choose another language. This violates the language/locale policy unless the skill is explicitly documented as region-specific or provides opt-in.
The function docstring and returned message strings are Chinese-only and appear to be surfaced to callers, which fixes the interaction language without a user choice. The policy requires either locale selection/opt-in or a clearly justified documented locale restriction.
The declared settings prefix is XBY_GAOKAO_, but the manual credential logic reads and writes XBY_APIKEY instead. This inconsistency can cause operators to misconfigure the service, accidentally load the wrong secret, or bypass intended configuration controls, which is especially risky in security-sensitive credential handling code.
This file includes credential persistence and management behavior that is not disclosed by the NBA data service description. Undocumented secret-handling capabilities are dangerous because they expand trust boundaries and can cause users or operators to supply sensitive keys to a skill that appears to only provide sports data.
The code writes API keys directly into a local .env file, creating plaintext secret storage on disk. If the host is shared, backed up, logged, or the project directory is exposed, the credential can be recovered and reused by unauthorized parties.
The function silently persists a provided API key to disk without any user-facing warning or confirmation. That behavior is risky because users may assume the key is used only for the current session, while the code creates a durable secret artifact that may later be disclosed.
The dependency is specified with only a minimum version (requests>=2.31.0), which allows future installs to resolve to different releases over time. This weakens build reproducibility and can unintentionally pull in vulnerable or breaking versions, especially significant for a network-facing data service that relies on HTTP requests.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
The manifest does not pin requests, so it is impossible to verify whether deployed environments avoid known vulnerable releases. In a service that likely makes outbound HTTP calls for NBA data, an affected requests version could expose credentials or weaken transport security depending on usage.
Using pydantic>=2.7.0 without an upper bound or exact pin permits uncontrolled dependency drift. That creates supply-chain and reliability risk because future releases may introduce security regressions or behavior changes that affect validation logic.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
Because pydantic is not pinned, the project may install a version impacted by known advisories, but that cannot be confirmed from this file alone. For a data service, flaws in validation libraries can enable denial of service or unsafe parsing if untrusted inputs are processed.
The unpinned pydantic-settings dependency allows installation of any newer version meeting the minimum constraint. Since settings libraries often process environment and secret-loading behavior, version drift can introduce security-sensitive changes unexpectedly.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
No suspicious patterns detected.