Back to skill

Security audit

Nest SDM

Security checks for vulnerabilities and agentic risk

Overview

This Nest skill is mostly purpose-aligned, but it handles sensitive home, camera, cloud, and messaging access with unsafe scripting patterns that need review before installation.

Install only if you are comfortable granting this skill access to control Nest devices, access camera-related data, create and modify Google Pub/Sub/IAM resources, store OAuth refresh tokens locally, log household events, and optionally send alerts to Telegram. Review and fix the unsafe python3 -c interpolation patterns before running it with real credentials, restrict token and log file permissions, avoid broad cloud-platform credentials where possible, and disable Telegram forwarding unless you explicitly want household activity sent there.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
nest-sdm.sh:77
Finding
Python Source Injection Through CLI Arguments<![CDATA[ ## Vulnerability Details **File Location**: `nest-sdm.sh`, lines 77-115 **Vulnerability Type**: Python source injection caused by unsafe interpolation **Risk Level**: High ### Vulnerable Code ```bash # --- Temperature conversion --- f_to_c() { python3 -c "print(round(($1 - 32) * 5/9, 1))"; } c_to_f() { python3 -c "print(round($1 * 9/5 + 32, 1))"; } # --- Device ID resolution --- # Auto-discover device IDs by type, optionally filtered by --name # Usage: get_device_id <TYPE> [name_filter] # name_filter matches against customName or room displayName (case-insensitive, substring) get_device_id() { local dtype="$1" local name_filter="${2:-}" api_get "devices" | python3 -c " import sys, json devices = json.load(sys.stdin).get('devices', []) name_filter = '''${name_filter}'''.strip().lower() matches = [] for d in devices: if d['type'] == 'sdm.devices.types.${dtype}': matches.append(d) if not matches: print(f'Error: No ${dtype} device found.', file=sys.stderr) sys.exit(1) if name_filter: filtered = [] for d in matches: custom = d.get('traits', {}).get('sdm.devices.traits.Info', {}).get('customName', '').lower() room = (d.get('parentRelations', [{}])[0].get('displayName', '') or '').lower() if name_filter in custom or name_filter in room: filtered.append(d) if not filtered: avail = [] for d in matches: custom = d.get('traits', {}).get('sdm.devices.traits.Info', {}).get('customName', '') room = d.get('parentRelations', [{}])[0].get('displayName', '') label = custom or room or '(unnamed)' avail.append(label) print(f'Error: No ${dtype} matching \"{name_filter}\". Available: {\", \".join(avail)}', file=sys.stderr) sys.exit(1) matches = filtered print(matches[0]['name'].split('/')[-1]) " } ``` A related instance occurs at line 414: ```bash echo "✅ Fan ON for ${duration}s ($(python3 -c "print(${duration} ...[truncated 2127 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Never construct Python source from shell variables. - Pass all values as positional arguments: ```bash f_to_c() { python3 - "$1" <<'PY' import sys value = float(sys.argv[1]) print(round((value - 32) * 5 / 9, 1)) PY } ``` - Pass `name_filter` and `dtype` through `sys.argv`, while continuing to read API JSON from standard input. - Validate temperatures against documented Nest operating ranges before making API calls. - Validate fan duration as a decimal integer and enforce a reasonable minimum and maximum. - Validate modes and device types with explicit allowlists. - Avoid `eval`, dynamically generated Python, and nested command interpolation. - Add regression tests containing quotes, triple quotes, backslashes, newlines, semicolons, and Python syntax in every CLI parameter. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
nest-events.sh:119
Finding
Remote Pub/Sub Event Data Is Embedded Into Executable Python Source<![CDATA[ ## Vulnerability Details **File Location**: `nest-events.sh`, lines 119-147 **Vulnerability Type**: Remote Python source injection **Risk Level**: Critical ### Vulnerable Code ```bash parse_event() { local event_data="$1" # Decode base64 data field local decoded decoded=$(echo "$event_data" | python3 -c " import sys, json, base64 try: msg = json.load(sys.stdin) data = msg.get('message', {}).get('data', '') if data: decoded = base64.b64decode(data).decode('utf-8') print(decoded) else: print('{}') except Exception as e: print(json.dumps({'error': str(e)})) " 2>/dev/null) echo "$decoded" } format_event_alert() { local event_json="$1" python3 -c " import json, sys from datetime import datetime try: event = json.loads('''${event_json}''') except: sys.exit(0) ``` The remote data reaches this function during event processing: ```bash decoded=$(echo "$msg_data" | parse_event) # Format alerts local alerts alerts=$(format_event_alert "$decoded") ``` ### Technical Analysis Pub/Sub message data is controlled by entities with permission to publish to the configured topic. The listener Base64-decodes this remote content and passes it as `event_json`. It then interpolates the decoded value directly into a triple-quoted literal inside a `python3 -c` program. JSON validation occurs only after Python has parsed the generated source code. It therefore cannot prevent source injection. Crafted data containing a suitable triple-quote termination sequence, escaping characters, and additional Python statements can alter the generated program before `json.loads` processes the value. This creates a network-reachable code-execution boundary. The attack does not require direct shell access to the host; it requires the ability to publish a crafted message to the relevant Pub/Sub topic or otherwise cause crafted content to be returned to the subscription. ### Attack Path 1. An attacker obtains or alre ...[truncated 1284 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pass event JSON through standard input instead of embedding it into Python source: ```bash format_event_alert() { python3 - <<'PY' import json import sys from datetime import datetime try: event = json.load(sys.stdin) except (ValueError, TypeError): sys.exit(0) # Process validated event data here. PY } ``` Invoke the function with: ```bash alerts=$(printf '%s' "$decoded" | format_event_alert) ``` - Use a quoted heredoc (`<<'PY'`) or a separate Python file so shell expansion cannot modify Python source. - Validate decoded data as UTF-8 JSON and enforce limits on message size and nesting depth. - Treat all resource names, timestamps, event IDs, and trait values as untrusted data. - Restrict Pub/Sub publishing rights to the documented SDM publisher principal and explicitly approved administrators. - Use a narrowly scoped runtime service account rather than broad user OAuth credentials. - Add tests using triple quotes, backslashes, newlines, malformed JSON, and oversized Base64 payloads. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
nest-sdm.sh:171
Finding
Remote SDM API Responses Are Embedded Into Python Programs<![CDATA[ ## Vulnerability Details **File Location**: `nest-sdm.sh`, lines 171-174 **Vulnerability Type**: Python source injection through unsafe remote-data parsing **Risk Level**: High ### Vulnerable Code ```bash cmd_structures() { local data data=$(api_get "structures") python3 -c " import json, sys data = json.loads('''$(echo "$data" | sed "s/'/\\\\'/g")''') structs = data.get('structures', []) ``` The same construction is repeated in other API-processing functions: ```bash python3 -c " import json, sys d = json.loads('''$(echo "$data" | sed "s/'/\\\\'/g")''') t = d['traits'] ``` ```bash python3 -c " import json r = json.loads('''$(echo "$result" | sed "s/'/\\\\'/g")''') res = r.get('results', {}) ``` Affected instances include the response-processing paths around lines 275-278, 434-437, 481-483, 519-521, and 552-554. ### Technical Analysis The script inserts JSON returned by Google SDM API requests into the body of a dynamically generated Python program. The `sed` expression only attempts to escape apostrophes. It is not a context-aware Python string encoder and does not comprehensively handle combinations of backslashes, triple-quote delimiters, control characters, or other syntax-affecting content. The response should be treated as untrusted because it contains remotely supplied device metadata, structure names, room names, stream results, and event-image results. If an attacker can influence relevant API content, compromise the upstream response path, or exploit mutable device metadata, crafted response data may alter the Python source before `json.loads` runs. Parsing JSON after inserting it into source code reverses the correct trust boundary: the Python parser sees the remote data before the JSON parser validates it. ### Attack Path 1. An attacker gains the ability to influence a device, room, structure, stream, or event-related value returned by the SDM API, or compromises the upstream response source. 2. The user invokes an affec ...[truncated 1056 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pipe every API response directly to Python and parse it with `json.load(sys.stdin)`: ```bash api_get "structures" | python3 - <<'PY' import json import sys data = json.load(sys.stdin) for structure in data.get("structures", []): # Process fields as data. pass PY ``` - If both a script and piped JSON are required, move the Python logic into a dedicated `.py` file or use a separate file descriptor. - Do not use `sed` as a substitute for Python or JSON string serialization. - Apply the correction to all repeated `json.loads('''...''')` instances, not only the first occurrence. - Validate expected response schemas and data types before using fields. - Set reasonable response-size and timeout limits on `curl`. - Use `curl --fail-with-body --show-error` and handle non-2xx responses before parsing. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
nest-events.sh:94
Finding
Telegram Message and Configuration Values Are Embedded Into Python Source<![CDATA[ ## Vulnerability Details **File Location**: `nest-events.sh`, lines 94-113 **Vulnerability Type**: Python source injection in alert serialization **Risk Level**: High ### Vulnerable Code ```bash send_telegram_alert() { local message="$1" local parse_mode="${2:-Markdown}" if [ -z "${TELEGRAM_BOT_TOKEN:-}" ] || [ -z "${TELEGRAM_CHAT_ID:-}" ]; then echo "[$(date)] ALERT (no Telegram): $message" return 0 fi curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ -H "Content-Type: application/json" \ -d "$(python3 -c " import json, sys msg = '''${message}''' print(json.dumps({ 'chat_id': '${TELEGRAM_CHAT_ID}', 'text': msg, 'parse_mode': '${parse_mode}', 'disable_notification': False })) ")" > /dev/null 2>&1 || echo "[$(date)] Warning: Failed to send Telegram alert" >&2 } ``` ### Technical Analysis The alert message, Telegram chat ID, and parse mode are inserted directly into Python source. Alert text can contain information derived from remote event fields, including resource names. The chat ID may originate from environment variables or text extracted from `~/.zshenv`. A value containing quote delimiters and Python syntax can escape its intended literal and append executable statements. JSON serialization does not mitigate the issue because `json.dumps` is called only after Python parses and begins executing the dynamically constructed program. The Telegram bot token is placed in the request URL, which is necessary for Telegram's Bot API but should be protected from process tracing, verbose logging, and diagnostic output. ### Attack Path 1. An attacker influences a remotely derived alert field or a local Telegram configuration value. 2. `pull_events` formats the value as an alert and calls `send_telegram_alert`. 3. The function interpolates the value into the program passed to `python3 -c`. 4. The crafted value terminates the intended Python string. 5. Injected Python statements ...[truncated 698 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Generate the Telegram JSON body by passing values as data, not source: ```bash payload=$( MESSAGE="$message" \ CHAT_ID="$TELEGRAM_CHAT_ID" \ PARSE_MODE="$parse_mode" \ python3 - <<'PY' import json import os print(json.dumps({ "chat_id": os.environ["CHAT_ID"], "text": os.environ["MESSAGE"], "parse_mode": os.environ["PARSE_MODE"], "disable_notification": False, })) PY ) ``` - Alternatively, pass values through positional arguments or standard input. - Validate `parse_mode` against an explicit allowlist such as `Markdown`, `MarkdownV2`, or `HTML`. - Validate the chat ID according to expected Telegram identifier syntax. - Keep the bot token out of logs and ensure shell tracing is disabled around requests. - Store Telegram credentials in a dedicated permission-restricted configuration file or secret manager rather than parsing general-purpose shell startup files. - Treat all event-derived text as untrusted, including resource names and timestamps. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
nest-events.sh:34
Finding
Raw Household Event Logs Are Created Without Explicit Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `nest-events.sh`, lines 34-36 and 306-312 **Vulnerability Type**: Insecure storage of sensitive event data **Risk Level**: Medium ### Vulnerable Code ```bash SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" LOG_DIR="${HOME}/.openclaw/workspace/data/nest-events" mkdir -p "$LOG_DIR" ``` ```bash # Collect ack IDs ack_ids+=("\"$ack_id\"") # Log raw event echo "$decoded" >> "${LOG_DIR}/events-$(date +%Y-%m-%d).jsonl" ``` ### Technical Analysis The listener records decoded Pub/Sub events in daily JSONL files. These events may include doorbell activity, person and motion detection, sound detection, thermostat state, timestamps, and device identifiers. The script does not set a restrictive `umask`, explicitly assign directory mode `700`, or assign log mode `600`. Resulting permissions therefore depend on the invoking environment's existing umask. Under a permissive configuration, other local accounts or processes may be able to read the logs. The logs have no documented automated retention or deletion mechanism, which can cause sensitive historical occupancy information to accumulate indefinitely. ### Attack Path 1. The event listener receives and decodes Nest events. 2. It appends every decoded event to a daily log file. 3. A permissive process umask causes the directory or files to be created with group or world-readable permissions. 4. Another local user or compromised process reads the accumulated event files. 5. The reader correlates timestamps and event types to infer household presence, routines, or device activity. ### Impact Assessment Exposure is limited to principals that can access the local filesystem, but the data is privacy-sensitive. Potential consequences include: - Disclosure of doorbell, person, motion, and sound detection history. - Occupancy and routine inference. - Exposure of device and resource identifiers. - Long-term accumulation of household activity data. - Increased impact from a ...[truncated 122 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Set a restrictive umask before creating the directory or any log files: ```bash umask 077 mkdir -p "$LOG_DIR" chmod 700 "$LOG_DIR" ``` - Create log files explicitly and enforce mode `600`: ```bash log_file="${LOG_DIR}/events-$(date +%Y-%m-%d).jsonl" touch "$log_file" chmod 600 "$log_file" printf '%s\n' "$decoded" >> "$log_file" ``` - Document what data is retained and obtain explicit user consent. - Implement configurable retention, rotation, and secure deletion. - Consider logging only the minimum fields required for diagnostics rather than complete raw events. - Avoid logging authentication tokens, image URLs, stream tokens, or other credentials if they appear in future event schemas. - Protect the workspace against access by unrelated local accounts and processes. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (38)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The manifest says the skill controls Nest devices, but the documentation also describes polling Pub/Sub, modifying IAM permissions, logging events, and forwarding alerts to Telegram. That mismatch is dangerous because users may authorize a device-control skill without realizing it also monitors household activity, stores event data, and transmits it to external services.

External Script Fetching

High
Category
Supply Chain
Content
refresh_token=$(python3 -c "import json; print(json.load(open('${tokens_file}'))['refresh_token'])")

    local response token
    response=$(curl -s -X POST https://oauth2.googleapis.com/token \
      -d "client_id=${client_id}" \
      -d "client_secret=${client_secret}" \
      -d "refresh_token=${refresh_token}" \
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
token=$(get_pubsub_token) || return 1

  local response
  response=$(curl -s -X POST \
    "https://pubsub.googleapis.com/v1/projects/${GCP_PROJECT}/subscriptions/${PUBSUB_SUBSCRIPTION}:pull" \
    -H "Authorization: Bearer ${token}" \
    -H "Content-Type: application/json" \
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
echo "Creating Pub/Sub topic: projects/${GCP_PROJECT}/topics/${PUBSUB_TOPIC}"
  local response
  response=$(curl -s -X PUT \
    "https://pubsub.googleapis.com/v1/projects/${GCP_PROJECT}/topics/${PUBSUB_TOPIC}" \
    -H "Authorization: Bearer ${token}" \
    -H "Content-Type: application/json" \
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
echo "Creating subscription: projects/${GCP_PROJECT}/subscriptions/${PUBSUB_SUBSCRIPTION}"
  local response
  response=$(curl -s -X PUT \
    "https://pubsub.googleapis.com/v1/projects/${GCP_PROJECT}/subscriptions/${PUBSUB_SUBSCRIPTION}" \
    -H "Authorization: Bearer ${token}" \
    -H "Content-Type: application/json" \
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
# Get current IAM policy
  local policy
  policy=$(curl -s -X GET \
    "https://pubsub.googleapis.com/v1/${topic_path}:getIamPolicy" \
    -H "Authorization: Bearer ${token}" 2>/dev/null)
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
set_policy=$(echo "$new_policy" | python3 -c "import sys,json; print(json.dumps(json.load(sys.stdin).get('policy', {})))" 2>/dev/null)

  local result
  result=$(curl -s -X POST \
    "https://pubsub.googleapis.com/v1/${topic_path}:setIamPolicy" \
    -H "Authorization: Bearer ${token}" \
    -H "Content-Type: application/json" \
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
# --- Auth ---
get_token() {
  local response
  response=$(curl -s -X POST https://oauth2.googleapis.com/token \
    -d "client_id=${CLIENT_ID}" \
    -d "client_secret=${CLIENT_SECRET}" \
    -d "refresh_token=${REFRESH_TOKEN}" \
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Credential Access

High
Category
Privilege Escalation
Content
token=$(echo "$response" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('access_token',''))" 2>/dev/null)

  if [ -z "$token" ]; then
    echo "Error: Failed to get access token. Response:" >&2
    echo "$response" >&2
    echo "" >&2
    echo "The refresh token may have expired (7-day limit in testing mode)." >&2
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

External Script Fetching

High
Category
Supply Chain
Content
# --- API helpers ---
api_get() {
  curl -s -X GET "${BASE_URL}/$1" \
    -H "Authorization: Bearer ${ACCESS_TOKEN}" \
    -H "Content-Type: application/json"
}
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
if url:
    print(f'Image URL: {url}')
    print(f'Token:     {token[:40]}...')
    print(f'Download:  curl -o ${output} -H \"Authorization: Basic {token}\" \"{url}\"')
else:
    err = r.get('error', {})
    print(f'Error: {err.get(\"message\", \"Unknown error\")}')
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill documents shell-based capabilities and operational commands but does not declare an explicit tool scope such as permissions or allowed-tools. This creates an authorization ambiguity where a user or platform may not understand that the skill can invoke shell actions with side effects, increasing the chance of unintended command execution or overbroad access.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The documented capabilities materially exceed the manifest description by including event polling, local logging, and third-party alerting. In security terms, incomplete disclosure undermines informed consent and can hide sensitive data flows involving occupancy, motion, and camera-related metadata.

Session Persistence

Medium
Category
Rogue Agent
Content
### Prerequisites

1. **Device Access Console** — Register at https://console.nest.google.com/device-access ($5 one-time fee)
2. **GCP Project** — Create at https://console.cloud.google.com with SDM API enabled
3. **OAuth Client** — Web application type with `https://www.google.com` as redirect URI
4. **SDM scope** — Add `https://www.googleapis.com/auth/sdm.service` to OAuth consent screen
Confidence
60% 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.

External Transmission

Medium
Category
Data Exfiltration
Content
4. Copy the `code=` parameter from the redirect URL
5. Exchange for tokens:
```bash
curl -s -X POST https://oauth2.googleapis.com/token \
  -d "client_id=<CLIENT_ID>" \
  -d "client_secret=<CLIENT_SECRET>" \
  -d "code=<AUTH_CODE>" \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill instructs users to persist OAuth client secrets and refresh tokens locally but does not explicitly warn that these credentials grant ongoing access to smart-home devices and related data. If the file is exposed, an attacker could gain durable access to device control and monitoring capabilities, including cameras and thermostat functions.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
"scope": "https://www.googleapis.com/auth/sdm.service"
}
```
Secure it: `chmod 600 ~/.openclaw/workspace/.nest-sdm-tokens.json`

## CLI Usage
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill enables live camera streaming and event snapshot retrieval without warning users about the privacy implications of accessing in-home video and image data. In a home automation context, camera feeds are highly sensitive and misuse could expose occupants, routines, and private spaces.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
Telegram alerting is not necessary for the stated core function of controlling Nest devices and introduces third-party data transmission of sensitive home activity events. Because alerts may contain occupancy or motion information, this broadens the privacy and attack surface beyond what a user would expect from a control-only skill.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The event listener features describe storing raw smart-home events locally and forwarding alerts to Telegram without an explicit warning that household activity data may be retained and transmitted to a third party. Motion, person, sound, and doorbell events can reveal presence patterns and other sensitive behavioral information.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The skill materially expands scope beyond Nest device control by adding event forwarding to Telegram and Google Cloud Pub/Sub topic/subscription/IAM management. This increases the attack surface and introduces data-flow and infrastructure-changing capabilities that are not implied by simple local device control, making accidental over-privilege and privacy leakage more likely.

Session Persistence

Medium
Category
Rogue Agent
Content
#   nest-events.sh listen              - Poll events continuously (daemon mode)
#   nest-events.sh poll                - Poll once, print events, exit
#   nest-events.sh setup-check         - Verify Pub/Sub config is ready
#   nest-events.sh create-topic        - Create Pub/Sub topic (requires cloud-platform scope)
#   nest-events.sh create-subscription - Create pull subscription
#   nest-events.sh grant-permissions   - Grant SDM publisher role to topic
#
Confidence
78% confidence
Finding
The script is designed to create persistent Pub/Sub resources and use long-lived OAuth refresh tokens, establishing ongoing access and durable event-delivery channels. That persistence is not inherently malicious, but it does increase exposure if credentials or configuration are later compromised.

External Transmission

Medium
Category
Data Exfiltration
Content
refresh_token=$(python3 -c "import json; print(json.load(open('${tokens_file}'))['refresh_token'])")

    local response token
    response=$(curl -s -X POST https://oauth2.googleapis.com/token \
      -d "client_id=${client_id}" \
      -d "client_secret=${client_secret}" \
      -d "refresh_token=${refresh_token}" \
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
return 0
  fi

  curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
    -H "Content-Type: application/json" \
    -d "$(python3 -c "
import json, sys
Confidence
99% confidence
Finding
The Telegram API endpoint is used to transmit device event notifications off-system. In a home monitoring context, that external transmission is sensitive because it can disclose presence, movement, and other behavioral signals to a third party.

External Transmission

Medium
Category
Data Exfiltration
Content
return 0
  fi

  curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
    -H "Content-Type: application/json" \
    -d "$(python3 -c "
import json, sys
Confidence
99% confidence
Finding
The Telegram API endpoint is used to transmit device event notifications off-system. In a home monitoring context, that external transmission is sensitive because it can disclose presence, movement, and other behavioral signals to a third party.

Static analysis

No suspicious patterns detected.