T09 · Insecure Skill Coding Practices
- Location
scripts/config.py:48- Finding
API Key Persisted in an Unprotected Plaintext Environment File
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This calculator skill is not clearly malicious, but it sends calculations to a remote API and persists an API key in a local plaintext .env file with weak scoping and disclosure.
Install only if you are comfortable sending calculator inputs to the XiaoBenYang remote API and storing the service API key in a local .env file. Prefer using a scoped/rotatable key, avoid entering sensitive financial or business data unless the provider is trusted, and review the stale gaokao/search_schools references before relying on the package in a controlled environment.
scripts/config.py:48API Key Persisted in an Unprotected Plaintext Environment File
requirements.txt:1Unbounded Dependency Versions Permit Unreviewed Future Releases
The example call to search_schools and the gaokao-oriented project naming indicate likely code or workflow reuse from an unrelated education/search skill. This strongly suggests the skill may invoke unintended remote capabilities beyond math, creating a severe trust-boundary failure where a 'calculator' facade masks different data handling and tool behavior.
A second aspect of the same mismatch is that the skill manages persistent API credentials and remote service configuration even though it claims to be a self-contained calculator. Hidden credential storage and remote connectivity materially change the trust model and can expose users to credential leakage or unauthorized external processing.
A second aspect of the same mismatch is that the skill manages persistent API credentials and remote service configuration even though it claims to be a self-contained calculator. Hidden credential storage and remote connectivity materially change the trust model and can expose users to credential leakage or unauthorized external processing.
The documented workflow contradicts the stated identity of the skill by routing user requests through external API-backed tools rather than performing local computation. In context, this is more dangerous because users expect a calculator to be low-risk and offline-like, making them less likely to scrutinize network use or secret collection.
The project structure names the skill as a gaokao skill, conflicting with the calculator branding and reinforcing that the package may be repurposed from unrelated functionality. This increases the likelihood of hidden endpoints, stale logic, or mismatched secret handling that users cannot infer from the declared purpose.
This file implements a generic remote MCP tool invocation client rather than a calculator-limited function set. Because tool_name, mcp_id, and params are caller-controlled and sent to an external service with an API key, the skill can be used as a proxy to invoke arbitrary upstream capabilities that exceed the advertised calculator scope.
The code performs outbound network calls to an upstream tool endpoint using headers that let the caller select the function and MCP target. In the context of a calculator skill, this creates capability confusion and enables misuse of the skill as a remote action bridge, potentially exposing users or systems to unauthorized external operations.
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 file for a purported calculator service implements unrelated external API credential loading, override logic, and persistence to a local .env file. That mismatch strongly suggests copied or repurposed code and creates unnecessary secret-handling capability, increasing the attack surface and risk of credential exposure or misuse in a skill that should not need such behavior.
This code explicitly reads the .env file at runtime and extracts a specific API key outside the normal settings framework. Custom secret scraping bypasses standard validation and can unexpectedly collect or expose credentials, especially in a skill whose stated purpose is local math operations rather than authenticated remote access.
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")
Creating a direct path to '.env' and inspecting its contents is part of bespoke credential-access logic that is unnecessary for a calculator skill. This increases the chance of improper handling of local secrets and can normalize access to sensitive developer files from application code.
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
The code can write attacker- or user-supplied API keys directly into a .env file and mirror them into process environment variables. Runtime secret persistence in the working directory is dangerous because it can leak credentials through source control, backups, logs, shared volumes, or later unintended reads by other components.
This function is explicitly designed to persist an API key into a local .env file, which creates long-lived credential material on disk. In the context of a calculator service, this capability is unjustified and materially raises the risk of credential leakage, accidental commit, or abuse by other local processes or future code paths.
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 read/write, and outbound network requests. In an agent setting, missing scope declarations weakens least-privilege controls and can allow broader capability use than users would reasonably expect from a calculator skill.
The skill explicitly instructs the agent to collect an API key from the user and persist it via set_api_key without clearly warning that the secret will be stored, where it will be stored, or how it will be protected. Secret collection plus persistence is sensitive behavior, especially in a skill masquerading as a calculator, and could lead to inadvertent credential exposure.
The instruction to directly display tool raw data indicates the skill acts as a thin proxy for external API responses instead of a bounded calculator. Returning raw upstream content increases the chance of exposing unnecessary metadata, error traces, or untrusted content directly to users.
Caller-supplied parameters are serialized and transmitted to an external API together with the skill's API credential, but this file provides no user-visible warning, consent flow, or minimization of forwarded data. In a skill presented as a calculator service, users may reasonably expect local computation, making undisclosed external transmission more risky from a privacy and trust perspective.
Settings 类的文档字符串写明“\u5c0f\u7b28\u7f8a\u9ad8\u8003Skill配置”,显示该文件似乎源自另一个高考相关技能,而不是当前声明的计算器服务。这不是简单信息缺失,而是对代码归属和用途的直接矛盾,削弱了开发者意图与实现的一致性。
This file presents a calculator interface but every operation forwards inputs to an external API via call_api instead of performing local computation. That creates an unexpected data-flow boundary: user inputs and usage patterns are transmitted off-box, introducing privacy, availability, and integrity risks if the remote service is compromised, unavailable, or behaves unexpectedly.
The advertised purpose is a math calculator, but the code has hidden external API dependency and data forwarding behavior not reflected in the stated capability description. This mismatch can mislead operators and users into providing sensitive numeric or financial inputs under the assumption that processing is local.
Nearly all wrapper functions package user-provided arguments and send them directly to a network API, while this file provides no user-facing disclosure, consent, minimization, or visible validation. In a calculator skill, users may enter financial figures, business metrics, or other sensitive values, so silent transmission increases confidentiality and trust risks beyond what the context suggests.
The skill name, description, workflow, and user-facing instructions are all presented in Chinese, effectively imposing a specific language on users. There is no stated opt-in, alternative language support, or justification that this skill is intentionally region- or locale-specific.
The dependency is specified with a lower-bound range instead of an exact version, so builds may resolve to different releases over time. This weakens reproducibility and can unintentionally introduce a vulnerable or breaking upstream version into the calculator service.
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 an exact version, it is impossible to verify from this file whether the installed release is affected. The danger here is not confirmed exploitation but uncertainty: an environment could resolve to a vulnerable version without developers noticing.