Back to skill

Security audit

b2b-sales-prospecting-agent

Security checks for vulnerabilities and agentic risk

Overview

This sales-prospecting skill is not clearly malicious, but it handles sensitive contact data and API credentials with under-disclosed remote uploads and weak local storage safeguards.

Install only if you are comfortable sending prospecting filters, target companies, contact identifiers, and possibly CSV-derived names/emails/LinkedIn data to Explorium. Do not use it with employee, customer, regulated, or confidential lists unless you have authorization and a lawful basis. Prefer a securely set environment variable over the setup prompt or --api-key command, avoid exporting sensitive lists to Downloads, and clean up /tmp/agentsource_*.json result files after use.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
bin/agentsource.py:117
Finding

Predictable and Non-Private Temporary Files Allow Data Disclosure and Symlink Overwrite

Content
View full analysis
pathlib.Path: ts = int(time.time()) return TEMP_DIR / f"agentsource_{ts}_{command}.json" def write_result(command: str, data: dict) -> pathlib.Path: path = make_temp_path(command) path.write_text(json.dumps(data, indent=2, default=str)) print(str(path)) return path def write_error(command: str, error_msg: str, error_code: str = None, http_status: int = None) -> pathlib.Path: data = { "success": False, "error": error_msg, "error_code": error_code, "http_status": http_status, "command": command, "timestamp": int(time.time()), } path = make_temp_path(f"{command}_error") path.write_text(json.dumps(data, indent=2)) print(str(path)) return path ``` ### Technical Analysis Temporary filenames consist only of the current second and a known command name. They are therefore predictable and can collide when multiple commands of the same type run during the same second. `Path.write_text()` does not provide exclusive file creation and follows an existing symbolic link. An attacker with access to the shared `/tmp` directory can pre-create the predicted path as a symbolic link to another file writable by the victim. When the CLI writes its result, it follows that link and overwrites the target. The code also does not explicitly set mode `0600`. File permissions consequently depend on the process umask and commonly become `0644`, allowing other local users to read them. These files may contain complete uploaded CSV rows, prospect names, professional or personal email addresses, direct or mobile phone numbers, LinkedIn profiles, and business intelligence. ### Attack Path 1. A local ...[truncated 1027 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:141
Finding

Original User Requests Are Sent to a Remote Service Without Required Consent

Content
View full analysis
" ``` ```bash RESULT=$(python3 "$CLI" autocomplete \ --entity-type businesses \ --field linkedin_category \ --query "software" \ --semantic \ --plan-id "$PLAN_ID" \ --call-reasoning "$QUERY") cat "$RESULT" ``` The CLI converts that value into remote request metadata: ```python def _request_context(args): """Build the optional request_context payload for server-side call grouping. Privacy note: when --call-reasoning is supplied, the user's query text is sent to api.explorium.ai as part of the request metadata. This is opt-in — omit --call-reasoning if the user has not consented to query logging. """ reasoning = getattr(args, "call_reasoning", None) plan_id = getattr(args, "plan_id", None) if not reasoning and not plan_id: return None return { "type": "vibe-prospecting-plugin", "call_reasoning": reasoning, "plan_id": plan_id, } ``` ### Technical Analysis The implementation correctly notes that transmitting `call_reasoning` should be opt-in, but the authoritative workflow in `SKILL.md` uses it by default and does not instruct the agent to obtain consent first. A user's original request can contain internal targeting strategy, confidential company names, customer information, exclusion lists, campaign plans, or personal data. Sending the original text is not technically necessary for autocomplete, statistics, fetch, enrichment, matching, or event retrieval. Search filters and entity identifiers are sufficient t ...[truncated 1254 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
bin/agentsource.py:729
Finding

CSV Matching Uploads Personal and Business Data Without Specific Disclosure or Confirmation

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
setup.sh:69
Finding

API-Key Setup Exposes Secrets Through Visible Input, Terminal Output, and Command-Line Arguments

