T09 · Insecure Skill Coding Practices
- Location
scripts/browser_fallback.py:27- Finding
Shell Command Injection in the Agent Browser Helper
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill broadly matches its AI news reporting purpose, but it contains unsafe automation and dependency behavior that should be reviewed before installation.
Install only in an isolated, low-privilege environment after reviewing the code. Preinstall pinned dependencies through your normal deployment process, avoid the automatic yt-dlp install path, restrict RSS feeds to trusted HTTPS domains, protect config.json and the Feishu webhook as secrets, and do not run the scheduler under a privileged account until the shell-based browser helper is removed or tightly constrained.
scripts/browser_fallback.py:27Shell Command Injection in the Agent Browser Helper
scripts/youtube_collector.py:62Automatic Retrieval, Installation, and Import of an Unpinned Package
scripts/rss_collector.py:43Server-Side Request Forgery Through Unrestricted RSS URLs
scripts/setup_config.py:82Feishu Webhook Secret Stored in a Plaintext File Without Enforced Permissions
scripts/collect_ai_news.py:75arXiv Feed Retrieved Over Plaintext HTTP
There is a clear description-behavior mismatch. The declared purpose describes a production news aggregation and reporting system with external content fetching and report delivery. The actual code chunk only handles local packaging/distribution of a skill, including validation of SKILL.md and creation of a zip-based .skill file. These capabilities are materially different from the declared functionality, and the described news collection/reporting behavior is absent from the supplied code.
Referenced artifact was not completely inspected
pip install -r references/requirements.txt
Using shell=True with a dynamically assembled command is a classic tool-parameter abuse pattern because the shell interprets special characters, separators, and substitutions. In this skill context, the risk is heightened because URLs and extractor inputs may come from external feeds or configuration, making accidental or malicious injection more plausible in an automation pipeline.
"""
try:
full_cmd = f"agent-browser {command}"
result = subprocess.run(
full_cmd,
shell=True,
capture_output=True,
This markdown file documents editing config.json with a Feishu webhook_url and chat_id, which are sensitive integration details. The installation guide does not warn users to keep these values private, avoid committing them to source control, or treat them as secrets.
The skill advertises and documents use of shell commands, local file access, configuration writes, and outbound network access, but it does not declare any explicit tool scope or permissions boundary in the manifest. This creates an authorization transparency gap: operators cannot easily assess or restrict what the skill may do, increasing the chance of over-privileged execution or unsafe deployment.
The skill explicitly instructs users to generate and push reports to Feishu, but it does not warn that collected content and possibly metadata will be transmitted to an external third-party service. In enterprise or privacy-sensitive environments, this can lead to unintentional data disclosure, policy violations, or sharing of scraped/internal-enriched content outside approved channels.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# Edit crontab
crontab -e
# Add lines:
0 6 * * * cd /path/to/ai-daily-news && python scripts/collect_ai_news.py
The module docstring is written entirely in Chinese and does not indicate any language choice or opt-in. Under the policy for natural-language content, forcing a specific language without user selection is a locale/language policy concern.
This helper exposes a broad command-execution surface through run_agent_browser_command(command, ...), even though the skill's purpose is only to collect news from known sources. A news collection skill does not need arbitrary shell-mediated browser command strings, so this creates unnecessary capability that can be abused for actions beyond scraping.
The code performs dynamically constructed shell execution of browser commands without any confirmation, policy gate, or user-visible warning. In an automated skill, this increases the chance that dangerous or out-of-scope actions occur silently, especially when combined with caller-controlled command content.
The code builds a shell command string from a caller-controlled command value and executes it with subprocess.run(..., shell=True). If any part of command is influenced by untrusted input, shell metacharacters can escape the intended agent-browser invocation and execute arbitrary OS commands on the host.
"""
try:
full_cmd = f"agent-browser {command}"
result = subprocess.run(
full_cmd,
shell=True,
capture_output=True,
The fallback scraper accepts js_extractor and passes it into agent-browser eval, enabling arbitrary JavaScript execution in the browser context. While this may not directly execute OS commands by itself, it expands the skill from passive data collection into active page-script execution, which can manipulate page state, exfiltrate accessible page data, or interact with sites in unintended ways.
This code file contains natural-language descriptions and runtime log/messages exclusively in Chinese, which effectively forces a specific language for users and operators. Under the policy, locale or language constraints should either be optional for the user or clearly documented as justified and intentional.
This Python file contains the primary description and operational messages entirely in Chinese, including the module docstring and runtime logs/help text. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified, which is not present here.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
'Content-Type': 'application/json'
}
response = requests.post(webhook_url, json=message, headers=headers, timeout=30)
response_data = response.json()
if response_data.get('code') == 0:
This collector expands its environment by installing software at runtime, which exceeds passive news collection and creates a supply-chain risk surface. A compromised package, typo-squatted dependency, or unexpected dependency resolution could lead to code execution in the host environment when the skill runs.
The script performs package installation automatically with no user-facing confirmation or administrative approval. In an agent-skill context, that behavior is more dangerous because the skill may run unattended on shared infrastructure, silently changing the system state and pulling code from the network without operator awareness.
The code invokes pip at runtime to install yt-dlp automatically if the module is missing. Dynamically modifying the execution environment during normal operation is dangerous because it introduces unpinned third-party code from an external package index, can execute arbitrary install-time package code, and bypasses normal dependency review and deployment controls.
import yt_dlp
except ImportError:
logger.warning("yt-dlp 未安装,尝试使用pip安装...")
subprocess.check_call(['pip', 'install', '-q', 'yt-dlp'])
import yt_dlp
channel_url = f"https://www.youtube.com/{creator_config.get('handle', '')}/videos"
This manifest/config file contains multiple Chinese-language comment strings and sets the default timezone to Asia/Shanghai, which can amount to an implicit locale preference rather than a neutral or user-selectable default. Because the file does not indicate that the skill is region-specific or provide an opt-in choice for language/locale, it may conflict with organizational language/locale policy guidance.
The dependency is specified with a lower bound only, so builds may resolve to different versions over time and across environments. That weakens supply-chain control and makes it difficult to verify whether a known-vulnerable or incompatible release is being installed, especially in an automated news collection system that regularly fetches untrusted remote content.
requests>=2.31.0
feedparser>=6.0.10
schedule>=1.2.0
pyyaml>=6.0.1
requests has known advisories, and because the requirement is not pinned, there is no reliable way to determine whether deployments will use a fixed or vulnerable version. In a network-heavy automation skill that fetches external resources, uncertainty around HTTP client security is more significant because it directly handles remote inputs and credentials/session data.
Using feedparser>=6.0.10 allows uncontrolled version drift and prevents reproducible installs. Because this skill ingests external RSS/Atom feeds, unresolved dependency versions increase the chance of pulling a release with parser-related security regressions or known advisories.
requests>=2.31.0
feedparser>=6.0.10
schedule>=1.2.0
pyyaml>=6.0.1
python-dateutil>=2.8.2
feedparser has multiple historical advisories, and the manifest does not pin a specific version, so the installed release cannot be verified as safe. Because the skill continuously ingests third-party feeds, parser vulnerabilities are more relevant than they would be in an offline-only application.
An unpinned schedule dependency is a supply-chain hygiene issue because installation may pull different releases at different times. While the package itself is not inherently dangerous from this file alone, non-deterministic dependency resolution still reduces assurance and can introduce unexpected vulnerable versions.
requests>=2.31.0
feedparser>=6.0.10
schedule>=1.2.0
pyyaml>=6.0.1
python-dateutil>=2.8.2
beautifulsoup4>=4.12.2
PyYAML has a history of unsafe-deserialization issues, and leaving it unpinned means the environment may resolve to a vulnerable or unreviewed release. In a configurable automation skill, YAML is often used for configuration, so dependency ambiguity is more dangerous than in a purely local, static tool.
requests>=2.31.0
feedparser>=6.0.10
schedule>=1.2.0
pyyaml>=6.0.1
python-dateutil>=2.8.2
beautifulsoup4>=4.12.2
lxml>=4.9.3
No suspicious patterns detected.