Back to skill

Security audit

Lead Outreach CRM

Security checks for vulnerabilities and agentic risk

Overview

This local outreach CRM is mostly purpose-aligned, but it can permanently wipe stored lead data without confirmation and exports untrusted lead fields to CSV without formula hardening.

Review before installing if the stored leads matter: ask for a confirmation/force flag or backup behavior before using `clear`, and treat exported CSVs as untrusted unless formula-prefixed values are neutralized. The skill does not show network exfiltration or hidden persistence, but it handles retained contact/lead data locally.

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

T09 · Insecure Skill Coding Practices

Warning
Location
outreach-crm.js:321
Finding

CSV Formula Injection in Lead Export

Content
View full analysis

Vulnerability Details

File Location: outreach-crm.js, lines 321–329
Vulnerability Type: CSV formula injection
Risk Level: Medium

Vulnerable Code

js
const escape = (v) => `"${String(v ?? '').replace(/"/g, '""')}"`;

const header = allKeys.join(',');
const rows = leads.map(lead =>
  allKeys.map(k => escape(Array.isArray(lead[k]) ? lead[k].join('; ') : lead[k])).join(',')
);

const csv = [header, ...rows].join('\n');
fs.mkdirSync(WORKSPACE_DIR, { recursive: true });
fs.writeFileSync(CSV_FILE, csv, 'utf8');

Technical Analysis

Lead fields are attacker- or user-controlled and are persisted by saveLeadToFile(). During CSV export, the implementation only doubles quotation marks and surrounds each value with quotes. This provides CSV syntax escaping but does not neutralize spreadsheet formulas.

Spreadsheet applications may evaluate cells whose first non-whitespace character is =, +, -, or @, even when the value is quoted in the CSV file. A field such as a lead name, handle, source, or interaction-derived property can therefore contain a formula that remains active in the generated leads.csv.

Attack Path

  1. An attacker supplies a crafted lead field beginning with a spreadsheet formula marker, such as =, +, -, or @.
  2. The add-lead command parses the value and saveLeadToFile() stores it in leads.json without formula neutralization.
  3. The user invokes export-csv.
  4. exportLeadsAsCSV() writes the malicious value to leads.csv, escaping only CSV quotation marks.
  5. The user downloads and opens the CSV file in spreadsheet software.
  6. If the spreadsheet application permits formula evaluation, the crafted cell is interpreted as a formula rather than inert text.

Impact Assessment

Exploitation occurs in the context of the user opening the exported file and is constrained by the behavior and security settings of the spreadsheet application. A success ...[truncated 441 chars]

Remediation
View remediation

Remediation Suggestions

Neutralize formula-capable values before performing ordinary CSV escaping:

  1. Convert each value to a string.
  2. Detect whether its first non-whitespace character is =, +, -, or @.
  3. Prefix matching values with an apostrophe so spreadsheet applications treat them as text.
  4. Continue doubling embedded quotation marks and quoting every cell.
  5. Consider rejecting or removing unsafe control characters.
  6. Add tests covering every formula prefix, leading whitespace, embedded quotes, arrays, and ordinary values.
  7. Document that lead fields are untrusted and that CSV exports should be opened with formula execution disabled where possible.

Example hardening:

js
const escapeCSV = (value) => {
  let text = String(value ?? '');

  if (/^[\t\r\n ]*[=+\-@]/.test(text)) {
    text = `'${text}`;
  }

  return `"${text.replace(/"/g, '""')}"`;
};
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The skill description understates its actual capabilities: it appears to support lead scoring, interaction logging, destructive clearing, and local file read/write without declaring permissions. This mismatch is dangerous because operators may approve or invoke the skill based on incomplete expectations, while the implementation can manipulate local data and potentially process consumer outreach information in ways not clearly disclosed. In security reviews, behavior-description drift is a meaningful trust and consent failure.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The clear command irreversibly deletes all saved leads without any confirmation, safeguard, or recovery mechanism. This makes accidental or coerced invocation highly damaging, resulting in complete loss of CRM data stored by the skill.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill declares no permissions or allowed tool scope, yet its documented behavior includes local file access and the static finding indicates code capabilities related to environment access. Missing scope declarations weaken least-privilege controls and make it harder for users or the platform to understand what the skill can access. In an agent setting, undocumented access to env or filesystem can expose sensitive workspace or runtime data beyond the stated CRM purpose.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The documented clear command removes all leads but only says 'use with caution,' which is not a sufficient warning for an irreversible destructive action. In a local CRM context, accidental invocation could wipe user data, and an agent may call it without the user fully understanding the consequence if safeguards are absent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Lead and consumer data is persisted to local JSON/CSV files without an explicit warning or consent flow, which can surprise users and cause unintended retention of potentially sensitive personal or business contact information. In a skill handling CRM-style data, silent persistence increases privacy and data-handling risk, especially in shared or long-lived workspaces.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes a skill focused on tracking leads locally, managing outreach campaigns, and exporting CSVs. This file additionally implements a separate B2C marketing capability, including multi-step consumer email/DM sequence generation and consumer-intent scoring, which goes beyond the narrower stated outreach CRM/tracking description.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The top-level doc comment says the skill automates outreach and saves leads locally, then states that CRM/Supabase sync is available on paid plans. In this file, no CRM or Supabase sync exists; the related functions only return failure placeholders, so the documentation overstates actual behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.