T01 · Skill Instruction Hijacking
- Location
scripts/nest-webhook.py:318- Finding
Unauthenticated public webhook permits forged events and Agent message injection
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This Nest skill is mostly purpose-aligned, but its always-on public webhook and alert forwarding create review-worthy privacy and security risks.
Review carefully before installing. Use this only if you are comfortable exposing a Nest event webhook through Cloudflare, sending doorbell/person snapshots and activity alerts to Telegram, and running persistent services. Require authenticated Pub/Sub push validation, pin and verify cloudflared, store tokens in restricted secret files or systemd credentials, avoid passing the full environment to subprocesses, and add explicit confirmation or opt-in for camera and third-party alerting paths.
scripts/nest-webhook.py:318Unauthenticated public webhook permits forged events and Agent message injection
scripts/nest-webhook.py:323Unbounded webhook request body permits remote denial of service
SKILL.md:183Unpinned and unverified executable is installed as a persistent service
SKILL.md:226Clawdbot hook bearer token is stored directly in a systemd unit
scripts/nest-webhook.py:181Camera snapshot temporary files are not reliably deleted
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
}).encode()
req = urllib.request.Request('https://oauth2.googleapis.com/token', data=data, method='POST')
with urllib.request.urlopen(req, timeout=10) as resp:
result = json.loads(resp.read())
_access_token['token'] = result['access_token']
_access_token['expires'] = time.time() + result.get('expires_in', 3600) - 60
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
'Content-Type': 'application/json',
})
with urllib.request.urlopen(req, timeout=15) as resp:
result = json.loads(resp.read())
image_url = result.get('results', {}).get('url')
image_token = result.get('results', {}).get('token')
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
'Content-Type': 'application/json',
})
with urllib.request.urlopen(req, timeout=15) as resp:
result = json.loads(resp.read())
image_url = result.get('results', {}).get('url')
image_token = result.get('results', {}).get('token')
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
img_req = urllib.request.Request(image_url, headers={
'Authorization': f'Basic {image_token}',
})
with urllib.request.urlopen(img_req, timeout=15) as img_resp:
image_data = img_resp.read()
print(f"[IMAGE] Downloaded {len(image_data)} bytes")
return image_data
The code transmits camera snapshots and event captions to Telegram automatically, which is a third-party external service unrelated to core Nest device control. In the context of a smart-home skill, this materially increases privacy risk because images of visitors or occupants can be disclosed off-platform without user confirmation or clear consent controls.
'Content-Type': f'multipart/form-data; boundary={boundary}',
})
with urllib.request.urlopen(req, timeout=15) as resp:
result = json.loads(resp.read())
if result.get('ok'):
print(f"[TELEGRAM] Photo sent successfully")
Event alerts are sent to Telegram based on environment-configured bot credentials and chat ID, creating an external disclosure path for occupancy/security events. Even without images, doorbell/person alerts reveal presence patterns and home activity to a third party.
'Content-Type': 'application/json',
})
with urllib.request.urlopen(req, timeout=10) as resp:
return json.loads(resp.read()).get('ok', False)
except Exception as e:
print(f"[TELEGRAM] Error: {e}")
The webhook forwards event metadata to a gateway URL fully controlled by the CLAWDBOT_GATEWAY_URL environment variable, with no allowlist or origin restriction. If that variable is misconfigured or attacker-controlled, sensitive occupancy/event data and the bearer hook token can be sent to an arbitrary server, enabling exfiltration and token abuse.
'Content-Type': 'application/json',
},
)
urllib.request.urlopen(req, timeout=5)
except Exception as e:
print(f"[HOOK] Error: {e}")
The documented behavior includes undisclosed credential retrieval from 1Password and device enumeration while omitting or overstating features like temperature scheduling and direct doorbell handling. Security-relevant behavior hidden behind an inaccurate description undermines informed approval and can expose secrets or device metadata under the guise of ordinary home automation.
The documented behavior includes undisclosed credential retrieval from 1Password and device enumeration while omitting or overstating features like temperature scheduling and direct doorbell handling. Security-relevant behavior hidden behind an inaccurate description undermines informed approval and can expose secrets or device metadata under the guise of ordinary home automation.
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).
---
name: nest-devices
description: Control Nest smart home devices (thermostat, cameras, doorbell) via the Device Access API. Use when asked to check or adjust home temperature, view camera feeds, check who's at the door, monitor rooms, or set up temperature schedules.
metadata:
clawdbot:
emoji: "🏠"
---
# Nest Device Access
Control Nest devices via Google's Smart Device Management API.
## Setup
### 1. Google Cloud & Device Access
1. Create a Google Cloud project at [console.cloud.google.com](https://console.cloud.google.com)
2. Pay the $5 fee and create a Device Access project at [console.nest.google.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 1Password token for Nest API credentials
OP_TOKEN = os.environ.get('OP_SVC_ACCT_TOKEN', '')
# Cache for Nest credentials and access token
_nest_creds = {}
_access_token = {'token': None, 'expires': 0}
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 1Password token for Nest API credentials
OP_TOKEN = os.environ.get('OP_SVC_ACCT_TOKEN', '')
# Cache for Nest credentials and access token
_nest_creds = {}
_access_token = {'token': None, 'expires': 0}
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# 1Password token for Nest API credentials
OP_TOKEN = os.environ.get('OP_SVC_ACCT_TOKEN', '')
# Cache for Nest credentials and access token
_nest_creds = {}
_access_token = {'token': None, 'expires': 0}
The code clones the full process environment and passes it to the 1Password CLI, which broadens exposure of unrelated secrets to a child process unnecessarily. If the child process, its plugins, or diagnostics are compromised, environment-resident credentials beyond the intended service-account token may leak.
print("[NEST] No OP_SVC_ACCT_TOKEN set")
return None
env = {**os.environ, 'OP_SERVICE_ACCOUNT_TOKEN': OP_TOKEN}
op = os.path.expanduser('~/.local/bin/op')
vault_id = 'Alfred' # Use vault name
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
"""
# Try 1Password first
op_token = None
for key in os.environ:
if key.startswith('OP_TOKEN_') or key == 'OP_SERVICE_ACCOUNT_TOKEN':
op_token = os.environ[key]
break
Passing the entire parent environment into the op subprocess unnecessarily exposes all ambient secrets and runtime context to an external binary. If the op binary is compromised, replaced via PATH ambiguity, or behaves unexpectedly, unrelated credentials in the environment could be disclosed beyond what this skill actually needs.
result = subprocess.run(
[op_path, 'item', 'get', item, '--vault', vault, '--format', 'json'],
capture_output=True, text=True,
env={**os.environ, 'OP_SERVICE_ACCOUNT_TOKEN': op_token}
)
if result.returncode == 0:
item_data = json.loads(result.stdout)
The skill declares no explicit tool/permission scope even though the documentation clearly requires shell access, network access, and environment/secret access. In an agent setting, missing scope boundaries increases the chance the skill is invoked with broader capabilities than users expect, especially given it touches cameras, thermostats, cloud APIs, tunnels, and local services.
The invocation text uses broad natural-language triggers such as monitoring rooms or checking who is at the door, which could match common conversational requests and cause over-selection of a high-privilege home surveillance skill. In agent systems, overly broad routing language can lead to unintended access to cameras, device metadata, or control functions without sufficiently specific user intent.
The skill advertises camera feeds, room monitoring, and photo alerts without an explicit privacy warning or notice about transmitting images/events to third parties. In the smart-home context this is more dangerous because the data concerns occupants, visitors, and household activity, making silent or poorly disclosed monitoring particularly sensitive.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# 2. Authorize and copy the 'code' parameter from the redirect URL
# 3. Exchange code for tokens:
curl -X POST https://oauth2.googleapis.com/token \
-d "client_id=CLIENT_ID" \
-d "client_secret=CLIENT_SECRET" \
-d "code=AUTH_CODE" \
The documentation broadens the skill from direct Nest control into an event-forwarding and alerting system involving webhooks, Cloudflare exposure, Clawdbot hooks, and Telegram delivery. That scope expansion materially changes the trust model by moving from user-triggered control to automated surveillance-style event processing and outbound sharing.
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.
Generate a token: openssl rand -hex 24
gcloud config set project YOUR_GCP_PROJECT_ID
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# Install cloudflared
curl -L -o ~/.local/bin/cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
chmod +x ~/.local/bin/cloudflared
# Authenticate (opens browser)
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable --now nest-webhook cloudflared-nest
Enabling services with sudo causes the webhook listener and tunnel to start automatically and persist across reboots, increasing the blast radius of any misconfiguration or compromise. In the context of a smart-home camera/doorbell integration, persistent background network services materially raise exposure beyond one-off device control.
sudo systemctl daemon-reload
sudo systemctl enable --now nest-webhook cloudflared-nest
No suspicious patterns detected.