Back to skill

Security audit

Zoho

Security checks for vulnerabilities and agentic risk

Overview

This Zoho skill is purpose-aligned, but it needs review because it combines broad business-data authority, local long-lived secrets, destructive examples, and third-party meeting transcription without enough safeguards.

Review this skill before installing. Use least-privilege Zoho scopes, keep secrets in a managed secret store instead of a skill-directory .env, require explicit approval for writes/deletes and meeting downloads, and only run the summarizer when everyone is authorized for recordings to be sent to Gemini. The package should also include the missing CLI wrapper or clearly declare and verify that dependency.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/standup-summarizer.sh:93
Finding

Zoho OAuth Token Sent to an Unvalidated Recording URL

Content
View full analysis
` to the attacker-controlled endpoint. 6. The attacker captures and reuses the token until it expires. ### Impact Assessment A successful exploit discloses a valid Zoho ...[truncated 533 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/standup-summarizer.sh:9
Finding

Predictable and Potentially Permissive Temporary Storage Exposes Meeting Data

Content
View full analysis
"$PROCESSED_FILE" cleanup() { rm -rf "$TMP_DIR"; } trap cleanup EXIT ``` Sensitive files are subsequently created in that predictable directory: ```bash MP4_FILE="${TMP_DIR}/recording_${i}.mp4" HTTP_CODE=$(curl -s -w "%{http_code}" -o "$MP4_FILE" -L \ -H "Authorization: Zoho-oauthtoken ${TOKEN}" \ "$DOWNLOAD_URL") WAV_FILE="${TMP_DIR}/audio_${i}.wav" ffmpeg -i "$MP4_FILE" -vn -acodec pcm_s16le -ar 16000 -ac 1 "$WAV_FILE" -y -loglevel error 2>&1 ``` ```bash B64_FILE="${TMP_DIR}/audio_${i}.b64" base64 -w0 "$WAV_FILE" > "$B64_FILE" PROMPT_TEXT="Transcribe this meeting recording. The speakers are Egyptian and speak in Egyptian Arabic mixed with English technical terms. Provide a faithful transcription preserving the language as spoken (Arabic parts in Arabic script, English parts in English). Include speaker changes where detectable. Do NOT summarize — provide the full transcription." GEMINI_BODY=$(jq -n --rawfile audio "$B64_FILE" --arg prompt "$PROMPT_TEXT" \ '{ "contents": [{ "parts": [ {"inline_data": {"mime_type": "audio/wav", "data": $audio}}, {"text": $prompt} ] }], "generationConfig": {"temperature": 0.1, "maxOutputTokens": 8192} }') rm -f "$B64_FILE" ``` ```bash # Save transcript TRANSCRIPT_FILE="${TMP_DIR}/transcript_${i}.txt" echo "$TRANSCRIPT" > "$TRANSCRIPT_FILE" ``` ### Technical Analysis The script constructs its temporary directory from its process ID rather than using an atomic secure temporary-directory API. Process IDs are pr ...[truncated 2231 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/standup-summarizer.sh:156
Finding

Gemini API Key Exposed in Request URLs

