Back to skill

Security audit

Zoom Calendar

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do what it claims, but it handles powerful Zoom and Google credentials in a brittle shell script that can expose tokens or meeting details.

Review before installing. Use only on a machine and account you trust, with the narrowest Zoom and Google Calendar scopes possible. Be aware that it prints live meeting join details and passcodes, assumes the Asia/Jerusalem timezone, and should ideally be fixed to JSON-encode request bodies and clean up token files with an exit trap before routine use.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/zoom_meeting.sh:34
Finding

Unsafe JSON Construction Allows Request-Body Injection

Content
View full analysis

Join Zoom Meeting:
${JOIN_URL}\" } }") ``` ### Technical Analysis The script constructs JSON by directly interpolating command-line arguments, environment variables, and API response values into double-quoted shell strings. These values are not JSON-encoded before insertion. In particular: - `TOPIC` can contain quotation marks, backslashes, control characters, or additional ...[truncated 2566 chars]
Remediation
View remediation
1440 )); then echo "ERROR: Duration must be an integer between 1 and 1440" >&2 exit 1 fi if ! [[ "$START_TIME" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$ ]]; then echo "ERROR: Invalid start_time format" >&2 exit 1 fi ZOOM_BODY=$(jq -n \ --arg topic "$TOPIC" \ --arg start_time "$START_TIME" \ --argjson duration "$DURATION" \ '{ topic: $topic, type: 2, start_time: $start_time, duration: $duration, timezone: "Asia/Jerusalem", settings: { host_video: true, participant_video: true, join_before_host: true } }') ``` 2. Pass the generated body using `curl --data-binary "$ZOOM_BODY"`. 3. Build the Google Calendar patch with `jq -n --arg` for every interpolated string. 4. Validate `EVENT_ID` against the expected Google Calendar event-ID character set before placing it in the URL, and URL-encode it defensively. 5. Check HTTP status codes with `curl --fail-with-body` rather than relying exclusively on selected JSON fields. 6. Consider compensating cleanup, such as deleting the newly created Zoom meeting, when the calendar update fails. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/zoom_meeting.sh:68
Finding

Google OAuth Refresh Token Can Persist in a Temporary File

Content
View full analysis
/dev/null REFRESH_TOKEN=$(jq -r '.refresh_token' "$GOG_TOKEN_FILE") GOG_CREDS_FILE="${GOG_CREDENTIALS:-$HOME/.config/gogcli/credentials.json}" if [ ! -f "$GOG_CREDS_FILE" ]; then echo "ERROR: Google credentials not found at $GOG_CREDS_FILE" >&2 echo "Set GOG_CREDENTIALS env var or install gog CLI first" >&2 exit 1 fi GCAL_CLIENT_ID=$(jq -r '.client_id' "$GOG_CREDS_FILE") GCAL_CLIENT_SECRET=$(jq -r '.client_secret' "$GOG_CREDS_FILE") rm -f "$GOG_TOKEN_FILE" ``` ### Technical Analysis The script exports a long-lived Google OAuth refresh token into a temporary file. Although `mktemp` normally creates a uniquely named file with restrictive permissions, deletion is performed only through a normal-flow `rm` command. The script enables `set -euo pipefail`. Consequently, a failed `gog` invocation, failed `jq` operation, missing credentials file, signal, interruption, or other abnormal termination before `rm -f` can leave the refresh token on disk. The missing-credentials branch explicitly exits before cleanup. A refresh token is more sensitive than a short-lived access token because it can repeatedly obtain new access tokens until revoked or otherwise invalidated. ### Attack Path 1. The script successfully exports the configured Google account's token data to `GOG_TOKEN_FILE`. 2. Execution fails before line 83—for example, the Google client credential file is absent, parsing fails, or the process receives an interrupt. 3. Because no `EXIT` or signal trap is registered, the temporary file is not deleted. 4. A local user, compromised process, forensic collector, backup mechanism, or later attacker with access to the account or temporary storage recovers the f ...[truncated 937 chars]
Remediation
View remediation
/dev/null REFRESH_TOKEN=$(jq -er '.refresh_token | select(type == "string" and length > 0)' \ "$GOG_TOKEN_FILE") rm -f -- "$GOG_TOKEN_FILE" trap - EXIT HUP INT TERM ``` 2. Prefer a supported `gog` mechanism that supplies an access token without exporting a long-lived refresh token to disk. 3. Apply a restrictive `umask`, such as `umask 077`, before creating any secret-bearing temporary resource. 4. Verify the export and JSON parsing results before continuing. 5. Unset `REFRESH_TOKEN`, `GCAL_CLIENT_SECRET`, and access-token variables as soon as they are no longer required. 6. Avoid suppressing all `gog` diagnostic output; retain sanitized errors so token-handling failures can be identified without printing secret values. 7. Revoke and reauthorize the Google token if a residual temporary file may have been exposed. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (18)

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 8)May include surrounding context.

