T09 · Insecure Skill Coding Practices
- Location
scripts/safe-web.py:71- Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill mostly does what it says, but needs review because it can fetch any address your machine can reach and its setup can alter system Python and create a system-wide command.
Install only if you are comfortable with a command that can fetch any URL reachable from your machine. Prefer running it in a restricted network environment, avoid the sudo symlink unless needed, use a virtual environment with pinned dependencies instead of --break-system-packages, and treat Brave search as sending your query and API key to Brave.
scripts/safe-web.py:71Unrestricted URL Fetching Enables Server-Side Request Forgery
README.md:23Unpinned Dependencies Are Installed into the System-Managed Python Environment
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
}
try:
response = requests.get(url, headers=headers, timeout=timeout, allow_redirects=True)
response.raise_for_status()
except requests.RequestException as e:
print(f"Error fetching URL: {e}", file=sys.stderr)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
}
try:
response = requests.get(
'https://api.search.brave.com/res/v1/web/search',
headers=headers,
params=params,
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.
By default, OpenClaw's native `web_fetch` and `web_search` tools fetch content directly without security scanning. Safe-web provides the same functionality but adds a critical security layer that scans all content for:
- Instruction override attempts ("ignore previous instructions")
- Role manipulation attacks ("you are now DAN")
- System impersonation patterns
- Hidden malicious payloads in web pages
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).
ning to detect and block prompt injection attacks hidden in web content, emails, PDFs, and documents before they reach the AI.
By default, OpenClaw's native web_fetch and web_search tools fetch content directly without security scanning. Safe-web provides the same functionality but adds a critical security layer that scans all content for:
# Install PromptGuard first
cd /home/linuxbrew/.openclaw/workspace/skills/prompt-guard
pip3 install --break-system-packages -e .
# Install web dependencies
pip3 install --break-system-packages requests beautifulsoup4
sudo ln -s /home/linuxbrew/.openclaw/workspace/skills/safe-web/scripts/safe-web.py /usr/local/bin/safe-web
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
sudo ln -s /home/linuxbrew/.openclaw/workspace/skills/safe-web/scripts/safe-web.py /usr/local/bin/safe-web
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
sudo ln -s /home/linuxbrew/.openclaw/workspace/skills/safe-web/scripts/safe-web.py /usr/local/bin/safe-web
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
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.
for result in results:
# Scan title
title_result = scan_with_promptguard(result['title'])
if title_result.severity.value >= getattr(title_result.severity, severity_threshold).value:
threats_found.append({
'field': 'title',
'url': result['url'],
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.
# Scan description
desc_result = scan_with_promptguard(result['description'])
if desc_result.severity.value >= getattr(desc_result.severity, severity_threshold).value:
threats_found.append({
'field': 'description',
'url': result['url'],
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.
result = scan_with_promptguard(content)
severity_threshold = "MEDIUM" if args.strict else "HIGH"
should_block = result.severity.value >= getattr(result.severity, severity_threshold).value
if args.json:
output = {
Detected: suspicious.prompt_injection_instructions