Back to skill

Security audit

freelancer-crm

Security checks for vulnerabilities and agentic risk

Overview

This freelancer CRM skill is mostly purpose-aligned, but it handles WhatsApp credentials and client data in ways users should review carefully before installing.

Install only if you are comfortable with a local CRM skill reading and writing client records and sending WhatsApp messages. Before using the official API mode, consider moving the API token to a secret manager or environment variable, adding a .gitignore for config.json and clients.json, restricting file permissions, and reviewing each outbound message before approval.

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.py:17
Finding

Unpinned Dependencies Installed Automatically at Runtime

Content
View full analysis

Vulnerability Details

File Location: setup.py:17-22
Vulnerability Type: Unpinned runtime dependency installation
Risk Level: Medium

Vulnerable Code

python
# Step 2: Install dependencies
print("\nInstalling required dependencies...")
try:
    subprocess.run([sys.executable, "-m", "pip", "install", "filelock", "requests"], check=True)
    print("Dependencies installed.")
except subprocess.CalledProcessError:
    print("Error: Failed to install dependencies. Please install 'filelock' and 'requests' manually.")
    sys.exit(1)

Technical Analysis

The setup process installs filelock and requests from the active Python package index without version constraints, cryptographic hashes, a lockfile, or an explicitly trusted index. Package resolution therefore depends on mutable external repository state and local pip configuration.

Although both package names correspond to established packages and there is no evidence that this project intentionally retrieves a malicious dependency, the installation mechanism does not guarantee that the installed artifacts are the versions reviewed or tested by the project author. A compromised upstream release, package-index account, configured mirror, or local pip index setting could cause attacker-controlled code to be installed.

Python packages can execute build-related code during installation. Installed dependency code is also later imported by the application, including requests in whatsapp_api.py and filelock in crm_cli.py.

Attack Path

  1. An attacker compromises an upstream package release, package publisher account, configured package mirror, or package-index resolution path.
  2. The user runs python3 setup.py.
  3. The setup script invokes pip without version or hash verification.
  4. Pip resolves and installs the attacker-controlled artifact.
  5. Malicious code executes during package installation or when the dependency is subsequ ...[truncated 605 chars]
Remediation
View remediation

Remediation Suggestions

  • Define reviewed, exact dependency versions in a requirements lockfile.

  • Record and enforce cryptographic hashes for every accepted distribution.

  • Install with a command such as:

    bash
    python3 -m pip install --require-hashes -r requirements.txt
    
  • Prefer documenting dependency installation separately instead of automatically modifying the user's Python environment during application setup.

  • Use a dedicated virtual environment and a trusted, explicitly configured package index.

  • Add automated dependency vulnerability and integrity checks to the release process.

  • Regularly update pins through a controlled review and testing workflow rather than resolving unrestricted latest versions at installation time.

T09 · Insecure Skill Coding Practices

Warning
Location
setup.py:43
Finding

WhatsApp API Bearer Token Stored in a Plaintext Configuration File

Content
View full analysis

Vulnerability Details

File Location: setup.py:43-46, 61-70
Vulnerability Type: Plaintext sensitive credential storage
Risk Level: Medium

Vulnerable Code

python
api_token = ""
api_phone_id = ""
if choice == "2":
    api_token = input("WhatsApp Business API token (from Meta Developer Console): ")
    api_phone_id = input("WhatsApp Phone Number ID (from Meta Developer Console): ")
else:
    print("\nWhatsApp Bridge selected. After setup completes, run:")
    print("  openclaw integrations whatsapp")
    print("Then scan the QR code with your phone to connect.")

# Step 5: Validate phone number format
if not user_phone.startswith("+"):
    print("Error: Phone number must start with + (e.g. +923001234567)")
    sys.exit(1)

# Step 6: Write config.json
config = {
    "user_name": user_name,
    "user_phone": user_phone,
    "whatsapp_method": "bridge" if choice == "1" else "api",
    "api_token": api_token,
    "api_phone_id": api_phone_id,
    "follow_up_days": int(follow_up_days),
    "invoice_reminder_days": int(invoice_reminder_days)
}

with open("config.json", "w") as f:
    json.dump(config, f, indent=2)

The stored credential is subsequently loaded and used as follows:

python
with open(config_path, "r") as f:
    config = json.load(f)

# ...

