T09 · Insecure Skill Coding Practices
- Location
scripts/call_api.py:52- Finding
Configurable API Endpoint Can Expose Credentials and Submitted Images
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill appears to use a remote API for cigarette detection, but it stores API keys in plaintext and can send keys and images to a configurable endpoint.
Review before installing. Use only non-sensitive images, do not provide an API key you cannot rotate, and avoid running this skill in a workspace where .env files may be committed, backed up, or shared. The publisher should remove the Gaokao leftovers, validate or pin the upstream API host, avoid plaintext key persistence, and clearly disclose that images are sent to Xiaobenyang's remote service.
scripts/call_api.py:52Configurable API Endpoint Can Expose Credentials and Submitted Images
scripts/config.py:42API Key Is Persisted in a Plaintext Environment File Without Explicit Permission Hardening
The skill documentation references reading/writing .env files, persisting API keys, loading credentials from environment variables, and even unrelated gaokao/default-year configuration, which is materially inconsistent with a narrowly scoped image-detection skill. This broadens the attack surface and suggests code reuse or hidden functionality that could mishandle secrets or perform actions unrelated to the user’s request.
The skill documentation references reading/writing .env files, persisting API keys, loading credentials from environment variables, and even unrelated gaokao/default-year configuration, which is materially inconsistent with a narrowly scoped image-detection skill. This broadens the attack surface and suggests code reuse or hidden functionality that could mishandle secrets or perform actions unrelated to the user’s request.
The file for a cigarette-detection skill contains configuration for an unrelated Gaokao/MCP service, including base URL, MCP identifier, and API-key handling. This capability mismatch is dangerous because it introduces unexplained network/service integration and credential handling that are not required for the stated image-detection purpose, increasing the risk of hidden data flow or unauthorized service access.
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 model_post_init routine explicitly reads .env and extracts XBY_APIKEY manually, creating custom credential-loading logic beyond normal framework behavior. In the context of an image-detection skill, this unexplained secret harvesting is high risk because it widens access to credentials and bypasses clearer, centralized secret-management patterns.
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 checks for the existence of .env and reads its contents directly, which is part of a custom credential access path. In this mismatched skill context, directly inspecting a sensitive configuration file is suspicious because the advertised function does not require managing external service credentials, making hidden or unnecessary secret access more dangerous.
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 persist an API key into a local .env file and reuse it later, even though the declared purpose is image-based cigarette detection. Storing credentials on disk without a clear operational need broadens secret exposure through source packaging, backups, logs, or accidental inclusion in repositories, and creates a hidden persistence mechanism in a low-trust skill context.
This function is explicitly designed to save an API key into .env, establishing durable credential persistence in the skill's working directory. In a skill whose stated purpose is object detection from images, this is an unnecessary credential-handling capability that increases the chance of secret leakage through files, packaging, backups, or repository commits.
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 or permission scope even though its documented/project capabilities include environment access, file read/write, and network use. Without least-privilege boundaries, a consumer cannot easily determine or constrain what the skill may access, increasing the risk of credential handling abuse or unintended data exposure.
References to unrelated gaokao/search functionality inside a cigarette-detection skill indicate copy-paste drift or mixed-purpose tooling. Such inconsistencies are dangerous because they can misroute user input, invoke the wrong tools, or conceal broader capabilities than users expect.
The skill asks users to provide image URLs or Base64 image data but does not warn that this content will be transmitted to an external service. Users may unknowingly send sensitive images or internal URLs to a third party, creating privacy, confidentiality, and potential SSRF-like risk depending on how remote fetching is implemented.
Instructing the agent to directly display raw API responses can expose sensitive or unnecessary data, including user-submitted image-derived content, internal identifiers, verbose error traces, or echoed request metadata. Raw output bypasses minimization and redaction, making accidental disclosure more likely.
This code sends the provided params to a remote endpoint and includes a credential in the request headers. The file contains no confirmation prompt, print/log statement informing the user that data will be transmitted externally, and no inline warning near the operation.
The docstring identifies the code as a '小笨羊高考Skill配置', which conflicts with the manifest claiming cigarette detection. This inconsistency is a strong trust and provenance warning: it suggests code reuse or substitution from another project, making hidden functionality and mis-scoped permissions more likely in a security review.
The function writes the supplied API key to .env and exports it into the process environment with no user-facing warning, confirmation, or security controls. This is risky because users may unknowingly cause long-lived credential persistence, and other components in the same runtime may subsequently access the secret from the environment.
The function sends a user-provided image URL to an external API endpoint via call_api, but this file provides no disclosure, consent handling, or indication to callers that image content will leave the local environment. Because images may contain sensitive visual data, silent transmission to a third-party service creates a real privacy and data-governance risk even if the code is otherwise straightforward.
This function transmits raw base64-encoded image content to an external API without any visible user warning or disclosure in the file. Sending the full image bytes off-box is more privacy-sensitive than passing a reference, since the entire potentially sensitive image is directly exfiltrated to a remote service.
The entire skill name and instructions are written only in Chinese, with no indication that users may choose another language or that the locale limitation is required for a region-specific compliance reason. This can violate language/locale policy when a skill implicitly mandates one language without opt-in.
The dependency specification uses a lower-bound only constraint (requests>=2.31.0), which makes builds non-reproducible and allows future installs to resolve to unexpected versions. This increases supply-chain risk and makes it impossible to determine from the manifest alone whether a vulnerable or incompatible release will be installed.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
requests has multiple known advisories, but the manifest does not pin the installed version, so exposure cannot be verified. This is dangerous because an environment may resolve to an affected release, especially in CI/CD or redeployments where dependency state changes over time.
pydantic>=2.7.0 is unpinned, so dependency resolution may pull different versions over time across environments. That weakens build integrity and can silently introduce vulnerable or breaking releases into the skill.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
pydantic has known advisories, and without exact version pinning there is no reliable way to assess whether deployed environments are vulnerable. This creates a real but low-severity supply-chain risk because the package selected at install time may differ from what was tested.
pydantic-settings>=2.2.0 permits any newer version, making installations non-deterministic. In a security context, that means potentially affected versions could be installed later without any manifest change.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
pydantic-settings is listed with a known advisory, and the lack of a fixed version means the actual security posture is unverifiable from this file. Even if the current environment happens to be safe, future installs could select an affected version.