T09 · Insecure Skill Coding Practices
- Location
scripts/auth.py:75- Finding
Gateway credentials and SMS data may be transmitted over plaintext HTTP
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill has a plausible SMS-gateway purpose, but it handles SMS content and credentials with weak network and webhook safeguards.
Review carefully before installing. Use only a trusted HTTPS or protected local/VPN gateway, avoid public ngrok exposure unless you add authentication, disable or tightly control OPENCLAW_WEBHOOK_URL forwarding, protect .env and .token.json permissions, and remember this skill can send SMS, read message data, and change webhook configuration.
scripts/auth.py:75Gateway credentials and SMS data may be transmitted over plaintext HTTP
scripts/auth.py:54JWT bearer token is cached without explicit restrictive file permissions
scripts/webhook_server.py:9Unauthenticated public webhook receiver forwards attacker-controlled JSON to OpenClaw
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
)
try:
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read().decode())
_write_cached_token(data)
return data['access_token']
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
method=method
)
with urllib.request.urlopen(req, timeout=30) as resp:
return json.loads(resp.read().decode())
The server forwards full incoming SMS webhook bodies to a URL controlled by the OPENCLAW_WEBHOOK_URL environment variable without validation, restriction, or authentication. Because SMS contents often contain highly sensitive data such as OTPs, personal messages, and phone numbers, this creates a clear exfiltration path and can leak data to any endpoint configured in the environment.
headers={'Content-Type': 'application/json'},
method='POST'
)
urllib.request.urlopen(req, timeout=5)
except Exception as e:
print(f" ⚠️ Could not forward to OpenClaw: {e}")
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
cp .env.example .env
.env with your gateway URL and credentials:The declared description presents a broad SMS management capability, including sending messages, checking status, viewing history, and webhook management. The actual code chunk is much narrower: it only receives webhook HTTP requests, prints their contents, and optionally forwards them to a configured OpenClaw endpoint. While this partially aligns with 'manage webhooks for incoming SMS,' it does not implement the other central described capabilities. Additionally, forwarding incoming webhook data to another service is a network behavior not mentioned in the description. Therefore the code chunk does not accurately represent the full declared purpose.
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
GET /webhooks
POST /webhooks {"event": "sms:received", "url": "https://example.com"}
DELETE /webhooks/{event}
Webhook events:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def _load_env():
"""Load .env from the skill root directory."""
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), '.env')
if os.path.exists(env_path):
with open(env_path) as f:
for line in f:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def _load_env():
"""Load .env from the skill root directory."""
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), '.env')
if os.path.exists(env_path):
with open(env_path) as f:
for line in f:
The code sources a destination URL from an environment variable and uses it to forward incoming SMS webhook contents, enabling transmission to an arbitrary endpoint. In the context of an SMS gateway, this is especially dangerous because the forwarded payload may contain sensitive communications and verification codes, making the behavior functionally equivalent to data exfiltration if misused or misconfigured.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
"""Integration tests for SMS Gateway skill.
Requires SMS_GATE_URL, SMS_GATE_USER, and SMS_GATE_PASS in .env or environment.
Tests call the actual scripts in scripts/ as subprocesses.
"""
import json
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
"""Integration tests for SMS Gateway skill.
Requires SMS_GATE_URL, SMS_GATE_USER, and SMS_GATE_PASS in .env or environment.
Tests call the actual scripts in scripts/ as subprocesses.
"""
import json
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
"""Integration tests for SMS Gateway skill.
Requires SMS_GATE_URL, SMS_GATE_USER, and SMS_GATE_PASS in .env or environment.
Tests call the actual scripts in scripts/ as subprocesses.
"""
import json
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
"""Integration tests for SMS Gateway skill.
Requires SMS_GATE_URL, SMS_GATE_USER, and SMS_GATE_PASS in .env or environment.
Tests call the actual scripts in scripts/ as subprocesses.
"""
import json
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
"""Integration tests for SMS Gateway skill.
Requires SMS_GATE_URL, SMS_GATE_USER, and SMS_GATE_PASS in .env or environment.
Tests call the actual scripts in scripts/ as subprocesses.
"""
import json
The README explicitly instructs users to expose an incoming-SMS webhook via ngrok or a LAN-accessible HTTP endpoint, but it does not warn that SMS contents and sender numbers will be transmitted to that endpoint. This creates a real confidentiality risk because users may unintentionally forward sensitive inbound messages to a public internet URL or an unauthenticated local listener, increasing the chance of interception, logging leakage, or misdelivery.
The skill requires environment secrets and instructs use of Python scripts, networking, file access, and shell commands, but it does not declare any explicit tool scope or permission boundaries. That creates an over-privileged execution model where an agent may invoke broader capabilities than users expect, increasing the chance of secret exposure, unintended network access, or misuse of local resources.
The documentation encourages sending SMS content and managing message operations without clearly warning that phone numbers, message text, and delivery metadata are sensitive data. Users may disclose personal or regulated information through the skill without understanding the privacy implications or retention/exposure risks.
The webhook instructions recommend exposing inbound SMS via ngrok or other remotely reachable endpoints, but they do not clearly warn that incoming message contents may be transmitted through third-party infrastructure or exposed to the public internet. Because SMS messages often contain highly sensitive data such as OTPs, personal messages, or account notifications, this omission materially increases the risk of interception, misconfiguration, or unintended disclosure.
This markdown file describes behaviors that transmit phone numbers, message contents, and webhook data over network endpoints, including outbound SMS and callback URLs. It does not include any warning about handling personal data, message disclosure, or the privacy/system implications of configuring webhooks.
The code writes a bearer token cache to .token.json in the skill root without setting restrictive file permissions or protecting the location. On multi-user systems or permissive environments, another local user or process could read the cached token and use it to access SMS read/send capabilities until expiry.
The code reads SMS_GATE_USER and SMS_GATE_PASS, constructs a Basic Authorization header, and transmits those credentials to a remote /auth/token endpoint. While network authentication is part of the helper's purpose, the file does not provide any user-facing notice that local credentials will be sent to an external service.
This code retrieves message data from an external API and later displays sender phone numbers and message text. While the module docstring says it checks for incoming SMS, it does not explicitly warn that private message contents and identifiers will be fetched and surfaced to the user, which is a user-data/privacy-relevant behavior under the warning rule.
The webhook receiver performs an additional data-forwarding function beyond simply receiving local SMS gateway webhooks, expanding the skill’s behavior beyond its stated role. That mismatch matters because it silently redistributes inbound SMS data to another service, increasing data exposure and trust boundary violations.
The file forwards webhook payloads onward without any in-file warning, consent flow, or disclosure that inbound SMS data will be retransmitted. Lack of transparency around secondary handling of sensitive SMS data increases the chance of unnoticed privacy violations and unsafe deployment by users who assume the tool is only local.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def run_script(script_name, args=None):
"""Run a script from scripts/ and return (stdout, stderr, returncode)."""
cmd = ['python3', os.path.join(SCRIPTS_DIR, script_name)] + (args or [])
result = subprocess.run(cmd, capture_output=True, text=True)
return result.stdout.strip(), result.stderr.strip(), result.returncode