Back to skill

Security audit

Cloudflare Agent Tunnel

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it advertises, but it can persistently expose a local OpenClaw service to the internet and runs the tunnel as a root system service without enough access-control guidance.

Install only if you intend to administer a VPS and deliberately publish the selected OpenClaw agent port through Cloudflare. Before using it, require application authentication or Cloudflare Access, verify the local port is the intended OpenClaw service, avoid quick tunnels for sensitive services, and prefer a dedicated non-root cloudflared user with hardened systemd settings and documented cleanup/revocation steps.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T06 · System Persistence

Error
Location
scripts/tunnel-setup.sh:97
Finding

Reboot-Persistent Cloudflare Tunnel Runs with Unnecessary Root Privileges

Content
View full analysis
"$SERVICE_FILE" << EOF [Unit] Description=Cloudflare Tunnel for OpenClaw agent: ${AGENT} After=network.target [Service] Type=simple User=root ExecStart=/usr/bin/cloudflared tunnel --no-autoupdate --config ${CONFIG_FILE} run Restart=always RestartSec=5 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable "$SERVICE_NAME" systemctl restart "$SERVICE_NAME" ``` The documented equivalent in `SKILL.md` also explicitly enables the persistent service: ```bash systemctl daemon-reload systemctl enable cloudflared-koda systemctl start cloudflared-koda systemctl is-active cloudflared-koda ``` The multi-agent instructions in `references/custom-domains.md` enable several persistent services: ```bash systemctl daemon-reload systemctl enable cloudflared-koda cloudflared-alex cloudflared-jordan systemctl start cloudflared-koda cloudflared-alex cloudflared-jordan ``` ### Technical Analysis The setup writes a system-level unit into `/etc/systemd/system`, enables it for startup under `multi-user.target`, and configures `Restart=always`. The resulting Cloudflare tunnel survives completion of the Skill, automatically starts after reboot, and reconnects whenever it exits. Cross-session persistence is relevant to the declared permanent-tunnel feature and is openly documented rather than concealed. Nevertheless, the implementation exceeds minimum necessary privileges because `cloudflared` is explicitly run as `root`. A tunnel process generally only needs permission to read its own configuration and credential file and ...[truncated 1834 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/tunnel-setup.sh:76
Finding

Local OpenClaw Service Is Published to the Internet Without Requiring Access Control

Content
View full analysis
"$CONFIG_FILE" << EOF tunnel: ${TUNNEL_UUID} credentials-file: ${CREDS_FILE} ingress: - hostname: ${DOMAIN} service: http://localhost:${PORT} - service: http_status:404 EOF echo "Config written: ${CONFIG_FILE}" # Route DNS (adds CNAME record in Cloudflare dashboard) echo "Routing DNS: ${DOMAIN} → ${TUNNEL_NAME}..." cloudflared tunnel route dns "$TUNNEL_NAME" "$DOMAIN" || { echo "" echo "⚠ DNS routing failed — you may need to add this CNAME manually in Cloudflare:" echo " Name: $(echo $DOMAIN | cut -d. -f1)" echo " Target: ${TUNNEL_UUID}.cfargotunnel.com" echo " Proxy: ON (orange cloud)" } ``` ### Technical Analysis The generated ingress rule forwards requests for the selected public hostname directly to `http://localhost:${PORT}`. The script then creates, or instructs the operator to create, a public DNS record for that tunnel. The workflow does not require or validate an authentication mechanism for the OpenClaw endpoint. It also does not configure a Cloudflare Access policy, identity-aware proxy rule, mutual TLS requirement, or another deny-by-default access layer before publishing the hostname. The documented `allowedOrigins` setting controls browser-origin behavior such as CORS; it is not an authentication or authorization boundary. Adding the public hostname to `allowedOrigins` therefore does not prevent unauthorized clients from directly reaching the service. The tunnel avoids opening an inbound VPS firewall port, but that does not make the application private. Cloudflare accepts internet traffic for the hostname and relays it through the outbound tunnel to the localhost service. ### Attack Path 1. An o ...[truncated 1455 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (12)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

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).

Content

Scanner excerpt · SKILL.md (reported line 204)May include surrounding context.

Delete a tunnel

cloudflared tunnel delete openclaw-koda systemctl disable cloudflared-koda && rm /etc/systemd/system/cloudflared-koda.service

text

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 41)May include surrounding context.

md
# Install cloudflared if missing
if ! command -v cloudflared &>/dev/null; then
  echo "Installing cloudflared..."
  curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
  echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main" \
    | tee /etc/apt/sources.list.d/cloudflared.list
  apt-get update -qq && apt-get install -y cloudflared

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 42)May include surrounding context.

md
# Install cloudflared if missing
if ! command -v cloudflared &>/dev/null; then
  echo "Installing cloudflared..."
  curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
  echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main" \
    | tee /etc/apt/sources.list.d/cloudflared.list
  apt-get update -qq && apt-get install -y cloudflared

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/tunnel-setup.sh (reported line 34)May include surrounding context.

sh
# Install cloudflared if missing
if ! command -v cloudflared &>/dev/null; then
  echo "Installing cloudflared..."
  curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
  echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main" \
    | tee /etc/apt/sources.list.d/cloudflared.list
  apt-get update -qq && apt-get install -y cloudflared

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/tunnel-setup.sh (reported line 35)May include surrounding context.

sh
# Install cloudflared if missing
if ! command -v cloudflared &>/dev/null; then
  echo "Installing cloudflared..."
  curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
  echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main" \
    | tee /etc/apt/sources.list.d/cloudflared.list
  apt-get update -qq && apt-get install -y cloudflared

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill contains extensive shell commands that install packages, create privileged config files, modify systemd units, and change firewall state, yet it declares no tool restrictions. In an agent setting, missing scope increases the chance the skill could be invoked with broader-than-necessary execution privileges, enabling unintended system modification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill tells the operator to change firewall policy with ufw deny 18789 but does not clearly warn about validating the management path first or checking existing remote-access rules. Firewall changes on a VPS can accidentally cut off required access paths or break the application if the tunnel is not yet confirmed working.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The quick-tunnel path publishes a localhost service to a public Cloudflare URL with no authentication, access control, or prominent warning about external exposure. In the context of an agent skill designed to expose local agent ports, this can unintentionally make sensitive local services internet-accessible, especially if users assume localhost implies private access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This shell script writes configuration under /etc, creates a systemd unit, installs packages via apt-get, and enables/restarts a root-run service. Although the actions are echoed as they occur, the script lacks a clear upfront warning that it will modify system configuration and persist a background service, which is a safety-relevant disclosure for a code file.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

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.

Content

Scanner excerpt · SKILL.md (reported line 115)May include surrounding context.

md
EOF

systemctl daemon-reload
systemctl enable "$SERVICE_NAME"
systemctl restart "$SERVICE_NAME"
sleep 3
systemctl status "$SERVICE_NAME" --no-pager | head -10

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

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.

Content

Scanner excerpt · references/custom-domains.md (reported line 153)May include surrounding context.

md
EOF

systemctl daemon-reload
systemctl enable "$SERVICE_NAME"
systemctl restart "$SERVICE_NAME"
sleep 3
systemctl status "$SERVICE_NAME" --no-pager | head -10

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

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.

Content

Scanner excerpt · scripts/tunnel-setup.sh (reported line 115)May include surrounding context.

sh
EOF

systemctl daemon-reload
systemctl enable "$SERVICE_NAME"
systemctl restart "$SERVICE_NAME"
sleep 3
systemctl status "$SERVICE_NAME" --no-pager | head -10

Static analysis

No suspicious patterns detected.