T09 · Insecure Skill Coding Practices
- Location
scripts/push_to_feishu.py:121- Finding
Unrestricted Webhook Destination Enables Server-Side Request Forgery and Unintended Data Disclosure
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a coherent AI news aggregation and Feishu push skill with disclosed network services and local storage, though users should handle webhook and API credentials carefully.
Install only if you are comfortable with the skill fetching news from external services, optionally sending article content to an LLM provider for scoring, storing local JSON history, and posting selected content to a Feishu webhook. Use a dedicated Feishu webhook, keep API keys and gateway tokens out of shared environments, prefer dry-run before sending, and consider pinning dependencies before production use.
scripts/push_to_feishu.py:121Unrestricted Webhook Destination Enables Server-Side Request Forgery and Unintended Data Disclosure
scripts/news_sources.py:141Default RSS Sources Use Plaintext HTTP and Permit News Content Tampering
scripts/news_scorer.py:150Untrusted News Content Is Directly Embedded in LLM Scoring Instructions
requirements.txt:4Unbounded Third-Party Dependency Versions Create Supply-Chain Exposure
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
try:
print(f"正在发送消息到Feishu...")
response = requests.post(
webhook_url,
json=payload,
headers={"Content-Type": "application/json"},
The skill declares itself as a news-fetch/push utility, yet the manifest prominently includes OpenClaw gateway configuration and cron-style task management, indicating external scheduling/control capabilities beyond the stated core purpose. Hidden or underemphasized control-plane behavior raises the risk of persistent automated actions, misuse of sensitive gateway tokens, and user misunderstanding about the real trust boundary.
The skill declares itself as a news-fetch/push utility, yet the manifest prominently includes OpenClaw gateway configuration and cron-style task management, indicating external scheduling/control capabilities beyond the stated core purpose. Hidden or underemphasized control-plane behavior raises the risk of persistent automated actions, misuse of sensitive gateway tokens, and user misunderstanding about the real trust boundary.
The skill advertises and documents capabilities that require environment access, file I/O, network access, and shell execution, but it does not declare an explicit tool scope such as permissions or allowed-tools. This creates an over-privilege risk because an agent/runtime may grant broader capabilities than users expect, increasing the chance of unintended outbound requests, local data exposure, or command execution.
The trigger text is broad enough to activate on many general requests about AI news, automation, aggregation, or filtering, which can cause the skill to run in situations where the user did not intend to invoke networked fetching, local storage, or outbound message delivery. Over-broad triggering increases the likelihood of unnecessary exposure of environment-backed secrets and accidental execution of side-effecting functionality.
This code file contains natural-language documentation and comments exclusively in Chinese, including the module docstring and initializer documentation. Under the policy, forcing a specific language without offering a choice or documenting a justified locale constraint is a language/locale policy violation.
The docstring at L199 says the method retrieves filtered news for recent days, but L202 calls datetime.timedelta(...), which will raise because datetime here is the class imported from datetime, not the module. The same contradiction appears in analogous recent-item and cleanup logic, meaning the code cannot carry out the documented behavior.
The script sends user-supplied search queries and associated request metadata to Brave's external API. In this skill context, outbound transmission is expected for a news retrieval tool, but it still creates a privacy and data-governance risk if queries contain sensitive information or if operators assume the tool is fully local.
try:
response = requests.get(
"https://api.search.brave.com/res/v1/web/search",
headers=headers,
params=params,
timeout=30
The manifest emphasizes news retrieval, aggregation, filtering, scoring, and push-related workflows. In addition to those expected behaviors, this file writes categorized results into persistent storage via DataStorage, which is a broader stateful data-management behavior not disclosed in the manifest description of this script itself.
The module docstring and CLI description frame this as a news acquisition tool. The --output path handling adds a filesystem write capability that goes beyond simple fetching and formatting, and this side effect is not reflected in the top-level documentation or manifest summary.
The module description and all user-facing prompts are written exclusively in Chinese, which imposes a specific language on users. The file does not provide any opt-in, fallback, or explanation that this tool is intentionally limited to a Chinese-speaking context.
Natural-language strings throughout the file instruct the model and describe the tool exclusively in Chinese, including the system message and scoring prompt. There is no indication that the user can choose another language or that the Chinese-only behavior is a justified locale-specific constraint.
The code sends full news content and related metadata, including title, content, source, publication date, and URL, to third-party LLM providers when an API key is present. In a news aggregation/push skill, this creates a real data-governance and privacy risk because externally sourced content, internal curation signals, and potentially sensitive URLs or unpublished material may be transmitted off-platform without any user-facing notice, consent, or minimization.
The Brave search request hard-codes search_lang to en, which imposes a specific language/locale behavior in the skill. The file does not provide a user opt-in, configurable alternative, or justification for restricting results to English.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
try:
response = requests.get(
"https://api.search.brave.com/res/v1/web/search",
headers=headers,
params=params,
timeout=30
This Python file contains its title, help text, warnings, and runtime output entirely in Chinese, including the CLI description and operational prompts. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the tool is clearly documented as region-specific, which is not indicated here.
The manifest describes AI news retrieval, aggregation, filtering, and push delivery, but this file also launches another program using subprocess. Spawning a process is a broader execution capability than the stated purpose requires and is not explicitly justified in the manifest.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
import subprocess
try:
script_dir = get_script_dir()
result = subprocess.run(
['python3', str(script_dir / 'fetch_ai_news.py'), '--limit', str(limit), '--format', 'json'],
capture_output=True,
text=True,
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
try:
print(f"正在发送消息到Feishu...")
response = requests.post(
webhook_url,
json=payload,
headers={"Content-Type": "application/json"},
The dependency is specified with only a lower bound, which allows future installs to pull newer unreviewed versions and makes builds non-reproducible. In a news aggregation skill that fetches and parses untrusted RSS content, this increases supply-chain risk and makes it harder to verify whether vulnerable versions of feedparser are in use.
# AI News Pusher v3.0 - Dependencies
# Core dependencies (required)
feedparser>=6.0.0
requests>=2.25.0
# Optional dependencies for news sources
feedparser has known historical advisories, and because the manifest does not pin a version, it is impossible to verify from this file whether deployment uses a fixed, unaffected release. This matters more here because the skill consumes and parses untrusted RSS feeds, so parser vulnerabilities could be exercised by attacker-controlled feed content.
Using requests with only a minimum version means installations may resolve to different versions over time, including versions later found vulnerable or behaviorally incompatible. Because this skill retrieves remote content from external sources, an unpinned HTTP client raises supply-chain and security maintenance concerns.
# Core dependencies (required)
feedparser>=6.0.0
requests>=2.25.0
# Optional dependencies for news sources
tavily-python>=0.3.0
requests has multiple advisories, and the absence of an exact version prevents confirming whether the deployed package includes fixes. Since this skill makes outbound network requests to third-party sources, using an unverifiable HTTP library version can expose it to known client-side flaws or credential-handling issues.
The optional tavily-python package is also unpinned, so environments that enable this source may install inconsistent or newly introduced vulnerable releases. Even though it is optional, it still expands the skill's attack surface when used for external news retrieval.
requests>=2.25.0
# Optional dependencies for news sources
tavily-python>=0.3.0
# Optional dependencies for LLM scoring
openai>=1.0.0
An unpinned openai SDK version can change API behavior and introduce security-relevant defects or transitive dependency issues without notice. Since this skill may use the SDK for scoring or processing external content, predictable and reviewed dependency versions are important.
tavily-python>=0.3.0
# Optional dependencies for LLM scoring
openai>=1.0.0
anthropic>=0.20.0
No suspicious patterns detected.