Back to skill

Security audit

Gracie Crm

Security checks for vulnerabilities and agentic risk

Overview

This is a functional local CRM skill, but it ships live-looking contact data and can import a fixed private lead file from the user's home directory without clear scoping or preview.

Install only if you intend to use this personal Gracie CRM workflow. Review or remove the bundled crm.json records first, understand that the import command may copy leads from the fixed ~/StudioBrain/30_INTERNAL/WLC-Services/LEADS/MASTER_LEAD_LIST.md path, and keep the CRM data file in a private location with restrictive permissions.

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
crm.py:54
Finding
Plaintext CRM records stored without enforced restrictive file permissions<![CDATA[ ## Vulnerability Details **File Location**: `crm.py:54-62`; sensitive records are present in `crm.json:1-368` **Vulnerability Type**: Plaintext sensitive-data storage and insufficient file-permission enforcement **Risk Level**: Medium ### Vulnerable Code ```python def load(): if not os.path.exists(CRM_FILE): return [] with open(CRM_FILE) as f: return json.load(f) def save(leads): with open(CRM_FILE, "w") as f: json.dump(leads, f, indent=2) ``` An example of the data exposed in `crm.json:20-40` is: ```json { "id": 2, "name": "P.A.C. Plumbing", "phone": "718-720-4980", "category": "hvac", "status": "interested", "calls": [ { "date": "2026-02-27", "outcome": "interested", "notes": "" } ], "notes": [ "Owner is Paul, best time is morning before 9am" ], "followup_date": "2026-03-03", "added": "2026-02-27" } ``` ### Technical Analysis The application stores lead names, telephone numbers, sales statuses, contact histories, follow-up dates, and free-form notes directly in an unencrypted JSON file. The project also distributes a populated copy of that file. The `save()` function opens `crm.json` without explicitly applying restrictive permissions. When the file is created, its effective permissions are determined by the process umask. In an environment with a permissive umask, other local users may be able to read the CRM data. The application does not subsequently verify or correct the file mode. Because the data file resides within the project directory, it may also be committed, copied, archived, or distributed with the Skill. Repository recipients do not need to run the application or bypass authentication to read the records. ### Attack Path 1. An attacker obtains read access to the project directory through local multi-user access, an exposed archive, repository access, backup access, or accidental project distribution. 2. The attacker locates `crm.json` in ...[truncated 1071 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove operational CRM records from the distributed Skill and replace `crm.json` with an empty array or clearly synthetic sample data. 2. Add `crm.json` to `.gitignore` and store live CRM data outside the source or Skill directory. 3. If real records were committed, assess the exposure and purge them from repository history where appropriate. Rotate or invalidate any sensitive information that can be changed. 4. Create the data file with owner-only permissions, such as mode `0600`, and verify permissions before every read and write. 5. Use atomic writes through a temporary file created with restrictive permissions, then replace the destination file to reduce corruption and permission risks. 6. Restrict access to the parent data directory, preferably with mode `0700`. 7. Consider an encrypted or authenticated datastore when the records contain personal, confidential, or regulated information. 8. Define and enforce data-retention rules for call histories and notes, and warn users not to store secrets or unnecessary sensitive personal information in free-form fields. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (5)

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger conditions are broad enough to match generic CRM and lead-management requests without clear boundaries, which can cause the agent to invoke this skill in situations the user did not specifically intend. That increases the risk of inappropriate access, modification, or disclosure of sales lead data, especially if other skills or workflows overlap in scope.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The script is hard-coded to read from a user-home path outside the skill directory and import its contents into the local CRM store. That creates an unexpected cross-boundary data access path that can expose unrelated personal or internal lead data and silently duplicate sensitive information into another file when the import command is run.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The import feature reads a hard-coded personal/internal markdown file and ingests its contents without any warning, confirmation, or scope limitation. In this skill context, that is more dangerous because a sales CRM will store names and phone numbers, so the behavior can quietly copy sensitive business contact data from an unrelated location into a new datastore.

Missing User Warnings

Low
Confidence
90% confidence
Finding
This code writes CRM lead data to crm.json, which is a user-data-affecting file write. Although the action is part of the tool's purpose, there is no docstring, comment, or command-level warning disclosing that lead additions, notes, calls, and imports persist data to disk.

Intent-Code Divergence

Low
Confidence
98% confidence
Finding
The _parse_master_leads docstring says a valid lead row may contain either a bold business name or a plausible non-header name. However, the code immediately below rejects any row where no bold text is found, so the documented parsing behavior contradicts the actual implementation.

Static analysis

No suspicious patterns detected.