md
(icon, video entry, notes). Use when creating calendar events with Zoom, adding Zoom to
  existing events, or any Zoom + Google Calendar integration. Requires Zoom Server-to-Server
  OAuth credentials and Google Calendar (gog) auth.
metadata: {"clawdbot":{"emoji":"📹","version":"1.1.0","author":"Leo 🦁","tags":["zoom","calendar","google-calendar","meetings","video-conference","scheduling"],"requires":{"env":["GOG_KEYRING_PASSWORD","GOG_ACCOUNT"],"credentials":[".credentials/zoom.json","$HOME/.config/gogcli/credentials.json"],"tools":["gog","jq","curl","base64"]}}}
allowed-tools: [exec]
---

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 72)May include surrounding context.

md
(icon, video entry, notes). Use when creating calendar events with Zoom, adding Zoom to
  existing events, or any Zoom + Google Calendar integration. Requires Zoom Server-to-Server
  OAuth credentials and Google Calendar (gog) auth.
metadata: {"clawdbot":{"emoji":"📹","version":"1.1.0","author":"Leo 🦁","tags":["zoom","calendar","google-calendar","meetings","video-conference","scheduling"],"requires":{"env":["GOG_KEYRING_PASSWORD","GOG_ACCOUNT"],"credentials":[".credentials/zoom.json","$HOME/.config/gogcli/credentials.json"],"tools":["gog","jq","curl","base64"]}}}
allowed-tools: [exec]
---

Lp1

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding

The skill uses 'shell' capability that is not listed in its permissions. This may indicate deceptive intent or missing permission declarations.

Content

No source excerpt is available for this finding.

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/zoom_meeting.sh (reported line 25)May include surrounding context.

sh
-d "grant_type=account_credentials&account_id=${ACCOUNT_ID}" | jq -r '.access_token')

if [ -z "$ZOOM_TOKEN" ] || [ "$ZOOM_TOKEN" = "null" ]; then
  echo "ERROR: Failed to get Zoom access token" >&2
  exit 1
fi

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/zoom_meeting.sh (reported line 90)May include surrounding context.

sh
-d "grant_type=account_credentials&account_id=${ACCOUNT_ID}" | jq -r '.access_token')

if [ -z "$ZOOM_TOKEN" ] || [ "$ZOOM_TOKEN" = "null" ]; then
  echo "ERROR: Failed to get Zoom access token" >&2
  exit 1
fi

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

The script prints the Zoom join URL, meeting ID, and passcode to stdout immediately after meeting creation. This exposes live meeting credentials to logs, terminal history capture, agent transcripts, and any downstream systems collecting command output, enabling unauthorized meeting access if those outputs are retained or shared.

Content

Scanner excerpt · scripts/zoom_meeting.sh (reported line 57)May include surrounding context.

sh
echo "Zoom meeting created: $JOIN_URL (ID: $MEETING_ID, Pass: $PASSWORD)"

# --- Step 2: Get Google Calendar access token ---
if [ -z "${GOG_KEYRING_PASSWORD:-}" ]; then
  echo "ERROR: GOG_KEYRING_PASSWORD env var is required" >&2
  exit 1

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

Requiring a keyring password via environment variable increases exposure because environment variables can be inherited by child processes, surfaced in diagnostics, or read by local users with sufficient access to process metadata. In this case the script exports the secret for downstream tooling, which expands the blast radius if the host is shared or instrumented.

Content

Scanner excerpt · scripts/zoom_meeting.sh (reported line 58)May include surrounding context.

sh
echo "Zoom meeting created: $JOIN_URL (ID: $MEETING_ID, Pass: $PASSWORD)"

# --- Step 2: Get Google Calendar access token ---
if [ -z "${GOG_KEYRING_PASSWORD:-}" ]; then
  echo "ERROR: GOG_KEYRING_PASSWORD env var is required" >&2
  exit 1
fi

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/zoom_meeting.sh (reported line 59)May include surrounding context.

sh
# --- Step 2: Get Google Calendar access token ---
if [ -z "${GOG_KEYRING_PASSWORD:-}" ]; then
  echo "ERROR: GOG_KEYRING_PASSWORD env var is required" >&2
  exit 1