Content
View full analysis
"$CONFIG_FILE" chmod 600 "$CONFIG_FILE" echo "[OK] API key saved to $CONFIG_FILE (mode 600, owner read-only)" fi else echo "No EXPLORIUM_API_KEY environment variable detected." echo "" read -r -p "Enter your Explorium API key (or press Enter to skip): " api_key if [ -n "${api_key:-}" ]; then printf '{\n "api_key": "%s"\n}\n' \ "$api_key" > "$CONFIG_FILE" chmod 600 "$CONFIG_FILE" echo "[OK] API key saved to $CONFIG_FILE (mode 600, owner read-only)" echo "" echo "To also set it as an environment variable, add this to ~/.zshrc or ~/.bashrc:" echo " export EXPLORIUM_API_KEY='$api_key'" else echo "[WARN] No API key configured." echo " Set it later with: python3 $BIN_DIR/agentsource.py config --api-key " echo " Or set env var: export EXPLORIUM_API_KEY=" echo " Get a key at: https://developers.explorium.ai/reference/setup/getting_your_api_key" fi fi ``` The documented alternative also places the key in a command-line argument: ```bash python3 ~/.agentsource/bin/agentsource.py config --api-key your_api_key_here ``` ### Technical Analysis The interactive prompt uses `read -r` rather than `read -r -s`, so the API key remains visible while the user types it. Afterward, the script prints an export command containing the exact key, exposing i ...[truncated 1730 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
Findings (20)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README advertises very broad natural-language trigger phrases such as 'build a list of', 'find contacts at', and 'find companies that', which can easily overlap with ordinary user conversation. In agent environments that auto-route on fuzzy trigger matching, this can cause unintended activation and transmission of user requests or sensitive context to the prospecting plugin.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill performs sensitive operations including shell execution, environment-variable access, local file reads/writes, and remote network calls, but it does not declare any explicit tool scope or permission boundaries. That mismatch increases the chance the host agent will invoke the skill with broader capabilities than users expect, enabling command execution, data exfiltration, or filesystem side effects without clear consent.

Content

No source excerpt is available for this finding.

Shadow Command Trigger

Medium
Category
Trigger Abuse
Confidence
82% confidence
Finding

The trigger phrase 'find prospects' overlaps with generic 'find' semantics and may shadow built-in or unrelated request routing. In a skill with shell, file, and network capabilities, ambiguous invocation can unintentionally route common user requests into an external prospecting workflow and expose data or create side effects.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger phrases are broad enough to match many ordinary requests such as 'find companies' or 'build a list of', causing the skill to activate outside a clearly scoped prospecting context. When combined with shell and network capabilities, accidental activation could send user queries to a third-party API or initiate local file operations the user did not intend.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
93% confidence
Finding

The skill explicitly transmits search filters, entity IDs, and request metadata to a remote third-party API. While remote access is core to the skill's business function, it still creates a real data-exposure risk because user-supplied prospecting criteria, company targets, and possibly sensitive business intent are sent off-host.

Content

Scanner excerpt · SKILL.md (reported line 49)May include surrounding context.

md
- "find companies that"
metadata:
  required_env_vars: "EXPLORIUM_API_KEY — your Explorium AgentSource API key. Set via environment variable or run: python3 <cli_path> config --api-key <key>"
  data_sent_to_remote: "Search filters, entity IDs, and optional request metadata are sent to https://api.explorium.ai/v1/. See README for full details."
---

# B2B Sales Prospecting & Lead Discovery Agent

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 85)May include surrounding context.

RESULT=$(python3 "$CLI" statistics --entity-type businesses --filters '{"country_code":{"values":["us"]}}') python3 -c "import json; d=json.load(open('$RESULT')); print(d.get('error_code','OK'))"

text
If it prints `AUTH_MISSING`, show the secure API key setup instructions (never ask the user to paste keys in chat).

---

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill writes prospect data to a predictable local path in the user's Downloads directory, but this behavior is not clearly disclosed up front in the description. That can expose sensitive lead lists and contact details to other local users, backup/sync services, or accidental sharing, especially because the exported data may include emails and phone numbers.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The config command persists the API key to disk in ~/.agentsource/config.json without an execution-time warning, even though storing long-lived credentials locally changes the user's risk profile. While file permissions are restrictive, silent credential persistence can still surprise users and leave secrets resident on shared or backed-up systems.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The from-csv command accepts any user-supplied filesystem path and reads the file into the skill's processing pipeline. In an agent setting, this broad local file read capability exceeds the advertised B2B prospecting scope and could be abused to access unrelated local data if the model is induced to pass sensitive paths.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The to-csv command writes data to an arbitrary path supplied at runtime, giving the skill a general-purpose local file write/export primitive. In an agent environment, this can be abused to place sensitive prospect data in unexpected locations or overwrite user files if the agent is tricked into using unsafe paths.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The CSV export implementation silently writes fetched or enriched data to disk without an execution-time warning about local persistence or data sensitivity. Because this skill handles business contacts and verified emails/phone numbers, silent export increases the risk of unintended local storage and secondary disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The example explicitly exports a CSV of business contact data, including verified emails, to a local Downloads folder without any warning, consent language, or guidance on secure handling. While writing to Downloads is not inherently malicious, it increases the risk of accidental exposure, syncing to unmanaged devices/services, or mishandling of sensitive prospect data in a sales workflow that involves personal contact information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly supports enrichment of professional email, personal email, direct phone, and mobile phone for prospects, but provides no privacy notice, lawful-use constraints, or data-handling guidance. In a B2B prospecting context, this materially increases the risk of misuse for unsolicited outreach, privacy violations, or collection of personal data without appropriate consent or compliance checks.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · README.md (reported line 75)May include surrounding context.

md
#   ~/.agentsource/config.json          — API key storage (mode 600, only if you choose to save it)
#
# Nothing is sent to any network during setup. The API key is only used when
# you run CLI commands that call https://api.explorium.ai/v1/.

PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
INSTALL_DIR="$HOME/.agentsource"

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · bin/agentsource.py (reported line 33)May include surrounding context.

python
#   ~/.agentsource/config.json          — API key storage (mode 600, only if you choose to save it)
#
# Nothing is sent to any network during setup. The API key is only used when
# you run CLI commands that call https://api.explorium.ai/v1/.

PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
INSTALL_DIR="$HOME/.agentsource"

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · setup.sh (reported line 12)May include surrounding context.

sh
#   ~/.agentsource/config.json          — API key storage (mode 600, only if you choose to save it)
#
# Nothing is sent to any network during setup. The API key is only used when
# you run CLI commands that call https://api.explorium.ai/v1/.

PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
INSTALL_DIR="$HOME/.agentsource"

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · setup.sh (reported line 46)May include surrounding context.

sh
echo "[OK] Python $PYTHON_VERSION"

# ---------------------------------------------------------------------------
# 2. Create directory structure
# ---------------------------------------------------------------------------
mkdir -p "$BIN_DIR"
echo "[OK] Created $BIN_DIR"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · setup.sh (reported line 75)May include surrounding context.

sh
if [[ "${save_key:-}" =~ ^[Yy]$ ]]; then
        printf '{\n  "api_key": "%s"\n}\n' \
            "$EXPLORIUM_API_KEY" > "$CONFIG_FILE"
        chmod 600 "$CONFIG_FILE"
        echo "[OK] API key saved to $CONFIG_FILE (mode 600, owner read-only)"
    fi
else

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · setup.sh (reported line 85)May include surrounding context.

sh
if [[ "${save_key:-}" =~ ^[Yy]$ ]]; then
        printf '{\n  "api_key": "%s"\n}\n' \
            "$EXPLORIUM_API_KEY" > "$CONFIG_FILE"
        chmod 600 "$CONFIG_FILE"
        echo "[OK] API key saved to $CONFIG_FILE (mode 600, owner read-only)"
    fi
else

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The setup script prints a shell export command that embeds the user's actual API key directly into terminal output. This can expose the credential via screen sharing, terminal scrollback, logging tools, shell history if copied verbatim, or shoulder-surfing, which is especially sensitive because this plugin handles access to a lead-generation API.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.