T09 · Insecure Skill Coding Practices
- Location
scripts/price_watch.py:302- Finding
Unrestricted Product URL Fetching Enables Server-Side Request Forgery
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This price monitor mostly matches its stated purpose, but it can be pointed at arbitrary URLs and may make requests to unintended internal systems.
Review before installing in sensitive environments. Only add trusted public product URLs, avoid running it where it can reach internal admin panels or cloud metadata services, use trusted notification endpoints, and prefer pinned install/run commands instead of live latest-resolution npx examples.
scripts/price_watch.py:302Unrestricted Product URL Fetching Enables Server-Side Request Forgery
The skill advertises Slack, Telegram, Email, and custom webhook alerting but does not clearly warn that competitor URLs, pricing details, recommendations, and related metadata may be transmitted to third-party endpoints outside the local SQLite store. This creates a privacy and data-governance risk because users may assume all operational data remains local based on the later 'stored locally' claim.
The skill instructs users to execute npx clawhub@latest install smtm-pricewatch, which pulls and runs the latest package version at install time rather than a pinned, reviewed release. If the package or its dependency chain is compromised upstream, users could execute attacker-controlled code during installation or skill invocation.
This run command uses unpinned npx clawhub, causing the executing environment to fetch whatever version is current at runtime. That creates a supply-chain execution risk because a malicious or compromised package update could run arbitrary code when the user performs a scan.
The documented npx clawhub command for adding a product relies on an unpinned package version, so users may unknowingly execute newly published code outside their review. Because this operation may process user-supplied URLs and local config, a compromised upstream package could abuse those inputs or exfiltrate configuration data.
Using npx clawhub without a fixed version for the history command exposes users to the same package substitution or malicious update risk at execution time. Since the command may access local price history data, a compromised CLI could tamper with or extract that data.
The report-generation example again invokes an unpinned npx clawhub, which permits runtime retrieval of whatever package version is currently published. In a supply-chain compromise scenario, that could lead to arbitrary code execution and disclosure of locally stored monitoring data or credentials used for notifications.
This code sends alert contents, including product names, platform, and price-change details, to an external Slack webhook via HTTP. While the function has an internal docstring, there is no confirmation prompt or broader user-facing disclosure in the CLI flow that scanning may forward monitored data to third-party services.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
}
]
}
resp = requests.post(webhook, json=message, timeout=10)
return resp.status_code == 200
except Exception as e:
print(f"Slack notification failed: {e}")
The Telegram notification path posts product names, platform, and pricing details to the Telegram Bot API, which is a network transmission of monitored data to a third party. The code lacks a visible confirmation or user-facing notice in the command interface that this external transmission can occur when alerting is configured.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
f"Old: ${alert['old_price']:.2f} → New: ${alert['new_price']:.2f}\n\n"
f"💡 {alert['recommendation']}"
)
url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
resp = requests.post(url, json={
"chat_id": chat_id,
"text": text,
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
f"💡 {alert['recommendation']}"
)
url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
resp = requests.post(url, json={
"chat_id": chat_id,
"text": text,
"parse_mode": "Markdown"
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
f"💡 {alert['recommendation']}"
)
url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
resp = requests.post(url, json={
"chat_id": chat_id,
"text": text,
"parse_mode": "Markdown"
The comment says threshold_percent is the minimum percent change to trigger an alert, but it does not clearly specify whether this applies to price drops only, any price movement, or deviation from the target price versus previous price. In a manifest/config file, this kind of ambiguity can cause unintended triggering behavior or misconfiguration.
The scraper hard-codes an Accept-Language header of en-US,en;q=0.9 for all requests, which forces a specific locale regardless of user preference. This is a natural-language policy issue because the skill does not offer a language or locale choice, nor document a justified region-specific constraint.
The docstring states the extractor 'Uses the Amazon Product API if configured, otherwise parses HTML,' which implies an API-based code path exists. In reality, the function immediately performs a direct HTTP GET on the supplied URL and parses the returned HTML, with no API configuration or API call present.
No suspicious patterns detected.