Back to skill

Security audit

Nex Crm

Security checks for vulnerabilities and agentic risk

Overview

This is a local CRM skill whose sensitive storage and exports match its stated purpose, with some setup and privacy caveats users should understand.

Install only if you are comfortable keeping CRM contact details, notes, messages, reminders, deal values, and exports on this machine. Review exported CSV/JSON files before sharing, keep ~/.nex-crm private, and be cautious with the setup script because it upgrades pip from the configured package index.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T08 · Insecure Dependencies

Warning
Location
setup.sh:79
Finding
Unpinned Network Package Upgrade During Installation## Vulnerability Details **File Location**: `setup.sh:79-82` **Vulnerability Type**: Uncontrolled third-party dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash echo "[5/6] Installing Python dependencies..." "$VENV_PIP" install --quiet --upgrade pip # Nex CRM uses stdlib only - no external dependencies echo " Environment ready (zero external dependencies)." ``` ### Technical Analysis The setup process upgrades `pip` from the package index configured in the user's environment without pinning a version, verifying a package hash, or explicitly selecting a trusted repository. This introduces a mutable supply-chain dependency even though the application states that it uses only the Python standard library. The effective source can be affected by pip configuration files, environment variables such as `PIP_INDEX_URL` and `PIP_EXTRA_INDEX_URL`, DNS or repository compromise, or a malicious package mirror. If an attacker controls the selected package source, a compromised distribution could be installed into the virtual environment. A malicious source distribution may also cause build-system code to run during installation. ### Attack Path 1. An attacker compromises or controls the package index selected by the victim's pip configuration, or modifies the victim's pip-related environment variables. 2. The victim runs `bash setup.sh`. 3. Line 80 requests the latest available `pip` package without a pinned version or integrity hash. 4. The attacker-controlled distribution is downloaded and installed into `~/.nex-crm/venv`. 5. Malicious build behavior may execute during installation, or installed malicious code may execute when the virtual environment's Python or pip components are subsequently used. ### Impact Assessment Successful exploitation operates with the privileges of the user running the installer. It could modify files accessible to that user, compromise the CRM virtual environment, access ...[truncated 209 chars]
Remediation
## Remediation Suggestions Remove the upgrade because the application has no external Python dependencies: ```bash # No dependency installation is required. echo " Environment ready (zero external dependencies)." ``` If upgrading pip is operationally necessary: 1. Pin an audited version rather than requesting the latest release. 2. Download and verify an expected cryptographic hash before installation. 3. Explicitly configure an approved HTTPS package index and disable untrusted extra indexes. 4. Avoid inheriting uncontrolled pip configuration and proxy environment variables during automated installation. 5. Document that setup performs network access instead of claiming that no external dependency operation occurs.

T09 · Insecure Skill Coding Practices

Note
Location
lib/storage.py:8
Finding
Sensitive CRM Storage May Inherit Permissive Filesystem Permissions## Vulnerability Details **File Location**: `lib/storage.py:8-13` **Vulnerability Type**: Insufficient protection of locally stored sensitive data **Risk Level**: Low ### Vulnerable Code ```python from config import DB_PATH, DATA_DIR, PIPELINE_STAGES, ACTIVITY_TYPES, LEAD_SOURCES # Ensure data directory exists DATA_DIR.mkdir(parents=True, exist_ok=True) ``` The relevant configurable paths are defined in `lib/config.py:11-14`: ```python DATA_DIR = Path(os.environ.get("NEX_CRM_DATA", Path.home() / ".nex-crm")) DB_PATH = DATA_DIR / "crm.db" LOG_PATH = DATA_DIR / "nex-crm.log" EXPORT_DIR = DATA_DIR / "exports" ``` ### Technical Analysis The storage module creates `DATA_DIR` without supplying or enforcing a restrictive mode. Consequently, newly created directories and SQLite files inherit permissions from the process's ambient umask. Although `setup.sh` applies mode `0700` to its hard-coded default directory on non-Windows systems, Python supports a different location through `NEX_CRM_DATA`. The setup script does not apply its `chmod` operation to that configurable path. Runtime-created export directories and exported CRM files likewise rely on inherited permissions. CRM records can contain names, email addresses, telephone numbers, sales values, notes, reminders, and interaction messages. These files should therefore not depend solely on an unknown process umask. ### Attack Path 1. The application is initialized with `NEX_CRM_DATA` pointing to a new path, or it runs in an environment with a permissive umask. 2. `DATA_DIR.mkdir(parents=True, exist_ok=True)` creates the data directory with permissions derived from that umask. 3. SQLite and export operations create files whose modes are also determined by the ambient umask. 4. Another local account with traversal and read access to the path reads `crm.db` or exported CSV/JSON files. 5. The local account obtains contact information, sales records, notes, rem ...[truncated 517 chars]
Remediation
## Remediation Suggestions 1. Create the data and export directories with mode `0700`. 2. Verify and tighten the permissions of existing directories rather than applying secure modes only when creating new ones. 3. Ensure the SQLite database and exported files use mode `0600`. 4. Apply protections to the resolved `NEX_CRM_DATA` path, not only the default `~/.nex-crm` directory. 5. Reject unsafe targets such as unexpected symbolic links where the deployment threat model includes hostile local users. 6. Document equivalent access-control requirements for platforms that do not use POSIX modes. Example hardening: ```python DATA_DIR.mkdir(parents=True, exist_ok=True, mode=0o700) DATA_DIR.chmod(0o700) EXPORT_DIR.mkdir(parents=True, exist_ok=True, mode=0o700) EXPORT_DIR.chmod(0o700) ``` After creating the database or an export, explicitly restrict it: ```python DB_PATH.chmod(0o600) output_file.chmod(0o600) ```
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (13)

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill advertises shell-based setup and CLI usage that create directories, install dependencies, initialize a database, and export data, yet it declares no explicit tool scope or allowed-tools boundary. This increases the chance an agent invokes shell, reads environment context, or writes files without transparent least-privilege constraints, especially in environments that rely on manifest-declared permissions for safety review.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The trigger list includes broad everyday terms such as "pipeline," "follow-up," "CRM," "prospects," and "contact Jan," which can match normal conversation outside the user's intent to use this skill. Over-broad activation can cause unintended access to local CRM data, accidental writes, or command execution in response to ambiguous language.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The setup and usage sections describe initializing a local database, logging activities, storing conversations, reminders, and exporting prospect data, but they do not clearly warn users that potentially sensitive customer and contact information will be persisted to disk and exported to files. This can lead to users unknowingly storing regulated or confidential business data locally without informed consent or handling guidance.

