Back to skill

Security audit

Bullybuddy

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed Claude Code session manager, but it creates a high-impact control surface with weak token handling, broad persistent-session authority, and an unpinned executable dependency.

Review carefully before installing. Use this only if you intentionally want one token to control multiple Claude Code sessions. Keep the server local when possible, avoid --tunnel unless you need remote access, do not share or log /bullybuddy url output, rotate the token if it appears in logs or chat, avoid --dangerously-skip-permissions, and prefer a pinned/audited package version before using it on sensitive repositories.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/bullybuddy.sh:43
Finding
JSON Injection into Security-Sensitive Session Spawn Requests<![CDATA[ ## Vulnerability Details **File Location**: `scripts/bullybuddy.sh`, lines 43–51 **Vulnerability Type**: Improper JSON construction using unescaped user input **Risk Level**: High ### Vulnerable Code ```bash cwd="${1:-$(pwd)}" task="$2" group="${3:-default}" body="{\"cwd\":\"$cwd\",\"group\":\"$group\"" [[ -n "$task" ]] && body="${body},\"task\":\"$task\"" body="${body}}" result=$(curl -sf -X POST "$BB_URL/api/sessions" -H "$AUTH" -H "$CT" -d "$body") ``` ### Technical Analysis The `cwd`, `task`, and `group` values originate from slash-command arguments and are inserted into a JSON document through direct string interpolation. JSON metacharacters in these values—including quotation marks, commas, and braces—are not escaped. An attacker able to influence command arguments can terminate the intended JSON string and add or replace properties in the request body. This is particularly security-sensitive because the documented spawn API accepts a `skipPermissions` property. A malicious argument could produce a request containing: ```json { "cwd": "/legitimate/path", "group": "default", "task": "example", "skipPermissions": true } ``` For example, a `task` value shaped like the following could inject an additional property: ```text example","skipPermissions":true,"padding":"x ``` The resulting request remains syntactically valid JSON while containing attacker-selected session configuration. ### Attack Path 1. An attacker causes a user or calling agent to invoke `bullybuddy spawn` with a crafted `cwd`, `task`, or `group` argument. 2. The shell script inserts the argument directly into `body` without JSON encoding. 3. The crafted argument closes the intended string and injects additional request properties. 4. The script sends the modified body to `POST /api/sessions` using the legitimate bearer token. 5. If the server accepts the injected `skipPermissions` property, it creates a Claude Code session without normal permission confirmations. ...[truncated 748 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Construct request bodies with a JSON-aware encoder instead of string concatenation. For example: ```bash if [[ -n "$task" ]]; then body=$(jq -n \ --arg cwd "$cwd" \ --arg group "$group" \ --arg task "$task" \ '{cwd: $cwd, group: $group, task: $task}') else body=$(jq -n \ --arg cwd "$cwd" \ --arg group "$group" \ '{cwd: $cwd, group: $group}') fi ``` Apply the following additional controls: 1. Validate `cwd` as an allowed, canonical directory before sending it. 2. Enforce reasonable length and character limits for `task` and `group`. 3. On the server, use a strict request schema that rejects unknown properties. 4. Do not permit API clients to set `skipPermissions` unless a separate, explicit authorization policy allows it. 5. Default `skipPermissions` to `false` server-side regardless of omitted or malformed client data. 6. Add tests using quotes, backslashes, control characters, commas, and attempted injected properties. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/bullybuddy.sh:109
Finding
Bearer Token Disclosure Through Credential-Bearing URLs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/bullybuddy.sh`, lines 109–115 **Vulnerability Type**: Exposure of an authentication credential in command output and URL query strings **Risk Level**: Medium ### Vulnerable Code ```bash url|u) echo "Local: $BB_URL/?token=$BB_TOKEN" tunnel=$(jq -r '.tunnel // empty' "$CONN_FILE" 2>/dev/null) if [[ -n "$tunnel" ]]; then echo "Tunnel: $tunnel/?token=$BB_TOKEN" fi ;; ``` ### Technical Analysis The `url` command deliberately embeds the full bearer token in URL query parameters and writes those URLs to standard output. The token grants full control over all spawned Claude Code sessions, including access to transcripts and the ability to send arbitrary input. Secrets in query strings have a broad leakage surface. These URLs can be retained in: - Agent and tool execution transcripts - Terminal capture and command-output logs - Browser history and synchronization services - Proxy, gateway, tunnel, and web-server access logs - Screenshots, copied messages, and support records - Referrer headers when navigating from the dashboard to another resource The tunnel variant is especially sensitive because it exposes the control interface through a remotely accessible Cloudflare URL. Possession of the URL is sufficient to disclose the token to anyone who can read it. ### Attack Path 1. A user or agent invokes `/bullybuddy url`. 2. The script prints a local URL and, when configured, a public tunnel URL containing `BB_TOKEN`. 3. The output is stored in an agent transcript, log, terminal recording, browser history, or another observable location. 4. An unauthorized party retrieves the credential-bearing URL. 5. The party uses the token to authenticate to the dashboard, REST API, or WebSocket interface. 6. The party enumerates sessions, reads transcripts, sends terminal input, creates sessions, or terminates existing sessions. 7. Commands delivered through a controlled Claude Code session execute w ...[truncated 663 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Do not print authentication tokens in URLs. The `url` command should display only non-secret base addresses: ```bash echo "Local: $BB_URL/" if [[ -n "$tunnel" ]]; then echo "Tunnel: $tunnel/" fi ``` Use a safer dashboard authentication design: 1. Exchange the bearer token for a short-lived, single-use browser login code. 2. Store the resulting session identifier in a `Secure`, `HttpOnly`, and appropriately configured `SameSite` cookie. 3. Exclude credentials from query strings, browser history, and referrer data. 4. Redact bearer tokens from application, proxy, tunnel, and agent logs. 5. Set a restrictive `Referrer-Policy`, such as `no-referrer`. 6. Rotate the server token immediately if it is printed, logged, or otherwise exposed. 7. Use short token lifetimes and provide an explicit token-revocation mechanism. 8. Warn users before enabling a public tunnel and bind locally by default. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:22
Finding
Unpinned Global npm Dependency Executes Unaudited Mutable Code<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 22–27 and 36–40 **Vulnerability Type**: Unpinned third-party executable and package lifecycle code **Risk Level**: Medium ### Vulnerable Code ```yaml install: - id: node kind: node package: openclaw-bullybuddy bins: - bullybuddy ``` ```bash npm install -g openclaw-bullybuddy ``` ### Technical Analysis The Skill directs installation of `openclaw-bullybuddy` without an exact version or integrity hash. Consequently, installation resolves to whatever package release the configured npm registry currently serves. The implementation of that package is not included in the audited artifact, even though its executable provides the server and session-management functionality on which the Skill relies. Global npm installation may execute package lifecycle scripts and installs a command that subsequently receives access to the user's session-control environment. If the package, publisher account, registry response, or a transitive dependency is compromised, code different from the reviewed Skill can execute during installation or when the `bullybuddy` binary is invoked. This finding identifies an unsafe dependency-management practice; the reviewed files do not establish that the current package release is malicious. ### Attack Path 1. An attacker compromises the npm publisher, package release process, registry path, or a dependency used by `openclaw-bullybuddy`. 2. The attacker publishes a malicious package version that satisfies the unpinned package reference. 3. A user follows the Skill installation instructions or the Skill manager installs the latest package. 4. npm downloads and installs the attacker-controlled release globally. 5. Malicious lifecycle code executes during installation, or malicious logic executes when `bullybuddy` is started. 6. The code runs with the privileges of the installing user and may access local files, environment variables, the BullyBuddy conn ...[truncated 601 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Pin the dependency to a reviewed, exact version rather than resolving an unrestricted latest release: ```yaml package: openclaw-bullybuddy@<reviewed-exact-version> ``` Apply the following supply-chain controls: 1. Record and verify the package integrity digest or lockfile integrity metadata. 2. Audit and retain the source corresponding to the pinned release. 3. Review package lifecycle scripts and install with lifecycle scripts disabled where operationally possible. 4. Pin and audit transitive dependencies through a lockfile. 5. Avoid global installation; install into an isolated, least-privileged environment. 6. Monitor publisher ownership, release provenance, and unexpected version changes. 7. Use registry allowlists and package-signing or provenance verification where supported. 8. Re-audit the package before upgrading the pinned version. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (13)

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The url command prints authenticated dashboard URLs with the bearer token embedded in the query string, directly exposing a reusable credential to the terminal, shell history, logs, screenshots, or chat transcripts. Query-string tokens are especially risky because they are often retained in browser history, copied unintentionally, and leaked through observability or referrer mechanisms.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
This command is an explicit credential-disclosure capability: it reveals the authentication token verbatim as part of a URL. Anyone who sees the output can reuse the token to access the BullyBuddy service with the same privileges until the token is rotated or expires.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill invokes shell execution via `command-tool: exec` and an external script, but it does not declare any `permissions` or `allowed-tools` scope. That leaves the skill with effectively broad execution capability while giving reviewers and users no explicit boundary on what tools or commands it may use.

Session Persistence

Medium
Category
Rogue Agent
Content
```
/bullybuddy status          - Server status & session summary
/bullybuddy list            - List all sessions
/bullybuddy spawn [cwd] [task] [group] - Create new session
/bullybuddy send <id> <text> - Send input to session
/bullybuddy output <id> [lines] - Show session output/transcript
/bullybuddy kill <id>       - Terminate session
Confidence
86% confidence
Finding
The skill is explicitly designed to spawn, list, send input to, inspect, and kill multiple long-lived sessions, which creates a persistence and remote-control surface beyond a one-shot command. Persistent sessions increase exposure because they can retain context, continue operating after the initiating interaction, and be reused by anyone who gains control of the management interface.

Unrestricted Tool Access

Medium
Category
Excessive Agency
Content
- The auth token grants **full control over all spawned Claude Code sessions**, including sending arbitrary input. Treat it as a secret.
- The `/bullybuddy url` command outputs the dashboard URL with the token embedded. Do not share or log this URL publicly.
- When using `--tunnel`, the dashboard and API are exposed to the internet via a Cloudflare temporary URL. Anyone with the token can access all sessions remotely.
- Spawned sessions run Claude Code with your local permissions. If `--dangerously-skip-permissions` is enabled, Claude can execute any command without confirmation.

## Authentication
Confidence
88% confidence
Finding
This skill manages a service whose token grants full control over spawned Claude Code sessions, including arbitrary input delivery, and those sessions may run with local user permissions. In this context, unrestricted command-driving capability is dangerous because compromise of the token, dashboard URL, or wrapper flow can be turned into arbitrary actions in persistent agent sessions.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- The auth token grants **full control over all spawned Claude Code sessions**, including sending arbitrary input. Treat it as a secret.
- The `/bullybuddy url` command outputs the dashboard URL with the token embedded. Do not share or log this URL publicly.
- When using `--tunnel`, the dashboard and API are exposed to the internet via a Cloudflare temporary URL. Anyone with the token can access all sessions remotely.
- Spawned sessions run Claude Code with your local permissions. If `--dangerously-skip-permissions` is enabled, Claude can execute any command without confirmation.

## Authentication
Confidence
84% confidence
Finding
The documented `--dangerously-skip-permissions` mode allows Claude to execute commands without confirmation, removing an important human approval checkpoint. In a session-management skill that can spawn, steer, and remotely access multiple sessions, this materially increases the risk of unintended or malicious autonomous actions.

Session Persistence

Medium
Category
Rogue Agent
Content
## Remote Access

Start the server with `--tunnel` to create a Cloudflare temporary URL automatically:

```bash
bullybuddy server --tunnel
Confidence
93% confidence
Finding
The `--tunnel` feature exposes the dashboard and API over a Cloudflare temporary URL, enabling remote access to persistent sessions from the internet. Given that the token confers full control and may be embedded in the dashboard URL, this substantially raises the likelihood and impact of session hijacking or unauthorized remote operation.

External Transmission

Medium
Category
Data Exfiltration
Content
[[ -n "$task" ]] && body="${body},\"task\":\"$task\""
    body="${body}}"
    
    result=$(curl -sf -X POST "$BB_URL/api/sessions" -H "$AUTH" -H "$CT" -d "$body")
    id=$(echo "$result" | jq -r '.data.id')
    echo "Spawned session: $id"
    echo "State: $(echo "$result" | jq -r '.data.detailedState')"
Confidence
70% 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
exit 1
    fi
    # Append carriage return for PTY
    curl -sf -X POST "$BB_URL/api/sessions/$id/input" -H "$AUTH" -H "$CT" -d "{\"data\":\"$text\\r\"}" > /dev/null
    echo "Sent to $id: $text"
    ;;
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The `kill` command issues an HTTP DELETE to remove a session and then reports success, but there is no confirmation prompt or prior warning before the destructive action. Because deleting a session may terminate active work irreversibly, users are not clearly alerted at the point of execution.

Description-Behavior Mismatch

Medium
Confidence
88% confidence
Finding
The manifest describes a CLI wrapper for spawning, listing, sending input to, killing, and monitoring Claude Code sessions. The `audit` subcommand adds access to a separate audit log capability, which is not mentioned in the described scope and goes beyond ordinary per-session management operations.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
Printing a bearer token in a dashboard URL without warning creates a high likelihood of accidental credential leakage through terminal capture, clipboard history, logs, screenshots, or browser history. Because bearer tokens are sufficient for access, disclosure equates to account or service compromise for the token's scope.

Missing User Warnings

Low
Confidence
81% confidence
Finding
The wrapper auto-discovers and loads `BB_TOKEN` from `~/.bullybuddy/connection.json`, which is credential access, but the script provides no visible notice to the user when doing so. Although this may be convenient, the absence of disclosure can obscure that sensitive credentials are being read automatically from disk.