Back to skill

Security audit

AI Crush Simulator

Security checks for vulnerabilities and agentic risk

Overview

This skill is a local, heuristic crush-advice tool with no evidence of hidden data access, persistence, or exfiltration, though one reply feature omits the promised disclaimer.

This appears reasonable to install if you are comfortable sharing crush or relationship details with the local skill flow. Treat its advice as lightweight suggestions, not facts about another person, and prefer a version that fixes the missing reply disclaimer and refreshes dev dependencies.

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

Note
Location
src/modules/replyGenerator.ts:94
Finding

Required Safety Disclaimer Is Missing from Reply Generation Outputs

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:22, SKILL.md:46, SKILL.md:190-191, src/types.ts:85-89, src/modules/replyGenerator.ts:94-106, and cli/main.ts:55-67
Vulnerability Type: Missing enforcement of a declared output safety control
Risk Level: Low

The Skill metadata declares alwaysDisclaimer: true, and its documentation requires every output to include a disclaimer framed as “Based on what you shared...”. However, the reply-generation result type has no disclaimer field, generateReplies() does not return a disclaimer, and the CLI reply renderer does not display one.

Vulnerable Code

src/types.ts:85-89:

ts
export interface ReplyOptions {
  goal: UserGoal;
  replies: ReplyOption[];
  tip: string;
}

src/modules/replyGenerator.ts:94-106:

ts
export function generateReplies(context: ReplyContext): ReplyOptions {
  const template = TEMPLATES[context.userGoal];
  const tones: ReplyTone[] = ['bold', 'chill', 'safe'];

  const replies: ReplyOption[] = tones.map(tone => ({
    tone,
    text:      template[tone].text,
    rationale: template[tone].rationale,
  }));

  return {
    goal: context.userGoal,
    replies,
    tip: template.tip,
  };
}

cli/main.ts:55-67:

ts
function printReplies(options: ReturnType<typeof generateReplies>) {
  section('✏️  Reply Options');
  for (const reply of options.replies) {
    const label = reply.tone === 'bold'  ? '🔥 Bold'
                : reply.tone === 'chill' ? '😎 Chill'
                :                          '🙂 Safe';
    print(`\n${label}`);
    print(`  "${reply.text}"`);
    print(`  → ${reply.rationale}`);
  }
  print(`\n💡 Tip: ${options.tip}`);
}

Technical Analysis

The implementation does not enforce the safety contract declared in SKILL.md. Other user-facing modules return an explicit disclaimer, but generateReplies() returns actionable i ...[truncated 1550 chars]

Remediation
View remediation

Remediation Suggestions

  1. Add a mandatory disclaimer: string property to ReplyOptions:

    ts
    export interface ReplyOptions {
      goal: UserGoal;
      replies: ReplyOption[];
      tip: string;
      disclaimer: string;
    }
    
  2. Define and return the required disclaimer from generateReplies():

    ts
    const DISCLAIMER =
      'Based on what you shared — these are general reply ideas, not facts about what the other person feels. Choose only what feels authentic and respectful to you.';
    
    return {
      goal: context.userGoal,
      replies,
      tip: template.tip,
      disclaimer: DISCLAIMER,
    };
    
  3. Update printReplies() and the test renderer to display options.disclaimer.

  4. Add automated assertions confirming that every public user-facing module returns a non-empty disclaimer beginning with the required framing.

  5. Add a policy consistency test that compares mandatory Skill metadata controls with the fields and behavior of every public output type.

Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The declared description presents a broader coaching skill with multiple user-facing capabilities: analyzing situations, decoding crush texts, generating replies, and advising on next steps. This code chunk only performs one subset of that promise: it combines a few situation fields, runs heuristic scoring and flag detection, derives a connection-depth label, and returns a summary/disclaimer. There is no logic here for text-message decoding as a distinct function, no reply generation, and no concrete recommendation engine for what to do next. The behavior is related to the domain, but the implemented capability in this chunk is materially narrower than the declared description.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger phrases are broad enough that the skill may activate for generic relationship-advice requests, causing unintended invocation and possible routing of sensitive teen/social conversations into this skill. In a youth-focused advice context, accidental activation can increase privacy and safety risk because users may share personal interpersonal details they did not intend for this specific skill flow.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: esbuild==0.27.3 — 1 advisory(ies): GHSA-g7r4-m6w7-qqqr (esbuild allows arbitrary file read when running the development server on Window)

Low
Category
Supply Chain
Confidence
60% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

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

json
"author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/node": "^25.4.0",
    "tsx": "^4.21.0",
    "typescript": "^5.9.3"
  }

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

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

json
"license": "ISC",
  "devDependencies": {
    "@types/node": "^25.4.0",
    "tsx": "^4.21.0",
    "typescript": "^5.9.3"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

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

json
"devDependencies": {
    "@types/node": "^25.4.0",
    "tsx": "^4.21.0",
    "typescript": "^5.9.3"
  }
}