Session Persistence

Medium
Category
Rogue Agent
Content
### Add Prospect

Create a new prospect from natural language or structured data:

```bash
# Natural language
Confidence
92% confidence
Finding
The skill is explicitly designed to remember conversation context, log interactions, and persist prospect records, which creates session persistence of sensitive customer relationship data beyond the immediate chat. In a CRM context this is expected functionality, but it still materially increases privacy and confidentiality risk because names, phone numbers, emails, deal status, and message history are retained and can later be surfaced or exported.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This module persistently stores CRM data, including contact details, notes, activities, reminders, and interaction history, in a local SQLite database with no visible controls for encryption, retention, minimization, or consent/disclosure. In the context of a chat-native CRM for Belgian businesses handling customer and prospect data, that increases privacy and compliance risk because sensitive personal and business information may be stored longer than expected or exposed to local users/processes if the host is compromised.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The export function writes the full CRM dataset, including prospect/contact details, to disk in plaintext JSON or CSV without any access control checks, destination restrictions beyond a configured directory, masking, or warning. In a CRM context, this increases the risk of sensitive business and personal data exposure through local compromise, shared workstations, backups, or accidental file sharing.

Session Persistence

Medium
Category
Rogue Agent
Content
PY_VERSION="$($PYTHON --version 2>&1)"
echo "  Found: $PY_VERSION"

# Step 2: Create data directory
echo "[2/6] Creating data directory..."
mkdir -p "$DATA_DIR"
if [ "$PLATFORM" != "windows" ]; then
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
echo "[2/6] Creating data directory..."
mkdir -p "$DATA_DIR"
if [ "$PLATFORM" != "windows" ]; then
    chmod 700 "$DATA_DIR"
fi
echo "  Data directory: $DATA_DIR"
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Scope Creep

Low
Category
Excessive Agency
Content
or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
Confidence
70% confidence
Finding
Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Intent-Code Divergence

Low
Confidence
92% confidence
Finding
The function is documented as getting follow-ups due and accepts a `days_ahead` parameter, suggesting callers can request follow-ups within some future window. The implementation never uses `days_ahead` and filters strictly on `f.date <= now`, which contradicts the advertised interface and intent.

Intent-Code Divergence

Low
Confidence
95% confidence
Finding
The function signature and docstring present this as an export routine with a `format` parameter, which implies behavior such as JSON/CSV or other selectable export formats. In reality, the implementation ignores `format` entirely and just returns the in-memory result of `list_prospects({})`, so the documented intent diverges from actual behavior.

Description-Behavior Mismatch

Low
Confidence
80% confidence
Finding
The manifest explicitly advertises discovering stale prospects who have not been contacted in over two weeks. In this file, the `--stale` flag only adds `filters['stale'] = True` before calling `list_prospects`, while the dedicated stale-prospect function imported at L029-L030 (`get_stale_prospects`) is never used here, so the advertised behavior is not evidenced by the implementation shown.

Intent-Code Divergence

Low
Confidence
98% confidence
Finding
The CLI definition documents a `--since` argument for the `stats` command, implying date-scoped statistics. However, `cmd_stats` runs fixed aggregate queries at L408-L423 and never reads `args.since`, so the documented intent contradicts actual behavior.

Static analysis

No suspicious patterns detected.