T09 · Insecure Skill Coding Practices
- Location
scripts/call_api.py:55- Finding
Configurable Upstream Endpoint Can Expose the API Key
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill offers currency and oil-price tools, but it asks for an API key, stores it in a local plaintext `.env` file, and uses mismatched XiaoBenYang/gaokao backend code that weakens trust in where the credential goes.
Review this skill carefully before installing. Use it only if you trust the publisher and XiaoBenYang backend, provide a limited-scope API key if possible, avoid running it in shared repositories or untrusted directories, and be prepared to rotate the key if the local `.env` file may have been exposed.
scripts/call_api.py:55Configurable Upstream Endpoint Can Expose the API Key
scripts/config.py:43API Key Is Persisted in a Plaintext File Without Secure File Controls
The skill appears mislabeled and internally inconsistent: the project references a different service, lacks the declared finance functionality, and includes undeclared local persistence of API keys. This creates a supply-chain style trust problem where a user may install a benign-looking finance skill that actually belongs to another product and handles secrets in unexpected ways.
The skill appears mislabeled and internally inconsistent: the project references a different service, lacks the declared finance functionality, and includes undeclared local persistence of API keys. This creates a supply-chain style trust problem where a user may install a benign-looking finance skill that actually belongs to another product and handles secrets in unexpected ways.
The file is for a skill declared as a currency/oil price service, but it implements configuration and persistence for a different '高考' service and its API key. This mismatch is a strong supply-chain integrity concern because it suggests code reuse from an unrelated service or hidden functionality, increasing the risk that operators provide credentials to the wrong backend or expose secrets to an unintended system.
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 opens .env and force-reads XBY_APIKEY outside the standard settings loader, bypassing normal configuration expectations and increasing the chance of silently ingesting credentials from the working directory. In a skill with mismatched service identity, this behavior is more dangerous because it can collect and use secrets for an apparently unrelated backend.
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 read of .env are part of a custom credential-loading path that silently consumes local secrets. This is risky because it broadens the trust boundary to any .env in the execution directory and can cause unreviewed credential use, especially problematic given the declared-service mismatch in this 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 an API key into .env, creating a durable plaintext secret on disk. Plaintext local storage is a real secret-management weakness because credentials may be exposed through repository mistakes, backups, filesystem access by other local users, or later tooling that reads the same .env file.
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 requires reading configuration, persisting an API key, and making outbound requests, but it does not declare any explicit tool scope or permissions boundaries. In an agent environment, undeclared capabilities reduce transparency and make it harder to enforce least privilege, especially when combined with instructions to write secrets to local configuration.
The skill instructions and operational requirements are presented entirely in Chinese and direct the model's behavior in that locale, without any indication that the user can choose another language. This can violate language/locale policy when a skill implicitly forces a specific language without user opt-in or justification.
The workflow example calls an unrelated school-search function, which indicates copy-paste contamination from another skill and weakens confidence in the integrity of the package. In security terms, such inconsistencies are a red flag because they can mask unintended or hidden capabilities and increase the chance that the agent invokes the wrong tool path with user data.
This code performs an outbound HTTP POST containing the caller-supplied params and an API key in headers, which is a safety-relevant network transmission. While the file includes internal logging and docstrings, there is no user-facing warning, confirmation, or comment disclosing that user/system data in params will be sent to an upstream service.
The docstring labels this as '高考Skill配置' while the published skill claims to provide currency and oil price data. Such contradictions undermine trust boundaries and can mislead reviewers and users into authorizing secrets or network access for a component different from what they believe they are installing.
The code persistently writes the API key to a local .env file and also places it in the process environment without any user-facing disclosure, consent flow, or storage hardening. This can expose credentials through accidental file inclusion, weak filesystem permissions, backups, logs, or later reuse by unrelated processes.
项目结构部分将根目录写为 xiaobenyang_gaokao_skill/,而整个清单与说明都在描述货币汇率和石油价格服务。这表明文档存在从其他技能复制遗留的内容,直接削弱了文档对开发者意图的准确表达。
The dependency specifier requests>=2.31.0 is unpinned, so builds may resolve to different versions over time. This weakens supply-chain control and makes it harder to ensure vulnerable or incompatible releases are not introduced unexpectedly.
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 version, it is impossible to verify whether deployed environments will avoid affected releases. In a service that likely performs outbound HTTP requests for currency and oil-price data, this uncertainty matters more because network-facing libraries are part of the attack surface.
The dependency specifier pydantic>=2.7.0 is unpinned, allowing future installs to select different releases without review. This creates a supply-chain risk because a newly published vulnerable or malicious version could be pulled into deployments automatically.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
pydantic has known advisories, and the lack of version pinning means the actual installed version cannot be audited from this file alone. If the service validates untrusted API inputs or configuration through Pydantic, vulnerable parser behavior could become reachable depending on the resolved release.
The dependency specifier pydantic-settings>=2.2.0 does not lock the installed version, which makes environments non-reproducible and can silently introduce risky upstream changes. In security-sensitive tooling, predictable dependency resolution is important for auditability and patch management.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
pydantic-settings has at least one advisory, and the open-ended requirement prevents confirming whether installations will resolve to a safe version. Since settings libraries may read secrets and filesystem-backed configuration, an unsafe version can affect confidentiality or path-handling if those features are used.
The dependency specifier python-dotenv>=1.0.1 is unpinned, so dependency resolution may later select unreviewed releases. This increases the chance of consuming a version with a newly disclosed vulnerability or harmful behavior.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
python-dotenv has known advisories, and without pinning there is no assurance that installed environments avoid affected versions. Because dotenv libraries interact with local configuration files, vulnerable releases can create file-handling or overwrite risks in development or deployment workflows.
The user-facing/docstring text in this file is exclusively in Chinese, including operational messages such as the API key setup error and function descriptions. That can constitute a language/locale policy issue if the skill is expected to be language-neutral and does not offer users a choice of language.
The user-visible docstrings, comments, and printed error message are written in Chinese, which indicates the skill is oriented to a single language without any opt-in or alternative. Under the language/locale policy, this is a natural-language constraint that should be explicitly optional or justified.