T09 · Insecure Skill Coding Practices
- Location
clawcat/adapters/news/rss.py:27- Finding
Unrestricted RSS URLs Permit Server-Side Request Forgery
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is a coherent report-generation tool, but it includes overly broad network and local-code execution bridges that should be reviewed before installation.
Install only if you are comfortable with a briefing tool that can make outbound web requests, call a configured LLM provider in standalone mode, and render reports through a browser. Avoid enabling skill_proxy except for explicitly trusted modules, do not allow untrusted users to supply RSS feed URLs or task_config values, and prefer running it in an isolated environment with pinned dependencies and restricted network egress.
clawcat/adapters/news/rss.py:27Unrestricted RSS URLs Permit Server-Side Request Forgery
clawcat/adapters/search/skill_proxy.py:60Caller-Controlled Python Module and Function Invocation
clawcat/nodes/write_section.py:43Fetched Web Content Can Perform Indirect Prompt Injection
clawcat/templates/base.html:7Report Rendering Executes Mutable Third-Party JavaScript
requirements.txt:3Production Dependencies Are Not Reproducibly Pinned
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""ClawCat configuration — powered by pydantic-settings.
Loads from: environment variables > .env > config.yaml (descending priority).
"""
from __future__ import annotations
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""ClawCat configuration — powered by pydantic-settings.
Loads from: environment variables > .env > config.yaml (descending priority).
"""
from __future__ import annotations
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""ClawCat configuration — powered by pydantic-settings.
Loads from: environment variables > .env > config.yaml (descending priority).
"""
from __future__ import annotations
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""ClawCat configuration — powered by pydantic-settings.
Loads from: environment variables > .env > config.yaml (descending priority).
"""
from __future__ import annotations
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
model_config = SettingsConfigDict(
yaml_file=["config.yaml", "config.local.yaml"],
yaml_file_encoding="utf-8",
env_file=".env",
env_nested_delimiter="__",
extra="ignore",
)
The skill_proxy feature allows the skill to invoke arbitrary external/local modules by module and function name, which greatly exceeds the stated scope of a report-generation tool. This creates a powerful execution bridge that could be abused to access unintended capabilities, trigger side effects in other installed skills, or expand network/data access without clear trust boundaries.
This markdown file contains extensive natural-language instructions and acceptance criteria exclusively in Chinese, including the title at L001 and all subsequent operational guidance. Because the document does not offer users a language/locale choice or explain that the skill is intentionally region-specific, it may violate a language or locale policy requiring user opt-in.
The skill plan is presented entirely in Chinese and labels itself as a '完整技术方案', with no indication that users may choose another language or locale. Under the language/locale policy rule, forcing a specific language without user opt-in can be a natural-language policy violation.
The top-level skill description states the product in Chinese only and frames it as a general-purpose briefing engine, but nowhere in the README does it indicate that the skill supports other languages or requires Chinese by design. For a broadly described skill, this creates a natural-language locale constraint without user opt-in or justification.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
pmi = latest.get("制造业-Loss", latest.get("PMI", ""))
items.append(Item(
title=f"中国制造业PMI: {pmi}",
url="https://data.eastmoney.com/cjsj/pmi.html",
source="akshare_macro",
raw_text=f"日期: {date_val}, PMI: {pmi}",
published_at=datetime.now().isoformat(),
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
pmi = latest.get("制造业-Loss", latest.get("PMI", ""))
items.append(Item(
title=f"中国制造业PMI: {pmi}",
url="https://data.eastmoney.com/cjsj/pmi.html",
source="akshare_macro",
raw_text=f"日期: {date_val}, PMI: {pmi}",
published_at=datetime.now().isoformat(),
This manifest contains multiple adapter entries with hard-coded language values such as 'en' and 'zh', and some guidance explicitly requires English or Chinese keywords. Because the file does not indicate that users can opt into these language constraints, it presents a natural-language locale policy concern under the rule for forced language without user choice.
The registry exposes a generic skill_proxy adapter that can invoke an arbitrary installed Python module and function based on configuration (skill_module, skill_function). This materially expands the trust boundary from a fixed set of built-in adapters to any locally installed skill, enabling unintended code execution paths, data exfiltration, or use of unreviewed third-party logic if an attacker can influence configuration or installed packages.
This adapter dynamically imports and executes arbitrary configured modules/functions for what is described as a search normalization bridge, creating a powerful execution primitive far beyond normal data transformation needs. If an attacker can influence configuration or available Python modules, they can cause arbitrary code execution, invoke unexpected side effects during import, or run non-search functions under the application's privileges.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
try:
async with new_client() as client:
resp = await client.get(
"https://api.github.com/search/repositories",
params={"q": q_str, "sort": sort, "order": "desc", "per_page": str(per_query)},
headers=headers,
)
The file's usage examples and argument help all present report requests exclusively in Chinese, which implicitly steers users toward a single language. There is no accompanying natural-language indication that other languages are supported or that the Chinese-only framing is a deliberate, justified regional constraint.
This code emits a natural-language message in Chinese (数值 ... 在素材中找不到来源,可能为 LLM 编造) when reporting grounding issues. Because the skill does not provide user opt-in, fallback localization, or documentation that it is intentionally Chinese-only, it violates the language/locale policy for natural-language output.
The embedded instruction explicitly requires the model to '使用中文撰写' (write in Chinese). This imposes a fixed language policy in natural-language instructions, and the file does not show any user choice or clear region-specific justification for restricting output to Chinese.
The module docstring states that items without published_at are discarded as part of the freshness guarantee, but the implementation only checks date bounds when published_datetime is not None. As a result, undated items bypass the time filter and are admitted into filtered_items, undermining any downstream assumption that all output is time-bounded and fresh.
The natural-language system prompt requires Chinese output, including Chinese section titles, rather than offering a language choice. This is a locale/language policy issue because the file imposes a specific language without evidence of user opt-in or a clearly documented region-specific constraint.
The planner injects the full serialized UserProfile into the system prompt sent to the LLM, which can expose personal or sensitive user data to a third-party model provider or downstream logging/retention systems. Because this happens automatically and there is no visible consent, minimization, or redaction in this file, the privacy risk is real and increased by the broad model_dump_json() serialization of the entire profile.
The instruction '使用中文撰写' mandates Chinese for all rewritten sections. The surrounding code does not offer a language choice or document that this is a region-specific or user-requested constraint, which creates a natural-language locale policy issue.
This code sends the full section JSON, audience/tone metadata, and issue text to an external chat completion client. There is no confirmation prompt, user-facing notice, or explanatory comment/docstring near the network operation to disclose that document content is being transmitted for revision.
The embedded system prompt is entirely in Chinese and instructs the model to act in that language, but the code does not offer a language choice or indicate that this is a justified region-specific constraint. This can violate language/locale policy when users have not opted into Chinese output.
No manifest is available, so there is no stated purpose justifying outbound model calls. This file transmits task metadata and item summaries to an LLM via chat completions, which is a meaningful external-processing capability that cannot be validated against any declared intent.
Detected: suspicious.exposed_secret_literal, suspicious.install_untrusted_source