T09 · Insecure Skill Coding Practices
- Location
scripts/call_api.py:51- Finding
Configurable API Endpoint Can Expose the API Key to an Attacker-Controlled Server
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is mostly a hot-trends API wrapper, but it handles API credentials in ways that could expose them and includes broader fetching capabilities that need review.
Review this skill before installing. Use it only in a trusted workspace, verify that XBY_GAOKAO_BASE_URL is not set to an unexpected host, avoid committing or sharing the generated .env file, and rotate the XiaoBenYang API key if the workspace may have been exposed.
scripts/call_api.py:51Configurable API Endpoint Can Expose the API Key to an Attacker-Controlled Server
scripts/config.py:39API Key Is Persisted in Plaintext Without Explicit Restrictive File Permissions
The stated purpose is hotspot aggregation, but the skill also exposes generic website crawling and custom RSS ingestion, which are materially broader network capabilities than curated trend retrieval. That expansion increases SSRF-like, data exfiltration, and unreviewed content-fetch risks while remaining under-disclosed in the top-level description.
The stated purpose is hotspot aggregation, but the skill also exposes generic website crawling and custom RSS ingestion, which are materially broader network capabilities than curated trend retrieval. That expansion increases SSRF-like, data exfiltration, and unreviewed content-fetch risks while remaining under-disclosed in the top-level description.
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 explicitly opens and parses .env to extract XBY_APIKEY, bypassing normal settings abstractions and directly handling credentials. Manual secret scraping increases the chance of unintended exposure and indicates the skill is actively processing sensitive material beyond simple configuration loading.
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 existence check is part of a manual secret access flow that reads credential material from disk. In the context of a hotspot aggregation service, directly traversing secret files is unnecessary and expands the attack surface for credential disclosure through coding mistakes or future feature creep.
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 on disk, creating durable storage of sensitive credentials inside the skill's working directory. If the filesystem is shared, backed up, logged, or accidentally committed, the key can be exposed and abused to access upstream services.
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 documents capabilities that imply environment access, file read/write, and network use, but it does not declare an explicit tool scope or permissions boundary. In an MCP/agent setting, missing scope declarations weaken least-privilege guarantees and can cause users or hosts to underestimate what the skill can access.
The entire skill documentation is written as mandatory Chinese-language operating instructions, and many tool descriptions explicitly frame outputs as Chinese content, but there is no statement allowing the user to choose language or clarifying that the skill is intentionally region-specific. Under the policy, forcing a specific language or locale without opt-in is a natural-language policy concern.
A skill framed as a news/trend aggregator includes a general website crawler, which broadens it from fixed-source retrieval to arbitrary network access. In agent environments this can be abused to fetch internal resources, unexpected external content, or sensitive pages if the runtime has network reachability beyond intended public sites.
The website crawling feature lacks a clear user-facing warning that it will perform external network requests and retrieve arbitrary page content. Without explicit notice and boundaries, users may unknowingly authorize requests to sensitive destinations or process untrusted content with greater risk than expected.
Referencing an unrelated gaokao project structure inside a hot-trend aggregation skill suggests copy-paste drift or packaging confusion, which undermines trust in the reviewed artifact and may hide unexpected code paths or configuration behavior. In security review, such inconsistencies increase the chance that the deployed implementation does more than the documented purpose.
This code performs an outbound HTTP POST using caller-supplied params and includes an API key in headers, which can transmit user or system data to an external service. While the code logs success and errors, those logs are not user-facing warnings or disclosures about the network transmission itself, and this file contains no prompt, comment, or docstring warning about that behavior.
Settings 类的文档字符串写的是“"小笨羊高考Skill配置"”,而当前技能清单名称和描述均指向“热点聚合服务”。这不是单纯信息缺失,而是对技能用途的直接错配,可能误导维护者对该模块真实服务对象和配置语义的理解。
The module does more than read configuration: it persists an API key to a local .env file and mirrors it into process environment state. Persisting secrets to disk increases exposure through accidental source inclusion, weak filesystem permissions, logs, backups, or multi-tenant runtime access, and this behavior is broader than expected for a news/hotspot aggregation skill.
The skill is described as a热点/趋势聚合服务, but it also exposes a generic website crawling primitive via crawl_website(url). That broadens capability from curated aggregation to arbitrary external fetches, which can enable misuse such as fetching attacker-chosen targets, internal resources, or content outside the declared trust boundary if the backend does not enforce strict URL restrictions.
An arbitrary URL fetch/crawl function is not clearly necessary for a news/trending aggregation skill and increases attack surface beyond the advertised use case. In agent environments, such generic network access can be abused for SSRF-style probing, unintended data retrieval, or access to sensitive metadata/internal endpoints depending on how call_api is implemented downstream.
The wrapper exposes website crawling with no user-facing warning that the skill may contact arbitrary third-party sites based on provided URLs. This reduces transparency and increases the chance of users or orchestrators invoking network access they did not expect, especially when the skill otherwise appears to only query fixed trend sources.
The workflow section states that the model routes requests and that '代码只负责调用API', implying a bounded API-wrapper design. But the listed tools include crawl_website, which semantically differs from simply calling the service's aggregation API and expands behavior into direct site retrieval/crawling.
The dependency specifier uses a lower bound only, which makes builds non-reproducible and allows future package releases to be pulled in without review. This increases supply-chain risk and makes it impossible to verify whether a deployed version includes known security fixes or newly introduced vulnerabilities.
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 there is no reliable way to determine whether the installed version is affected by known advisories such as credential leakage issues. In a hotspot aggregation service that likely makes external HTTP requests, this uncertainty is more relevant because network-facing code may exercise vulnerable request-handling paths.
Using pydantic with only a minimum version permits installation of any later release, which weakens reproducibility and can unexpectedly introduce vulnerable or incompatible versions. In a service-oriented skill, this creates avoidable supply-chain uncertainty even if no immediate exploit is shown in this file.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
Because pydantic is not pinned, the deployed version may fall on either side of known security fixes, including denial-of-service related issues. The file alone does not prove exploitation, but the unverifiable version state is a real supply-chain weakness that prevents accurate risk assessment.
The unpinned pydantic-settings dependency allows uncontrolled upgrades at install time, which can pull in versions with security defects or behavior changes. This is a classic dependency hygiene issue that becomes more relevant for configuration-handling libraries because they may process secrets and local file paths.
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
The version of pydantic-settings is not fixed, so it cannot be verified whether installations are exposed to known issues affecting secret and path handling. Given this library's role in application configuration, uncertainty around vulnerable versions can have security consequences if unsafe code paths are later used.