fi
if [ -z "${GOG_ACCOUNT:-}" ]; then

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

Exporting GOG_KEYRING_PASSWORD into the process environment propagates a sensitive secret to child processes and increases accidental disclosure risk through debugging, crash reports, or process inspection. This is a common but unsafe shell practice, especially for automation that may run in CI, agent frameworks, or shared systems.

Content

Scanner excerpt · scripts/zoom_meeting.sh (reported line 66)May include surrounding context.

sh
echo "ERROR: GOG_ACCOUNT env var is required" >&2
  exit 1
fi
export GOG_KEYRING_PASSWORD
export GOG_ACCOUNT

GOG_TOKEN_FILE=$(mktemp)

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The script directly reads Google OAuth client credentials from a local credentials.json file, which concentrates sensitive secrets in a predictable path and exposes them to any compromise of the execution environment. In a shell-based automation context, this is especially risky because such files are often broadly readable, copied into backups, or reused across tools without strict permission controls.

Content

Scanner excerpt · scripts/zoom_meeting.sh (reported line 73)May include surrounding context.

sh
gog auth tokens export "$GOG_ACCOUNT" --out "$GOG_TOKEN_FILE" --overwrite 2>/dev/null

REFRESH_TOKEN=$(jq -r '.refresh_token' "$GOG_TOKEN_FILE")
GOG_CREDS_FILE="${GOG_CREDENTIALS:-$HOME/.config/gogcli/credentials.json}"
if [ ! -f "$GOG_CREDS_FILE" ]; then
  echo "ERROR: Google credentials not found at $GOG_CREDS_FILE" >&2
  echo "Set GOG_CREDENTIALS env var or install gog CLI first" >&2

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill documentation states that timestamps without a timezone will be interpreted as 'Jerusalem assumed', which can cause meetings to be scheduled at the wrong time without explicit user consent. In a calendar/meeting automation context, silent timezone assumptions are risky because they can lead to missed meetings, unintended disclosures to attendees, or business disruption.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This shell script reads Zoom client credentials from a local credentials file and later uses Google credential material and environment variables to obtain access tokens. While the operations are core to the script's purpose, the file lacks any explicit disclosure in comments or usage text that it will access stored credentials and authenticate to third-party services on the user's behalf.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/zoom_meeting.sh (reported line 29)May include surrounding context.

sh
exit 1
fi

ZOOM_RESPONSE=$(curl -s -X POST "https://api.zoom.us/v2/users/me/meetings" \
  -H "Authorization: Bearer $ZOOM_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/zoom_meeting.sh (reported line 29)May include surrounding context.

sh
exit 1
fi

ZOOM_RESPONSE=$(curl -s -X POST "https://api.zoom.us/v2/users/me/meetings" \
  -H "Authorization: Bearer $ZOOM_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The meeting creation payload forces the timezone to "Asia/Jerusalem" for all users. This is a natural-language locale policy concern because the script imposes a specific locale setting without opt-in, configurability, or justification in surrounding comments.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

The script sends the Google OAuth client secret and refresh token in a direct token exchange without additional protections such as strict temporary file handling, explicit scope validation, or minimizing credential exposure lifetime. In this skill context, credential handling is necessary, but using long-lived refresh tokens and client secrets in a shell script materially increases the chance of credential theft from process inspection, debugging, logs, or local compromise.

Content

Scanner excerpt · scripts/zoom_meeting.sh (reported line 83)May include surrounding context.

sh
GCAL_CLIENT_SECRET=$(jq -r '.client_secret' "$GOG_CREDS_FILE")
rm -f "$GOG_TOKEN_FILE"

ACCESS_TOKEN=$(curl -s -X POST "https://oauth2.googleapis.com/token" \
  -d "client_id=$GCAL_CLIENT_ID" \
  -d "client_secret=$GCAL_CLIENT_SECRET" \
  -d "refresh_token=$REFRESH_TOKEN" \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The script patches a Google Calendar event by inserting Zoom conference data, which is a remote write affecting user data. Although the final success message confirms completion, there is no prior user-facing disclosure in the script header or usage text that running it will modify an existing calendar event.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/zoom_meeting.sh (reported line 95)May include surrounding context.

sh
fi

# --- Step 3: Patch Google Calendar event with conferenceData ---
PATCH_RESULT=$(curl -s -X PATCH \
  "https://www.googleapis.com/calendar/v3/calendars/primary/events/${EVENT_ID}?conferenceDataVersion=1" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \

Static analysis

No suspicious patterns detected.