Back to skill

Security audit

zoho-support-claw

Security checks for vulnerabilities and agentic risk

Overview

This Zoho support skill is coherent, but it needs review because it sends and stores broad support ticket content with weak scoping and credential-destination controls.

Review this before installing in any real support environment. Use only least-privilege Zoho tokens, restrict ZOHO_DOMAIN to known Zoho Desk domains, confirm OpenAI processing is approved for your ticket data, redact sensitive fields before embedding or draft generation, and protect or regularly delete data/embeddings.json. Do not rely on drafts without human review.

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

T09 · Insecure Skill Coding Practices

Error
Location
lib/zohoClient.js:4
Finding

Zoho OAuth Token Can Be Forwarded to an Arbitrary Configured Host

Content
View full analysis
`. 6. The attacker captures the token and uses it against the real Zoho Desk API, subject to the token's scopes and validity. ### Impact Assessment Successful exploitation d ...[truncated 375 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
lib/vectorStore.js:6
Finding

Sensitive Support Ticket Data Is Persisted in Plaintext

Content
View full analysis
({ id: t.id, subject: t.subject || '', text: (t.subject||'') + '\n' + (t.description||'') + '\n' + (t.resolution||''), meta: { requester: t.contact, closed_at: t.modifiedTime } })); const embedResp = await embeddings.createEmbeddings(docs.map(d=>d.text)); const items = docs.map((d,i)=>({ id:d.id, text:d.text, vector: embedResp[i], meta:d.meta })); store.saveVectors(items); ``` Plaintext persistence: ```js const DATA_FILE = path.join(__dirname,'..','data','embeddings.json'); function ensureFile(){ const dir = path.dirname(DATA_FILE); if(!fs.existsSync(dir)) fs.mkdirSync(dir,{ recursive:true }); if(!fs.existsSync(DATA_FILE)) fs.writeFileSync(DATA_FILE, JSON.stringify({items:[]},null,2)); } function saveVectors(items){ ensureFile(); const store = JSON.parse(fs.readFileSync(DATA_FILE,'utf8')); store.items = store.items.concat(items); fs.writeFileSync(DATA_FILE, JSON.stringify(store,null,2)); log.info({count: items.length}, 'Saved vectors'); } ``` ### Technical Analysis The ingestion process stores complete ticket subjects, descriptions, resolutions, requester metadata, and embeddings in `data/embeddings.json`. The file is ordinary plaintext JSON and is created using default process permissions. No explicit restrictive mode, encryption, data minimization, retention limit, or deduplication mechanism is applied. Repeated ingestion appends records through `store.items.concat(items)`, which can retain duplicate and obsolete customer data indefinitely. Although exploitation requires filesystem, backup, artifact, or repository access, the file creates an additional sensitive-data repository outside Zoho's access controls. ### Attack Pa ...[truncated 879 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
lib/replyGenerator.js:8
Finding

Untrusted Ticket Content Enables Indirect Prompt Injection

