Back to skill

Security audit

Personal CRM Warm-Up

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims locally, but users should treat contact data as sensitive and avoid rendering untrusted contact fields as rich Markdown.

Install only if you are comfortable letting the skill read your local contacts file and display relationship details in its output. Keep contacts.json under your control, avoid custom contact files from untrusted sources, and render the generated Markdown in a viewer that disables raw HTML and remote resource loading when possible.

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
handler.js:96
Finding

Unescaped Contact Data Allows Markdown and HTML Content Injection

Content
View full analysis

Vulnerability Details

File Location: handler.js, lines 96–111
Vulnerability Type: Improper output encoding for Markdown content
Risk Level: Medium

Vulnerable Code

js
for (const c of overdue) {
  const hook = c.lastTopic.split(" ").slice(0, 6).join(" ") + "...";
  lines.push(
    `| ${c.name} | ${c.category} | ${c.days}d | +${c.overdue}d | ${hook} |`
  );
}

lines.push("");
lines.push("---");
lines.push("");
lines.push("**Draft Messages:**\n");

for (const c of overdue) {
  const draft = draftMessage(c);
  lines.push(`**${c.name}** (${c.contactMethod}):`);
  lines.push(`> ${draft}\n`);
}

The generated draft also incorporates unescaped contact data through draftMessage():

js
const topic = contact.lastTopic;
const name = contact.name.split(" ")[0];

const templates = [
  `Hey ${name}, I saw something that reminded me of you — ${topic.toLowerCase()}. How's that going?`,
  `Hey ${name}! I was just thinking about ${topic.toLowerCase()}. Any updates? Would love to catch up.`,
  `${name}! It's been a minute. Last time we talked ${topic.toLowerCase()} — still on that? Let's reconnect soon.`,
];

Technical Analysis

Values originating from a contacts file—including name, category, lastTopic, and contactMethod—are interpolated directly into Markdown output without contextual escaping or schema validation. Markdown control characters, raw HTML, links, images, block delimiters, and table separators can therefore alter the structure and meaning of the generated report.

For example, a crafted lastTopic can introduce a remote image or deceptive link. A crafted name containing table separators or line breaks can terminate the intended table cell and inject additional report content. Whether raw HTML or remote resources become active depends on the downstream Markdown renderer and its security configuration.

The issue is classified as `T09: Insecure Ski ...[truncated 1916 chars]

Remediation
View remediation

Remediation Suggestions

  1. Validate the complete contacts document immediately after JSON parsing. Require an array of objects with bounded string fields and enforce documented enumerations for category and contactMethod.
  2. Escape all Markdown metacharacters according to the output context. Table cells must escape at least pipes, backslashes, HTML delimiters, and line breaks. Draft text must separately escape Markdown links, images, block markers, and raw HTML.
  3. Normalize or reject carriage returns and newline characters in fields intended to remain on one output line.
  4. Apply reasonable maximum lengths to names, topics, categories, and contact methods to prevent output manipulation and resource abuse.
  5. Configure the downstream Markdown renderer to disable raw HTML and automatic remote-resource loading. Apply a restrictive content security policy where rendered output is displayed in a browser.
  6. Prefer a structured return format such as JSON and let a trusted presentation layer perform context-aware encoding.
  7. Add security tests using contact values containing table separators, line breaks, Markdown links, image syntax, and raw HTML to verify that they are displayed as literal text rather than interpreted markup.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill loads personal contact records from disk and later renders names, categories, interaction recency, topics, and draft outreach messages directly into output without any consent, minimization, or privacy notice. In an agent or shared runtime context, this can disclose sensitive relationship metadata to users or logs beyond the data subject’s expectations.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The manifest describes a personal CRM helper that identifies overdue contacts and suggests reconnection messages. Reading process environment variables to control behavior is not an obvious requirement of that purpose and introduces access to host-level configuration beyond simple contact analysis.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.