Back to skill

Security audit

Companies & Contacts enrichment - Explorium AgentSource

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate B2B prospecting API skill, but it needs Review because its setup and result handling can expose API keys and prospect data on the local machine.

Install only if you are comfortable sending prospecting filters, entity IDs, and matching records to Explorium. Avoid running setup in recorded/shared terminals, do not paste API keys into chat, and treat /tmp result files and exported CSVs as sensitive until the publisher fixes private temp storage and credential handling.

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

T09 · Insecure Skill Coding Practices

Error
Location
bin/agentsource.py:115
Finding
Predictable and Insecure Temporary Files Expose Sensitive Prospect Data<![CDATA[ ## Vulnerability Details **File Location**: `bin/agentsource.py`, lines 115–129 **Vulnerability Type**: Predictable temporary files, non-atomic file creation, and insufficient file permissions **Risk Level**: High ### Vulnerable Code ```python def make_temp_path(command: str) -> 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: ``` The same predictable path construction and unrestricted `write_text()` operation are also used when error files are written. ### Technical Analysis The CLI stores API responses and imported CSV content directly in the shared `/tmp` directory. A filename consists only of the current timestamp in seconds and a predictable command name, such as: ```text /tmp/agentsource_1750000000_fetch.json ``` This construction has several security weaknesses: 1. **Predictable filenames:** A local attacker can calculate likely paths from the current time and known command names. 2. **Non-atomic creation:** `Path.write_text()` opens an existing pathname rather than securely creating a new, exclusive file. 3. **Symbolic-link following:** If an attacker creates the expected pathname as a symbolic link, the CLI follows it and overwrites the link target, provided the victim account can write to that target. 4. **No explicit restrictive permissions:** The resulting mode depends on the process umask. Under a common `022` umask, files are created as `0644` and may be readable by other local users. 5. **Filename collisions:** Two invocations of the same command during the same second use the same path and can overwrite or corrupt each other's results. 6. **No explicit cleanup: ...[truncated 1809 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use `tempfile.mkstemp()` or `tempfile.NamedTemporaryFile(delete=False)` to generate cryptographically unpredictable names and create files atomically. 2. Store results in a private per-user directory with mode `0700` rather than directly in shared `/tmp`. 3. Create each result file with mode `0600`, independent of the caller's umask. 4. Use exclusive creation semantics and reject symbolic links. On supported platforms, use `O_CREAT | O_EXCL | O_NOFOLLOW`. 5. Write to an exclusively created temporary file, flush and optionally `fsync()` it, and then atomically rename it when complete. 6. Add a defined retention policy and cleanup command rather than relying solely on operating-system cleanup. 7. Avoid embedding predictable timestamps as the only uniqueness source. A suitable pattern is: ```python import os import tempfile PRIVATE_TEMP_DIR = pathlib.Path(tempfile.gettempdir()) / f"agentsource-{os.getuid()}" PRIVATE_TEMP_DIR.mkdir(mode=0o700, parents=True, exist_ok=True) PRIVATE_TEMP_DIR.chmod(0o700) fd, name = tempfile.mkstemp( prefix=f"agentsource_{command}_", suffix=".json", dir=PRIVATE_TEMP_DIR, text=True, ) try: os.fchmod(fd, 0o600) with os.fdopen(fd, "w", encoding="utf-8") as output: json.dump(data, output, indent=2, default=str) finally: pass ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
setup.sh:81
Finding
API Key Is Echoed During Setup and Printed to Terminal Output<![CDATA[ ## Vulnerability Details **File Location**: `setup.sh`, lines 81–89 **Vulnerability Type**: Plaintext credential exposure through interactive input and terminal output **Risk Level**: Medium ### Vulnerable Code ```bash 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'" ``` ### Technical Analysis The setup script reads the API key with ordinary `read`, without the `-s` option. Consequently, the terminal displays the credential while the user types it. After storing the key, the script prints the complete secret again as part of an example environment-variable command. This duplicates the credential into terminal output and may expose it through: - Terminal scrollback. - Shell or terminal session recording. - CI or remote-session logs. - Screen sharing. - Shoulder surfing. - Clipboard or terminal-history tooling. Although the resulting configuration file is changed to mode `0600`, that protection does not address disclosure during entry or subsequent printing. The documented alternative, `config --api-key <key>`, also places the key in a command-line argument, which can remain in shell history and may be temporarily visible in process listings. The API key is legitimately required for the Skill's remote API functionality, but displaying or passing it in observable channels exceeds the minimum handling necessary. ### Attack Path 1. A user runs `setup.sh` in an observed, recorded, shared, or remotely managed terminal. 2. The user enters the Explorium API key at the prompt. 3. Because silent input is not enabled, the secret appears on screen as it is typed. 4. The s ...[truncated 782 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Read the key silently: ```bash read -r -s -p "Enter your Explorium API key (or press Enter to skip): " api_key printf '\n' ``` 2. Never interpolate the API key into informational terminal output. Replace the printed command with a generic placeholder: ```bash echo "To use an environment variable, add EXPLORIUM_API_KEY to your shell configuration securely." ``` 3. Avoid accepting secrets through command-line arguments. Add a `--api-key-stdin` option or securely prompt with Python's `getpass.getpass()`. 4. Warn users not to place the literal secret in shell history or shell configuration unless they understand the local exposure implications. 5. Generate the JSON configuration with a JSON serializer rather than direct string interpolation, ensuring quotes and backslashes in a key cannot corrupt the configuration. 6. Retain mode `0600` for the configuration file and create it atomically with restrictive permissions from the outset, rather than setting permissions only after writing. 7. Clear the shell variable after configuration where practical: ```bash unset api_key ``` ]]>
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 (19)

Session Persistence

Medium
Category
Rogue Agent
Content
**Option A — Environment variable** (recommended for persistent shell setups):
```bash
export EXPLORIUM_API_KEY=your_api_key_here
# Add to ~/.zshrc or ~/.bashrc to persist across sessions
```

**Option B — CLI config command** (saves to `~/.agentsource/config.json`, mode 600):
Confidence
90% 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.

Session Persistence

Medium
Category
Rogue Agent
Content
**Option A — Environment variable** (recommended for persistent shell setups):
```bash
export EXPLORIUM_API_KEY=your_api_key_here
# Add to ~/.zshrc or ~/.bashrc to persist across sessions
```

**Option B — CLI config command** (saves to `~/.agentsource/config.json`, mode 600):
Confidence
90% 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.

Session Persistence

Medium
Category
Rogue Agent
Content
## CLI Reference

All commands write results to `/tmp/agentsource_<timestamp>_<command>.json` and print only the file path to stdout.

### API Key Config
```bash
Confidence
89% confidence
Finding
The README states that all command results are written to predictable files under `/tmp`, which may contain fetched business/contact data and enrichment outputs. Temporary directories are often broadly accessible depending on system configuration, and storing potentially sensitive lead/contact datasets there creates a risk of local data exposure, accidental reuse, or recovery by other processes/users.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill performs privileged actions including shell execution, file reads/writes, environment-variable access, and network calls, but it does not declare an explicit tool scope such as allowed-tools or permissions. This creates an overbroad execution surface where an agent may invoke sensitive capabilities without a clear least-privilege boundary, increasing the chance of misuse or accidental data exposure.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The trigger list is extremely broad and includes common business phrases like market research, export to CSV, tech stack, and target list, which could cause the skill to activate in routine conversations where the user did not intend external lead-search behavior. Because this skill can access credentials, query a remote API, and write files, over-triggering increases the risk of unintended data transmission and tool execution.

Intent-Code Divergence

Medium
Confidence
91% confidence
Finding
The module docstring says results are written to temp files so large payloads never enter the conversation context window. However, the from-csv command reads the entire source CSV and writes all rows into the JSON temp file under data, which contradicts the stated intent of keeping large payloads out of conversational handling and instead creates another large payload file for later use.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The tool writes fetched prospect and business data to predictable files under `/tmp` using default permissions and without securely creating the files. On multi-user systems, temp directories can expose sensitive B2B contact data through permissive file modes, race/symlink attacks, or residual files left behind after execution.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The to-csv command writes flattened entity data to a user-specified output path, which can permanently persist prospect or business data outside the temp area. The code performs the write directly and neither prompts nor emits any user-facing warning about exporting potentially sensitive data to disk.

External Transmission

Medium
Category
Data Exfiltration
Content
#   ~/.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"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
#   ~/.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"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
#   ~/.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"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
#   ~/.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"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
#   ~/.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"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
#   ~/.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"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Session Persistence

Medium
Category
Rogue Agent
Content
echo "[OK] Python $PYTHON_VERSION"

# ---------------------------------------------------------------------------
# 2. Create directory structure
# ---------------------------------------------------------------------------
mkdir -p "$BIN_DIR"
echo "[OK] Created $BIN_DIR"
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
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
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
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
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Context-Inappropriate Capability

Medium
Confidence
99% confidence
Finding
The script prints the user-supplied API key back to the terminal inside an export command. This can expose the secret via shoulder-surfing, terminal scrollback, screen recordings, CI/session logging, or copied shell history if the user follows the printed instruction verbatim.

Missing User Warnings

Medium
Confidence
99% confidence
Finding
Echoing the entered API key into a shell command leaks a sensitive credential to the terminal output and encourages unsafe handling. If a user copies that command into their shell profile or terminal, the secret may also end up in shell history, backups, support logs, or shared recordings.

Static analysis

No suspicious patterns detected.