Content
View full analysis
n.text).join('\n---\n'); const draft = await replyGen.generateDraftReply(t, context); ``` ### Technical Analysis Current ticket fields and historical ticket text are untrusted or customer-controlled content. They are interpolated directly into a user message that also contains operational instructions. The prompt does not clearly delimit the data, identify it as untrusted, or instruct the model to disregard commands embedded inside ticket content. A malicious requester can include text such as instructions to ignore the support task, include attacker-selected links, disclose context, or produce misleading actions. The attack can occur directly through an open ticket or indirectly after a malicious ticket is ingested and retrieved as similar historical ...[truncated 1582 chars]
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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (20)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The README says the skill analyzes tickets and generates drafts using OpenAI, but does not clearly disclose that ticket contents may be transmitted to an external AI provider. Because support tickets often include sensitive customer and operational data, this omission creates a meaningful risk of unauthorized third-party disclosure, policy violations, and regulatory noncompliance.

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

md
Configuration (in .env):
- ZOHO_DOMAIN (e.g. desk.zoho.com)
- ZOHO_TOKEN (OAuth access token)
- OPENAI_API_KEY
- OPENAI_MODEL (optional, default gpt-4o-mini or fallback)
- EMBEDDINGS_MODEL (optional, default text-embedding-3-small)

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

md
Usage:
- Install via clawhub/publish or copy to workspace skills.
- Configure .env with ZOHO_TOKEN and OPENAI_API_KEY

Commands:
- ingest: Run historical ingest (npm run ingest)

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

md
Usage:
- Install via clawhub/publish or copy to workspace skills.
- Configure .env with ZOHO_TOKEN and OPENAI_API_KEY

Commands:
- ingest: Run historical ingest (npm run ingest)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The README says the skill analyzes tickets and generates drafts using OpenAI, but does not clearly disclose that ticket contents may be transmitted to an external AI provider. Because support tickets often include sensitive customer and operational data, this omission creates a meaningful risk of unauthorized third-party disclosure, policy violations, and regulatory noncompliance.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill description states that it ingests historical support tickets, stores local embeddings, and uses an OpenAI API key, but it does not warn users that ticket contents may be transmitted to external AI services and retained locally as embeddings. Support tickets often contain sensitive customer, account, or operational data, so failing to disclose these data flows creates a real privacy and compliance risk.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code ingests full closed-ticket subject, description, and resolution text, then stores embeddings alongside requester metadata for later retrieval. Support tickets commonly contain personal, account, billing, or incident details, so bulk retention and vectorization of historical content materially increases privacy, data-governance, and cross-ticket data leakage risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

At this line, full ticket text is sent to an embeddings service, which is an external processing step for potentially sensitive support data. Without prior redaction, data-processing controls, or explicit disclosure/consent, this can expose customer information to third-party systems and create compliance and confidentiality risks.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill retrieves historical ticket text and uses it as context to generate replies for unrelated open tickets, which can leak sensitive information from prior cases into new responses. Because there is no filtering, authorization boundary, or redaction step on retrieved context, the RAG workflow can expose one customer's data to another or cause the model to reproduce confidential internal resolution details.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Open ticket contents are embedded and then combined with retrieved historical text for draft generation, meaning current and prior sensitive support data may be transmitted to external model services. This raises both third-party disclosure risk and prompt-context leakage risk, especially because no sanitization, customer-boundary checks, or warning mechanisms are present.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

This code sends the provided texts to an external OpenAI embeddings endpoint, which may transmit user or system data off-host. While errors are logged, there is no confirmation prompt, user-facing notice, or explanatory comment/docstring in this file disclosing that text content is sent to a remote service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The function sends raw ticket subject, description, and related context to the OpenAI API, which is an external third-party service. If tickets contain personal data, credentials, internal business information, or regulated content, this creates a privacy and data-governance risk when users are not clearly informed and the data is not minimized or sanitized before transmission.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code persists supplied items, including id, text, and meta, into data/embeddings.json via fs.writeFileSync, which can retain user-derived content on disk. While there is an internal log message after saving, there is no user-facing prompt, warning comment, or explanatory docstring disclosing that data will be stored locally.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code sends support ticket data through HTTP requests to the Zoho API, which can involve user or system data such as ticket subjects, descriptions, and requester/contact fields. While there is error logging and a missing-token warning, there is no comment, docstring, or user-facing disclosure here explaining that the skill retrieves and transmits potentially sensitive ticket content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The file reads an OAuth token from the environment via ZOHO_TOKEN, which is a sensitive credential access pattern covered by the warning requirement for code files. Although the code warns when the token is missing, it does not explain to users or maintainers that the skill depends on a credential and will authenticate to an external service with it.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency version for axios is specified with a caret range, which allows npm to install newer minor and patch releases rather than a single vetted version. This weakens build reproducibility and can unintentionally introduce vulnerable or malicious upstream releases through the supply chain.

Content

Scanner excerpt · package.json (reported line 14)May include surrounding context.

json
"author": "",
  "license": "MIT",
  "dependencies": {
    "axios": "^1.4.0",
    "dotenv": "^16.0.0",
    "openai": "^4.0.0",
    "pino": "^8.0.0"

Unverifiable Dependency: axios has 16 known advisory(ies) (CVE-2026-44494 (axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co); CVE-2026-44495 (axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut); CVE-2025-62718 (Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The manifest includes axios without pinning to an exact version, while advisories exist for some axios releases. Because the installed version cannot be verified from this file alone, there is a credible risk that deployments may resolve to an affected version, especially across environments or over time.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dotenv dependency is not pinned to an exact version, so future installs may resolve to different package contents over time. That increases supply-chain risk and makes it harder to guarantee that the reviewed build matches the deployed build.

Content

Scanner excerpt · package.json (reported line 15)May include surrounding context.

json
"license": "MIT",
  "dependencies": {
    "axios": "^1.4.0",
    "dotenv": "^16.0.0",
    "openai": "^4.0.0",
    "pino": "^8.0.0"
  }

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The openai package uses a caret version range, allowing different releases to be installed without source changes. For a skill that processes support tickets and may handle sensitive data, non-reproducible dependency resolution increases the risk of unexpected behavior or supply-chain compromise.

Content

Scanner excerpt · package.json (reported line 16)May include surrounding context.

json
"dependencies": {
    "axios": "^1.4.0",
    "dotenv": "^16.0.0",
    "openai": "^4.0.0",
    "pino": "^8.0.0"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The pino dependency is declared with a non-exact semver range, which permits unreviewed upstream updates during installation. This creates avoidable supply-chain exposure and reduces the integrity and reproducibility of the application environment.

Content

Scanner excerpt · package.json (reported line 17)May include surrounding context.

json
"axios": "^1.4.0",
    "dotenv": "^16.0.0",
    "openai": "^4.0.0",
    "pino": "^8.0.0"
  }
}

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
lib/zohoClient.js:3