token = config.get("api_token", "")
phone_id = config.get("api_phone_id", "")

Technical Analysis

Setup collects a WhatsApp Business API bearer token and writes it directly into config.json. The file is created with the process's default permission behavior and no explicit restrictive mode such as 0600. The audited project also does not contain the .gitignore file that the README claims protects config.json and clients.json.

This creates exposure through permissive filesystem defaults, shared hosts, backups, copied Skill directories, support bundles, or accidental source-control commits. ...[truncated 1432 chars]

Remediation
View remediation

Remediation Suggestions

  • Store the API token in an operating-system secret store, deployment secret manager, or protected environment variable rather than config.json.

  • If file-based storage is unavoidable, create the secret file atomically with owner-only permissions:

    python
    import os
    import json
    
    fd = os.open(
        "config.json",
        os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
        0o600,
    )
    with os.fdopen(fd, "w") as f:
        json.dump(config, f, indent=2)
    
  • Separate secrets from non-sensitive configuration so ordinary configuration can be copied or backed up safely.

  • Ship a .gitignore that explicitly excludes config.json, clients.json, lock files, and other generated sensitive files.

  • Add startup checks that reject secret files readable or writable by group or other users.

  • Avoid requesting the token through visible terminal input where feasible; use a no-echo input mechanism such as getpass.getpass.

  • Document token expiration, least-privilege scoping, rotation, and immediate revocation procedures.

  • Ensure backups and diagnostic bundles exclude or encrypt credential files.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill explicitly directs the agent to use a local CRM CLI and raw clients.json data, which likely contains sensitive client names, invoices, phone numbers, and proposal details, but it provides no warning about handling, minimizing, or redacting that data. Because the skill also has exec, read, write, and web_fetch capabilities and supports WhatsApp messaging, an agent could expose CRM data in logs, outputs, generated digests, or outbound messages without clear safeguards.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The code sends arbitrary message content and recipient phone numbers through either a bridge or API path without any user-facing disclosure, confirmation, or consent step at the point of transmission. In an agent skill context, this can cause unintended exfiltration of sensitive content or accidental messaging to third parties, especially if invoked automatically or with untrusted inputs.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · setup.py (reported line 20)May include surrounding context.

python
# Step 2: Install dependencies
    print("\nInstalling required dependencies...")
    try:
        subprocess.run([sys.executable, "-m", "pip", "install", "filelock", "requests"], check=True)
        print("Dependencies installed.")
    except subprocess.CalledProcessError:
        print("Error: Failed to install dependencies. Please install 'filelock' and 'requests' manually.")

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The setup flow collects a WhatsApp Business API token and writes it directly into config.json in plaintext without warning the user that sensitive credentials will be stored locally. If the skill directory is readable by other local users, synced to cloud storage, committed to version control, or exfiltrated by another process, the token could be abused to send messages or access the associated WhatsApp Business integration.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
93% confidence
Finding

The code persists operational data and, depending on the selected mode, sensitive API credentials in config.json for future reuse. Persistent local storage increases the exposure window for secrets and personal data such as the user's phone number, especially since the script does not set restrictive file permissions or minimize retained sensitive fields.

Content

Scanner excerpt · setup.py (reported line 58)May include surrounding context.

python
print("Error: Phone number must start with + (e.g. +923001234567)")
        sys.exit(1)

    # Step 6: Write config.json
    config = {
        "user_name": user_name,
        "user_phone": user_phone,

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · whatsapp_api.py (reported line 18)May include surrounding context.

python
'text': {'body': message}
    }
    try:
        response = requests.post(url, headers=headers, json=payload)
        if response.status_code != 200:
            print(f"Error from WhatsApp API: {response.text}")
        return response.status_code == 200

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · whatsapp_bridge.py (reported line 8)May include surrounding context.

python
# This assumes the 'openclaw' CLI is available in the environment
    # and configured for the correct gateway.
    try:
        result = subprocess.run(
            ['openclaw', 'whatsapp', 'send', '--to', phone_number, '--message', message],
            capture_output=True, text=True
        )

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The initial usage message says the tool supports only 'list|follow-ups|invoices|proposal|digest', but the code also implements 'add' and 'update'. This is an active documentation mismatch because the help text presents a narrower, effectively read-oriented interface while the program actually supports modifying client records.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.