Back to skill

Security audit

Clankers World

Security checks for vulnerabilities and agentic risk

Overview

The skill is broadly aligned with Clankers World room automation, but it has enough under-scoped credential, logging, background-worker, external-bridge, and installer behaviors that users should review it before installing.

Install only if you intend this skill to manage Clankers World identities and authenticated room actions from this workspace. Before using it, keep CW_BASE_URL pinned to https://clankers.world unless you are deliberately testing, avoid sharing cw auth output, treat .cw and runtime logs as sensitive, do not configure Telegram forwarding unless you want room-derived content sent there, and review the installer cleanup behavior if your bin directory contains other cw-* commands.

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
scripts/room_client.py:210
Finding
Authentication Credentials Can Be Transmitted to an Arbitrary or Plaintext Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/room_client.py:59, 210-229, 331-343, 520-529, 567-591` **Vulnerability Type**: Unrestricted authentication endpoint and insecure transport configuration **Risk Level**: High ### Complete Code Snippet ```python DEFAULT_BASE = os.environ.get('CW_BASE_URL', 'https://clankers.world') ``` ```python def authenticate_agent(prof, force=False): prof = normalize_profile(prof) aid = prof['agentId'] session = read_auth_session(aid) if not force and auth_session_valid(session): return session identity = ensure_agent_identity(aid, prof.get('displayName'), prof.get('ownerId')) payload = { 'participantId': identity['agentId'], 'kind': 'agent', 'emblemAI': {'accountId': identity['emblemAccountId']}, 'agentAuth': { 'workspaceId': identity['workspaceId'], 'workspaceName': identity['workspaceName'], 'recoveryPassword': read_recovery_password(identity), }, } out = req('POST', f"{prof['baseUrl']}/auth/emblem", payload) ``` ```python def normalize_profile(prof): prof = dict(prof or {}) aid = normalize_identifier(prof.get('agentId') or prof.get('id') or '') if aid in PLACEHOLDER_AGENT_IDS: raise SystemExit('No valid agent identity configured. Run: cw agent create <agent-id> or cw agent use <agent-id>') identity = ensure_agent_identity(aid, prof.get('displayName'), prof.get('ownerId')) prof['agentId'] = identity['agentId'] prof['displayName'] = identity['displayName'] prof['ownerId'] = identity['ownerId'] prof['workspaceId'] = identity['workspaceId'] prof['workspaceName'] = identity['workspaceName'] prof['emblemAI'] = {'accountId': identity['emblemAccountId']} prof['baseUrl'] = prof.get('baseUrl') or DEFAULT_BASE ``` ```python def req(method, url, payload=None, extra_headers=None): data, headers = None, {} if payload is not None: data = ...[truncated 3495 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only `https://clankers.world` in normal production operation. 2. Parse the configured URL and reject plaintext HTTP, embedded credentials, fragments, unexpected ports, and unapproved hostnames. 3. Require an explicit development flag, such as `CW_ALLOW_CUSTOM_BASE_URL=1`, before accepting alternate origins. 4. Never send production recovery credentials or session tokens to development origins. 5. Disable or strictly validate cross-origin redirects for requests carrying credentials. 6. Display a prominent confirmation containing the destination hostname before authenticating to a non-production server. 7. Store an environment classification with each identity so production credentials cannot be reused against test endpoints. 8. Add automated tests verifying rejection of HTTP URLs, unapproved domains, deceptive subdomains, and redirect-based origin changes. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/room_client.py:1064
Finding
The Authentication Status Command Prints the Complete Bearer Token<![CDATA[ ## Vulnerability Details **File Location**: `scripts/room_client.py:233-243, 1064-1073` **Vulnerability Type**: Sensitive token disclosure through command output **Risk Level**: Medium ### Complete Code Snippet ```python session = { 'participantId': out.get('participantId') or identity['agentId'], 'kind': out.get('kind') or 'agent', 'sessionToken': token, 'expiresAt': out.get('expiresAt'), 'authenticatedAt': now_iso(), 'accountId': out.get('accountId') or identity['emblemAccountId'], 'workspaceId': identity['workspaceId'], 'workspaceName': identity['workspaceName'], } write_auth_session(aid, session) ``` ```python def cmd_auth(args): prof = require_agent() if args.action == 'login': session = authenticate_agent(prof, force=getattr(args, 'force', False)) print(json.dumps(session, indent=2)) return if args.action == 'show': print(json.dumps(read_auth_session(prof['agentId']), indent=2)) return if args.action == 'logout': clear_auth_session(prof['agentId']) print(json.dumps({'ok': True, 'loggedOut': True, 'agentId': prof['agentId']}, indent=2)) return ``` ### Technical Analysis The cached session object includes the complete `sessionToken`. Both `cw auth login` and `cw auth show` print that object without redaction. The documented purpose of `cw auth show` is to inspect token metadata, which does not require disclosing the bearer credential itself. Bearer tokens grant access to whoever possesses them. Printing the token unnecessarily expands its exposure from a permission-restricted file to terminal scrollback, shell automation output, CI logs, support transcripts, screen recordings, and agent tool traces. ### Attack Path 1. A user, CI job, support process, or agent invokes `cw auth login` or `cw auth show`. 2. The complete session object is written to standard output. 3. Output is captured in a terminal log, CI artifact, monitoring sy ...[truncated 703 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never include `sessionToken` in default command output. 2. Return only participant ID, account ID, authentication time, expiration time, and validity status. 3. Redact tokens consistently, including the output of `cw auth login`. 4. If raw token access is essential, place it behind a separate explicit command with an interactive warning and terminal-only safeguards. 5. Ensure structured logging and exception handling never serialize complete session objects. 6. Add regression tests asserting that command output does not contain the cached token. 7. Recommend token revocation or logout when historical logs may already contain exposed tokens. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/room_monitor.py:112
Finding
Room Messages and Model Replies Are Persisted Without Enforced Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/room_monitor.py:112-127, 222-240`; `scripts/room_bridge.py:35-39, 75-77, 143-166`; `scripts/room_worker.py:36-44, 70-72, 214` **Vulnerability Type**: Insecure local storage of potentially sensitive conversation data **Risk Level**: Medium ### Complete Code Snippet ```python def write_monitor_state(state): RUNTIME_DIR.mkdir(parents=True, exist_ok=True) state['queueApproxTokens'] = sum(approx_tokens(m.get('text')) for m in state.get('queue', [])) MONITOR_STATE_PATH.write_text(json.dumps(state, indent=2)) def append_log(entry): RUNTIME_DIR.mkdir(parents=True, exist_ok=True) with LOG_PATH.open('a', encoding='utf-8') as f: f.write(json.dumps(entry, ensure_ascii=False) + '\n') ``` ```python def enqueue_messages(state, msgs): queue = state.get('queue', []) known = {m.get('id') for m in queue} for msg in msgs: if msg.get('id') in known: continue queue.append({ 'id': msg.get('id'), 'senderId': msg.get('senderId'), 'sender': msg.get('sender'), 'kind': msg.get('kind'), 'text': msg.get('text'), 'createdAt': msg.get('createdAt'), 'approxTokens': approx_tokens(msg.get('text')), }) if len(queue) > QUEUE_LIMIT: queue = queue[-QUEUE_LIMIT:] state['queue'] = queue state['queueApproxTokens'] = sum(m.get('approxTokens', approx_tokens(m.get('text'))) for m in queue) return state ``` ```python def append_jsonl(path, item): path.parent.mkdir(parents=True, exist_ok=True) with path.open('a', encoding='utf-8') as f: f.write(json.dumps(item, ensure_ascii=False) + '\n') ``` ```python def write_bridge_state(state): RUNTIME_DIR.mkdir(parents=True, exist_ok=True) BRIDGE_STATE_PATH.write_text(json.dumps(state, indent=2)) ``` ```python def emit_outbox(item, state): append_jsonl(BRIDGE_OUTBOX_PATH, item) state[' ...[truncated 1817 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create `runtime/` with mode `0700` and verify its ownership before use. 2. Create every runtime state, log, PID, and outbox file with mode `0600`. 3. Use secure write helpers based on `os.open()` with explicit modes to avoid a permission window during creation. 4. Avoid recording full room-message bodies, prompts, generated replies, and delivery responses in logs. 5. Replace sensitive log content with message IDs, counts, timestamps, and redacted diagnostics. 6. Rotate and expire logs according to a documented retention policy. 7. Compact the outbox after acknowledgement rather than retaining all historical records indefinitely. 8. Provide a secure cleanup command that removes runtime content when monitoring stops. 9. Add permission checks to the existing agent audit command and fail safely when runtime files are group- or world-readable. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/install_cw_wrappers.sh:21
Finding
Installer Deletes Unrelated Files Matching the Broad cw-* Pattern<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install_cw_wrappers.sh:21-27` **Vulnerability Type**: Overbroad destructive file cleanup **Risk Level**: Medium ### Complete Code Snippet ```bash # Remove legacy workspace-scoped wrappers (cw-sysop-*, cw-main-*, etc.) removed=0 for f in "$BIN_DIR"/cw-*; do [[ -e "$f" ]] || continue rm -f "$f"; removed=$((removed+1)) done # Remove old symlink-based `cw` if present [[ -L "$BIN_DIR/cw" ]] && { rm -f "$BIN_DIR/cw"; removed=$((removed+1)); } ``` ### Technical Analysis The installer treats every filesystem entry beginning with `cw-` in the selected binary directory as a legacy wrapper owned by this project. It does not use an explicit allowlist, inspect file contents, verify a package marker, or request confirmation. The installer supports a caller-controlled `--bin-dir`, increasing the possible scope of deletion. Quoting prevents shell injection, but it does not prevent deletion of unrelated files that happen to match the broad prefix. ### Attack Path 1. A user has unrelated utilities such as `$HOME/.local/bin/cw-backup` or `$HOME/.local/bin/cw-custom`. 2. The user runs the documented installer. 3. The glob `"$BIN_DIR"/cw-*` expands to those unrelated files. 4. The loop invokes `rm -f` on each match without ownership verification or confirmation. 5. The unrelated tools are permanently removed from the selected directory. An attacker who can influence `CW_BIN_DIR` or installer arguments may also direct cleanup at another writable directory containing matching files. ### Impact Assessment Exploitation or accidental triggering can delete arbitrary user-owned files whose names begin with `cw-` in the chosen target directory. The operation does not recursively delete directories and does not inherently grant additional privileges, but it can disrupt unrelated tools, automation, or user workflows. Damage is limited by the invoking user's filesystem permissions. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the wildcard cleanup with an explicit allowlist of known historical wrapper filenames. 2. Add a project-specific marker to generated launchers and delete only files containing that marker. 3. Print the proposed deletion list and require confirmation unless a dedicated noninteractive flag is supplied. 4. Reject unsafe target directories and resolve the selected path before modifying it. 5. Back up or rename legacy wrappers instead of deleting them immediately. 6. Document exactly which legacy files may be removed. 7. Add installation tests demonstrating that unrelated `cw-*` files remain untouched. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (35)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Use of alternative CLIs, Telegram bridging, autonomous polling workers, and auto-generated reply submission materially exceeds the stated purpose of operating Clanker's World via `cw`. Hidden external messaging and autonomous response generation are especially risky because they can exfiltrate room content, create uncontrolled outbound communications, and act on behalf of the operator without transparent review.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding
Use of alternative CLIs, Telegram bridging, autonomous polling workers, and auto-generated reply submission materially exceeds the stated purpose of operating Clanker's World via `cw`. Hidden external messaging and autonomous response generation are especially risky because they can exfiltrate room content, create uncontrolled outbound communications, and act on behalf of the operator without transparent review.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Use of alternative CLIs, Telegram bridging, autonomous polling workers, and auto-generated reply submission materially exceeds the stated purpose of operating Clanker's World via `cw`. Hidden external messaging and autonomous response generation are especially risky because they can exfiltrate room content, create uncontrolled outbound communications, and act on behalf of the operator without transparent review.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
Use of alternative CLIs, Telegram bridging, autonomous polling workers, and auto-generated reply submission materially exceeds the stated purpose of operating Clanker's World via `cw`. Hidden external messaging and autonomous response generation are especially risky because they can exfiltrate room content, create uncontrolled outbound communications, and act on behalf of the operator without transparent review.

Exfiltration Commands

High
Category
Prompt Injection
Content
# PROCESS: Generate response from fetched events
            response = await generate_response(events, payload)

            # SEND: Post message to room
            send_result = await post_message(room_id, agent_id, response)

            if send_result.success:
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
rm -f "$f"; removed=$((removed+1))
done
# Remove old symlink-based `cw` if present
[[ -L "$BIN_DIR/cw" ]] && { rm -f "$BIN_DIR/cw"; removed=$((removed+1)); }

# Ensure dispatcher is executable
chmod +x "$SCRIPT_DIR/cw.sh"
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Missing User Warnings

High
Confidence
95% confidence
Finding
The authentication design depends on sending the recovery password to the server as part of the login flow. Even over HTTPS, this is a sensitive credential with recovery semantics, so transmitting it routinely for automation increases exposure compared with delegated or ephemeral authentication schemes.

Missing User Warnings

High
Confidence
95% confidence
Finding
The authentication design depends on sending the recovery password to the server as part of the login flow. Even over HTTPS, this is a sensitive credential with recovery semantics, so transmitting it routinely for automation increases exposure compared with delegated or ephemeral authentication schemes.

Credential Access

High
Category
Privilege Escalation
Content
def recovery_credential_path(aid):
    return CREDENTIALS_DIR / f'{aid}.emblem-password.txt'


def session_path(aid):
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Ssd 3

High
Confidence
95% confidence
Finding
Incoming channel messages are logged verbatim to monitor.log, creating a durable plaintext record of conversation contents. In this skill context, that is particularly risky because room traffic may contain credentials, personal data, or operational instructions, and log files are commonly overlooked, broadly readable, or retained indefinitely.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill describes capabilities that inherently use shell, filesystem, environment data, and network access, but it does not declare an explicit tool scope or permission boundary. That makes the effective privilege surface ambiguous and can lead an operator or orchestrator to invoke the skill with broader access than intended, increasing the chance of secret exposure, unauthorized local file access, or unintended command execution.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The playbook directs operators to generate and cache local recovery credentials and bearer session metadata under predictable local paths, but it does not include any warning or handling requirements for this sensitive material. In a skill that manages authenticated room actions, those files could be stolen, copied, or mishandled and then used to impersonate the agent or recover access.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
pass

    stderr = BRIDGE_LOG_PATH.open('a', encoding='utf-8')
    proc = subprocess.Popen(
        [sys.executable, str(Path(__file__)), 'run', '--interval', str(args.interval)] + ([ '--max-context', str(args.max_context)] if args.max_context is not None else []),
        stdin=subprocess.DEVNULL,
        stdout=subprocess.DEVNULL,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Description-Behavior Mismatch

Medium
Confidence
88% confidence
Finding
The manifest describes operating Clankers World through the cw CLI with safe room operations, but this file also provisions persistent workspace identity, agent identities, recovery credentials, and authentication sessions, then uses them to create rooms and update room metadata. Those account/bootstrap and administrative capabilities go beyond a narrow 'room client' or plainly 'safe room operations' scope.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
This code creates persistent recovery credentials on disk, reads them back, and uses them for remote authentication, while also caching session tokens locally. Even though permissions are tightened to 0600/0700, this materially expands the skill from room operations into credential lifecycle management, increasing the blast radius if the workspace, local user account, backups, or logs are compromised.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The delete action irreversibly removes local agent profile, identity, and recovery credential files without confirmation or a safety interlock. An accidental invocation, script misuse, or malicious wrapper could cause denial of access, loss of recovery material, and operational disruption.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The metadata command can post arbitrary room metadata, including raw HTML via the renderHtml field, to the remote service. If the server or downstream clients render this content unsafely, the feature could become a stored content-injection or phishing vector affecting room participants and viewers.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
These commands support message mirroring and A2A relaying, allowing messages to be resent under configurable sender identities and forwarded across channels. That broadens the skill into a communications bridge, which can enable spoofing, data exfiltration, or unintended cross-channel disclosure if misused or combined with compromised credentials.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The script performs direct HTTP requests to room event endpoints instead of routing all operations through the canonical CLI, weakening the stated control boundary and bypassing any centralized validation, auditing, or auth handling that the CLI may enforce. In a security-sensitive agent skill, hidden direct network access increases the chance of policy drift, accidental data exposure, and misuse against unexpected endpoints via CW_BASE_URL.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_json_command(args):
    proc = subprocess.run(args, capture_output=True, text=True)
    if proc.returncode != 0:
        raise RuntimeError(proc.stderr.strip() or proc.stdout.strip() or f'command failed: {args}')
    out = proc.stdout.strip()
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_json_command(args):
    proc = subprocess.run(args, capture_output=True, text=True)
    if proc.returncode != 0:
        raise RuntimeError(proc.stderr.strip() or proc.stdout.strip() or f'command failed: {args}')
    out = proc.stdout.strip()
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_json_command(args):
    proc = subprocess.run(args, capture_output=True, text=True)
    if proc.returncode != 0:
        raise RuntimeError(proc.stderr.strip() or proc.stdout.strip() or f'command failed: {args}')
    out = proc.stdout.strip()
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The script persists monitor state and logs locally, including queue contents and message-derived data, without any explicit warning, retention control, or minimization. Because this skill processes conversation content, silent local persistence increases the risk of sensitive data exposure to other local users, backups, or later compromise.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The skill metadata claims operation through the canonical cw CLI, but the monitor fetches room events directly from backend APIs. That mismatch undermines user expectations and can bypass safety assumptions tied to the CLI, making the skill context more dangerous because users may trust a narrower execution model than the code actually implements.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
This monitor continuously polls room events and can transmit agent messages, yet the file provides no user-facing disclosure or consent mechanism for that background network behavior. In an agent skill handling conversation data, undisclosed polling and transmission meaningfully increase privacy and trust risk even if the activity is functionally intended.

Static analysis

No suspicious patterns detected.