Content
View full analysis
`. 3. The observer extracts the API key. 4. The key is used to make unauthorized Gemini API requests. 5. The unauth ...[truncated 504 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/standup-summarizer.sh:153
Finding

Uploaded Meeting Audio Is Not Deleted from the Gemini File API

Content
View full analysis
Remediation
View remediation
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (25)

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

A command that prints the current access token is highly risky in an agent context because tokens can be exposed in terminal output, logs, chat transcripts, screenshots, or copied accidentally. Since the token enables authenticated API access, disclosure can immediately permit unauthorized reads or writes within the Zoho tenant until expiry.

Content

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

bash
zoho help          # Show all commands
zoho token         # Print current access token (auto-refreshes)

Authentication Setup

External Script Fetching

High
Category
Supply Chain
Confidence
60% confidence
Finding

Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Content

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

Step 3: Exchange Code for Refresh Token

Run this curl command (replace placeholders):

bash
curl -X POST "https://accounts.zoho.com/oauth/v2/token" \

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

This line explains that the refresh token is a long-lived credential and that the access token auto-refreshes, which is accurate documentation rather than active credential theft. However, the context does normalize handling a high-value persistent credential without sufficient safeguards, which contributes to operational risk when combined with local .env storage and shell-based workflows.

Content

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

}

text

Save the **refresh_token** — this is your long-lived credential. The access token expires in 1 hour, but the CLI auto-refreshes it using the refresh token.

### Step 4: Find Your Org IDs

Credential Access

High
Category
Privilege Escalation
Confidence
92% confidence
Finding

The skill explicitly instructs users to configure a .env containing client credentials and a long-lived refresh token. In agent environments with shell/file access, colocating secrets in the skill directory materially increases the risk of unintended disclosure through logs, command output, workspace sharing, or other tools reading local files.

Content

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

CRM/Projects Org ID:

bash
# After setting up .env with client_id, client_secret, refresh_token:
zoho raw GET /crm/v7/org | jq '.org[0].id'

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

The .env setup centralizes multiple sensitive values, including client secret, refresh token, and organization identifiers, in a predictable local file. While org IDs alone are not secret, bundling them with reusable credentials makes compromise easier and increases the blast radius if the workspace is exposed.

Content

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

md
**Meeting Org ID:**
Log into [Zoho Meeting](https://meeting.zoho.com) → Admin Settings → look for the Organization ID in the URL or settings page. It's different from the CRM org ID.

### Step 5: Configure .env

Create `.env` in the skill directory:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/standup-summarizer.sh (reported line 12)May include surrounding context.

sh
TMP_DIR="/tmp/standup-$$"

# ── Load env ──────────────────────────────────────────────────────────
source "${ZOHO_SKILL_DIR}/.env"
GEMINI_API_KEY="${GEMINI_API_KEY:-}"
ZOHO_MEETING_ORG_ID="${ZOHO_MEETING_ORG_ID:-853106938}"

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/standup-summarizer.sh (reported line 48)May include surrounding context.

sh
cleanup() { rm -rf "$TMP_DIR"; }
trap cleanup EXIT

# ── Get Zoho access token ────────────────────────────────────────────
get_token() {
  "${ZOHO_SKILL_DIR}/bin/zoho" token
}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README promotes automated downloading of meeting recordings and sending them into a transcription pipeline, but it does not warn about consent, recording policies, retention, or sharing sensitive meeting content with a third-party model provider. In a workplace context, this can expose confidential discussions or regulated personal data and may lead users to deploy the workflow in violation of internal policy or applicable privacy law.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill documents extensive shell-based capabilities but declares no explicit tool scope or permission boundaries. In an agent environment, that increases the chance the skill is invoked with broader execution authority than intended, enabling credential handling, API calls, downloads, and file operations without clear restrictions.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger description is very broad and includes generic terms like projects, tasks, meetings, and recordings, which are common in ordinary conversations. That can cause accidental invocation of a powerful integration skill in contexts where the user did not intend Zoho access, increasing the risk of unnecessary data exposure or unintended actions.

Content

No source excerpt is available for this finding.

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 · SKILL.md (reported line 70)May include surrounding context.

Step 3: Exchange Code for Refresh Token

Run this curl command (replace placeholders):

bash
curl -X POST "https://accounts.zoho.com/oauth/v2/token" \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation includes a direct delete command for CRM records with no warning, safety notes, or confirmation guidance. In an agent-assisted workflow, that normalizes destructive behavior and can lead to irreversible record deletion from a production CRM through user error or prompt ambiguity.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The recording download and summarization pipeline processes potentially sensitive meeting audio, transcripts, and summaries, and explicitly suggests sending content to external AI services, but it provides no privacy, consent, retention, or access-control guidance. This creates a realistic path for confidential business discussions or personal data to be exported and retained outside Zoho without informed approval.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file documents endpoints for listing and downloading recordings, including transcript and summary download URLs, which can expose sensitive meeting content. Under the markdown-specific warning criterion, the description lacks any caution about privacy, consent, or careful handling of user data affected by these operations.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill description suggests Zoho interaction, but this script also downloads recordings, extracts audio locally, and performs full transcription. While not inherently malicious, that broadens capability into surveillance-style content processing and increases privacy risk, especially because full transcripts are produced and returned to the caller.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script sends downloaded Zoho meeting audio and derived transcript content to Google's Gemini APIs, expanding data flow beyond Zoho into a third-party processor. This is dangerous because meeting recordings commonly contain sensitive business discussions, customer data, and credentials, and the transfer occurs automatically without any consent gate, data minimization, or processor-validation controls.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

This request uploads extracted meeting audio to Google's File API, constituting direct external exfiltration of potentially sensitive meeting content. Because the transfer is automatic and the skill context is Zoho-focused, the behavior is more dangerous: users are less likely to expect raw recordings to leave the primary platform.

Content

Scanner excerpt · scripts/standup-summarizer.sh (reported line 156)May include surrounding context.

sh
if [[ "$WAV_BYTES" -gt 20000000 ]]; then
    # Large file: upload via File API first
    echo "   📤 Large file — uploading to Gemini File API..."
    UPLOAD_RESP=$(curl -s -X POST \
      "https://generativelanguage.googleapis.com/upload/v1beta/files?key=${GEMINI_API_KEY}" \
      -H "X-Goog-Upload-Command: start, upload, finalize" \
      -H "X-Goog-Upload-Header-Content-Length: ${WAV_BYTES}" \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

Meeting recordings are uploaded or embedded into requests sent to external Gemini endpoints without any explicit warning, confirmation, or approval flow. This creates a real confidentiality risk because users may reasonably expect a Zoho skill to keep meeting data within Zoho or at least warn before sharing audio with a third party.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The prompt explicitly instructs Gemini that the speakers are Egyptian and speak in Egyptian Arabic mixed with English technical terms, effectively imposing a locale/language assumption. This can violate language/locale policy when the skill does not give users a choice or document that this is a region-specific tool.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
96% confidence
Finding

The script sends transcription requests containing meeting audio or file references to Gemini's generateContent API. This exposes sensitive communications to a third-party model service and may also place data into provider-side processing pipelines without user awareness.

Content

Scanner excerpt · scripts/standup-summarizer.sh (reported line 202)May include surrounding context.

sh
GEMINI_BODY_FILE="${TMP_DIR}/gemini_body_${i}.json"
  echo "$GEMINI_BODY" > "$GEMINI_BODY_FILE"
  GEMINI_RESP=$(curl -s -X POST \
    "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${GEMINI_API_KEY}" \
    -H "Content-Type: application/json" \
    -d "@${GEMINI_BODY_FILE}")

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

The fallback retry to a second Gemini model repeats third-party transmission of the same sensitive meeting content, increasing exposure surface and data-sharing events. Retrying against multiple models without consent or minimization amplifies confidentiality and compliance risk.

Content

Scanner excerpt · scripts/standup-summarizer.sh (reported line 216)May include surrounding context.

sh
echo "   🔄 Retrying with gemini-2.5-flash..."
    GEMINI_BODY_FILE="${TMP_DIR}/gemini_body_${i}.json"
    echo "$GEMINI_BODY" > "$GEMINI_BODY_FILE"
    GEMINI_RESP=$(curl -s -X POST \
      "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${GEMINI_API_KEY}" \
      -H "Content-Type: application/json" \
      -d "@${GEMINI_BODY_FILE}")

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
71% confidence
Finding

The README explicitly highlights handling of an Arabic and English language mix, which introduces a language-specific behavior in the skill description. There is no indication here that language handling is user-configurable or opt-in, which may conflict with organizational language/locale choice expectations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

This markdown file documents irreversible deletion operations for projects and tasks, but provides no warning about data loss, confirmation expectations, or recovery limitations. Under the markdown-specific warning criterion, descriptions of behaviors that can affect user data should include a caution when destructive actions are exposed.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The script sources a .env file and reads GEMINI_API_KEY, which is sensitive credential material. There is no user-facing warning, confirmation, or descriptive comment indicating that the skill accesses local secrets, which can be relevant for safety review of code that handles credentials.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

When no date is provided, the script computes the target date and time range in the Africa/Cairo timezone. This is a locale-specific assumption that may lead to unintended behavior for users in other regions and is not presented as an explicit user choice.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.