T09 · Insecure Skill Coding Practices
- Location
scripts/call_api.py:53- Finding
Configurable API Endpoint Can Expose Credentials and Speech Content
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill appears intended to call a remote speech-generation API, but it has mismatched service identity, plaintext API-key persistence, and an overridable authenticated endpoint that deserve review before installation.
Install only if you trust the XiaoBenYang backend and are comfortable storing the API key in a local .env file. Review or constrain the API endpoint before use, avoid committing .env, and rotate the key if it may have been exposed.
scripts/call_api.py:53Configurable API Endpoint Can Expose Credentials and Speech Content
scripts/config.py:42API Key Is Persisted in Plaintext Without Explicit Access Restrictions
scripts/tools.py:3Invalid and Unresolvable Tool Type Annotations Can Break Tool Registration
The skill advertises a speech-synthesis service but documents API-key persistence to .env, local configuration handling, and unrelated service/package naming with no evidence of the claimed TTS pipeline. That discrepancy can mislead users into disclosing secrets and trusting a skill whose actual behavior and storage model differ materially from the declared purpose.
The skill advertises a speech-synthesis service but documents API-key persistence to .env, local configuration handling, and unrelated service/package naming with no evidence of the claimed TTS pipeline. That discrepancy can mislead users into disclosing secrets and trusting a skill whose actual behavior and storage model differ materially from the declared purpose.
The API-key instructions and project structure mention an unrelated external service and package name, which strongly suggests the skill may send user data and credentials to a different backend than advertised. This elevates the risk of credential misuse, accidental exfiltration, and loss of user trust because the actual processing destination is obscured.
The configuration code is clearly for a different product domain ("小笨羊高考" / XBY_GAOKAO / XBY_APIKEY) than the declared speech synthesis service. This kind of skill-identity mismatch is dangerous because it can cause the deployed skill to load, retain, or transmit unrelated secrets and endpoints, indicating possible repackaging, code grafting, or hidden functionality beyond the declared purpose.
The docstrings and comments describe a different skill than the manifest, which is a strong signal of copied or substituted code. In security terms, this undermines trust boundaries because reviewers and operators may approve a speech tool while the code is configured for another service and credential set.
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 .env manually to extract XBY_APIKEY, bypassing normal typed settings handling and targeting a specific unrelated credential. In the context of a speech synthesis skill, this unnecessary secret harvesting increases the chance of hidden credential use, mishandling, or exfiltration by adjacent code.
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 code opens and reads the .env file contents directly, which is an unnecessary form of credential access for this skill and is focused on obtaining a specific unrelated API key. Direct file reads of secret material increase exposure surface and make it easier for hidden or future code paths to process credentials outside normal controls.
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 to .env in plaintext and updates process environment state, creating durable local secret exposure. In the context of a mislabeled skill handling an unrelated credential, this becomes more dangerous because users may unknowingly authorize storage of a secret for another service entirely.
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 references capabilities that can access environment variables, read/write local files, and perform network calls. In an agent setting, missing scope declarations weakens least-privilege controls and makes it easier for the skill to access secrets or modify local state beyond what a user would reasonably expect from a speech-synthesis skill.
The entire skill description and operational instructions are written only in Chinese, with no indication that users may choose another language or locale. This creates a language-policy concern because it implicitly constrains interaction to a specific language without documenting opt-in or a justified region-specific limitation.
The workflow documentation references unrelated gaokao school-search behavior inside a speech-synthesis skill, indicating copy-paste contamination or poor control over the prompt contract. In agent systems, irrelevant instructions can cause incorrect tool invocation, unexpected data handling, or routing user inputs to unintended functions or services.
The instruction to directly display raw API responses can expose secrets or sensitive backend fields, including echoed API keys, internal identifiers, storage URLs, or debugging metadata. In this skill, that risk is amplified because the workflow explicitly collects and stores an API key, and the backend is an external service with unclear response sanitization guarantees.
This code includes natural-language strings and docstrings exclusively in Chinese, including the class and function descriptions and the error message returned to users. Under the language/locale policy, forcing a specific language without opt-in or a documented region-specific justification is a policy concern.
The code persists and manages an unrelated API key (XBY_APIKEY) even though the advertised skill is for speech synthesis. Storing credentials unrelated to the stated function expands secret exposure and suggests the skill may access another service without user understanding or operational need.
The function silently writes an API key into a local .env file without any user-facing warning, consent, or disclosure. This is risky because plaintext secrets may be left on disk, accidentally committed to source control, read by other local processes, or persist longer than the user expects.
The dependency specifier for requests is unpinned, so builds may resolve to different versions over time. This weakens supply-chain reproducibility and can unintentionally introduce vulnerable or breaking releases into deployments.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
requests has known advisories, and because the manifest does not pin an exact version, it is impossible to verify from this file whether a safe or affected release will be installed. In a network-facing service, this uncertainty matters because HTTP client flaws can expose credentials, request integrity, or transport security.
The dependency specifier for pydantic is unpinned, allowing future installs to pull different versions than originally tested. This creates a supply-chain risk because insecure or incompatible releases could be introduced without code changes.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
pydantic has known advisories, and the unpinned version range prevents verification that deployed environments will avoid affected releases. This can matter for services processing untrusted input because parser or validation bugs may enable denial of service or unsafe behavior.
The dependency specifier for pydantic-settings is unpinned, which makes dependency resolution non-deterministic across environments and time. That increases exposure to accidental adoption of vulnerable releases or transitive dependency issues.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
pydantic-settings has at least one known advisory, and the lack of version pinning means the actual installed version cannot be validated from the manifest alone. For configuration-loading components, that uncertainty can affect secret handling and filesystem safety depending on how the package is used.
The dependency specifier for python-dotenv is unpinned, so installations may vary and could silently pick up a vulnerable release. This is a common supply-chain hygiene weakness even when no active exploit is present in the file itself.
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 an exact pin the project may install an affected version in some environments. Since this package interacts with environment and file handling, vulnerable releases could have security consequences if those features are exercised by the service.