T09 · Insecure Skill Coding Practices
- Location
scripts/monitor.py:340- Finding
Unrestricted URL Fetching and Webhook Destinations Enable SSRF
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a real web-monitoring skill, but it has review-worthy risks around unvalidated imports, arbitrary URL/webhook destinations, local file writes, and dashboard script injection.
Install only if you are comfortable reviewing the code and using it with trusted monitor configurations. Avoid importing monitor JSON from untrusted sources, do not monitor local/private/internal URLs, be careful with webhook destinations and payload sensitivity, and prefer a virtual environment with pinned dependencies if you enable optional engines.
scripts/monitor.py:340Unrestricted URL Fetching and Webhook Destinations Enable SSRF
scripts/monitor.py:2394Stored Script Injection in the Generated Local Dashboard
scripts/monitor.py:1921Imported Monitor IDs Enable Path Traversal and Writes Outside the Storage Directory
SKILL.md:257Unpinned Third-Party Package and Browser Installation Instructions
The documented purpose is web monitoring, but the skill also includes behaviors that affect local state and external interactions beyond that core scope, including import/export, feedback/debug collection, and opening browser content. This mismatch can mislead users and orchestration systems about the true risk surface, causing actions with privacy or integrity implications to occur without informed consent.
The skill exposes significant capabilities (shell, network, file read/write, environment access) but does not declare any tool scope or permissions boundaries in the manifest. That creates a trust and governance gap: an agent may invoke powerful operations without explicit limitation, making misuse, accidental overreach, or unsafe execution more likely.
The invocation guidance uses broad trigger words like watch, track, monitor, and check, which can cause the skill to activate in situations where the user did not intend persistent monitoring or network access. Over-broad activation increases the chance of unintended external requests, file persistence, or state changes being performed automatically.
The webhook feature sends monitoring event data to arbitrary third-party endpoints, but the documentation does not clearly warn users that monitored page content or derived metadata may leave the local system. In a monitoring context, captured content, URLs, pricing, stock status, or change summaries may contain sensitive or proprietary information, and silent exfiltration to external endpoints is a meaningful privacy risk.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
3. Many e-commerce sites block Python's default HTTP clients
"""
try:
result = subprocess.run(
["curl", "-sL", "--max-time", "30", "-A",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
# curl
try:
result = subprocess.run(["curl", "--version"], capture_output=True, text=True, timeout=5)
version = result.stdout.split('\n')[0].strip() if result.returncode == 0 else None
if version:
print(f" curl: {_green('✅ installed')} ({version.split()[1] if len(version.split()) > 1 else version})")
The feedback feature collects local system details and constructs a GitHub issue URL embedding that data, which expands the skill's data collection beyond core web monitoring. This creates an unnecessary privacy risk because users may disclose environment details and free-form messages to an external service without strong minimization or explicit consent flow.
The feedback command stores arbitrary user messages together with system details in a persistent local log without clearly warning about retention. That can capture sensitive data users include in bug reports and leave it accessible on disk longer than expected.
This code both persists user feedback plus system details locally and embeds the same material into a generated external GitHub issue URL, increasing the chance of accidental data disclosure. Because feedback text is free-form, users may include secrets, internal URLs, or personal data that then becomes stored and prepared for transmission outside the local system.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
feedback_log = STORE_DIR / "feedback.log"
ensure_dirs()
timestamp = datetime.now(timezone.utc).isoformat()
with open(feedback_log, "a", encoding="utf-8") as f:
f.write(f"\n--- {timestamp} ---\n{message}\n{sys_info}\n")
# Build GitHub issue URL
The debug command inventories local environment details and prints recent feedback log contents, exposing potentially sensitive operational and user-provided data that is not strictly required for monitoring functionality. In shared terminals, logs, or support screenshots, this can leak prior messages, filesystem paths, platform details, and monitor metadata.
The debug command prints recent feedback log entries, which may include sensitive prior user messages and environment details, directly to stdout without warning. This can unintentionally expose confidential data in terminal scrollback, recordings, CI logs, or shared support sessions.
The import command can create or modify persisted monitor state from file input, but the docs do not warn users about that side effect. This can lead to accidental state changes, addition of unwanted monitored URLs or webhooks, and persistence of attacker-supplied configuration if untrusted files are imported.
This is a markdown file, so SQP-2 applies to omitted warnings in the skill description. The examples encourage monitoring external sites, including a competitor pricing page, but provide no user-facing caution about potential policy, privacy, or site-terms implications of automated monitoring.
SQP-3 applies to all file types and covers language or locale policy issues. The example fixes scheduling to "Africa/Johannesburg" without indicating that users may change it or that the skill is South Africa-specific, which can impose an unintended locale default.
The manifest covers watching URLs, notifications, diffs, comparisons, templates, JS rendering, webhooks, and reporting on existing monitors. This code goes further by building a self-contained HTML console and launching it in the default browser, which is a broader UI/application behavior not reflected in the manifest description.
The HTML declares lang="en", and later date formatting uses a fixed English locale, which forces a specific language/locale presentation without user opt-in. This is a natural-language policy concern because the UI output is constrained to English formatting by default.
The JavaScript uses toLocaleDateString('en-ZA', ...) for date display, which imposes a specific regional locale on all users. The file does not provide a locale setting or explain why South African English formatting is required.
No suspicious patterns detected.