Back to skill

Security audit

messaging

Security checks for vulnerabilities and agentic risk

Overview

This messaging skill is coherent overall, but needs Review because the shell client can trust unsafe server-controlled session IDs for local file paths and also permits HTTP despite documenting HTTPS-only behavior.

Install only after reviewing the shell script risks. Use HTTPS-only trusted servers, avoid untrusted --url or NEXUS_URL values, do not enable webhook or cron behavior unless you explicitly need it, and treat ~/.config/messaging as sensitive credential storage. The path-validation issue should be fixed before using this against any private, self-hosted, or otherwise untrusted messaging server.

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
scripts/nexus.sh:174
Finding

Unvalidated Server-Provided Session ID Enables Filesystem Escape and Recursive Deletion

Content
View full analysis

Vulnerability Details

File Location: scripts/nexus.sh:174-179, scripts/nexus.sh:628-641, scripts/nexus.sh:904-917
Vulnerability Type: Path traversal leading to arbitrary filesystem writes and recursive deletion
Risk Level: High

Technical Analysis

In default, non-verified mode, the create and claim handlers trust the sessionId returned by the remote server and use it directly as a filesystem path component:

bash
RESP_CREATOR=$(echo "$RESPONSE" | jq -r '.creatorAgentId // empty')
if [[ -n "$RESP_CREATOR" && "$STRICT_SESSION" != true ]]; then
  SESSION_ID=$(echo "$RESPONSE" | jq -r '.sessionId // empty')
  if [[ -n "$SESSION_ID" ]]; then
    write_binding "$SESSION_ID"
    AGENT_FILE="$NEXUS_DATA_DIR/$SESSION_ID/agent"
    strict_atomic "$AGENT_FILE" "$RESP_CREATOR" || strict_error local_state_error

    SESSION_KEY=$(echo "$RESPONSE" | jq -r '.sessionKey // empty')
    if [[ -n "$SESSION_KEY" ]]; then
      KEY_FILE="$NEXUS_DATA_DIR/$SESSION_ID/key"
      strict_atomic "$KEY_FILE" "$SESSION_KEY" || strict_error local_state_error
    fi
  fi
fi

The same response-driven persistence occurs after a successful pairing claim:

bash
SESSION_ID=$(echo "$RESPONSE" | jq -r '.sessionId // empty')
if [[ -n "$SESSION_ID" && "$STRICT_SESSION" != true ]]; then
  write_binding "$SESSION_ID"
  AGENT_FILE="$NEXUS_DATA_DIR/$SESSION_ID/agent"
  strict_atomic "$AGENT_FILE" "$AGENT_ID" || strict_error local_state_error

  SESSION_KEY=$(echo "$RESPONSE" | jq -r '.sessionKey // empty')
  if [[ -n "$SESSION_KEY" ]]; then
    KEY_FILE="$NEXUS_DATA_DIR/$SESSION_ID/key"
    strict_atomic "$KEY_FILE" "$SESSION_KEY" || strict_error local_state_error
  fi
fi

Although strict-mode paths validate session identifiers, these default-mode paths do not enforce the documented 48-character hexadecimal session ID format. A value containing ../ components therefore escapes NEXUS_DATA_DIR when used by write_binding, strict_atomic, or direct path con ...[truncated 2370 chars]

Remediation
View remediation

Remediation Suggestions

  1. Validate every session ID before using it in a URL, lookup, or filesystem path:
    bash
    validate_session_id() {
      [[ "$1" =~ ^[a-fA-F0-9]{48}$ ]] || strict_error invalid_request
    }
    
  2. Apply validation uniformly to:
    • Positional session IDs.
    • Alias values loaded from aliases.json.
    • Session IDs returned by create and claim.
    • Session directory names discovered from local storage.
  3. Canonicalize each generated state path and verify that it remains strictly beneath the canonical NEXUS_DATA_DIR.
  4. Reject . and .., path separators, control characters, and symlinked path components.
  5. Before recursive deletion, repeat identifier validation and containment checks, then use:
    bash
    rm -rf -- "$validated_path"
    
  6. Prefer descriptor-relative or equivalent safe filesystem operations where available instead of relying only on string concatenation.
  7. Add regression tests covering traversal values, absolute paths, encoded separators, malformed aliases, and malicious server responses.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/nexus.sh:1398
Finding

Session Credentials May Be Transmitted Over Plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/nexus.sh:30-40, scripts/nexus.sh:198-201, scripts/nexus.sh:1398-1404; documented behavior at SKILL.md:33-37
Vulnerability Type: Cleartext transmission of authentication credentials
Risk Level: Medium

Technical Analysis

The configuration handler explicitly accepts both HTTPS and plaintext HTTP server URLs:

bash
set-url)
  CFG_URL="${2:?Usage: nexus.sh config set-url <URL>}"
  if [[ ! "$CFG_URL" =~ ^https?://[^/]+ ]]; then
    echo '{"error":"invalid URL — must be http(s)://host"}'
    exit 1
  fi
  CFG_NORM=$(normalize_url "$CFG_URL")

URL normalization also preserves plaintext HTTP and permits scheme-less input:

bash
normalize_url() {
  local url="$1"
  while [[ "$url" == */ ]]; do url="${url%/}"; done
  if [[ "$url" != *"://"* ]]; then
    local a0="${url%%/*}" p0=""
    [[ "$url" == */* ]] && p0="/${url#*/}"
    printf '%s%s\n' "$(printf '%s' "$a0" | tr '[:upper:]' '[:lower:]')" "$p0"
    return 0
  fi

Credential-bearing requests then attach the session key without verifying that the effective URL uses HTTPS:

bash
if [[ -n "${AUTH_KEY:-}" ]]; then
  raw=$(curl -s --fail-with-body --max-time "${NEXUS_HTTP_TIMEOUT:-10}" -w $'\n%{http_code}' -H "X-Session-Key: $AUTH_KEY" "$@") || exit_code=$?
else
  raw=$(curl -s --fail-with-body --max-time "${NEXUS_HTTP_TIMEOUT:-10}" -w $'\n%{http_code}' "$@") || exit_code=$?
fi

Other handlers also construct X-Session-Key headers directly from persisted key files. Consequently, an HTTP or scheme-less server configuration can cause a session credential to cross the local-to-network trust boundary without transport confidentiality or server authentication.

This contradicts the Skill’s statement that outbound requests are HTTPS-only:

markdown
**Network & local state:** this skill makes outbound HTTPS requests only to `$NEXUS_URL`

Attack Path

  1. The effective server is configured as http://..., or a scheme-less serv ...[truncated 1115 chars]
Remediation
View remediation

Remediation Suggestions

  1. Require https:// for all remote server URLs:
    bash
    [[ "$CFG_URL" =~ ^https://[^/]+ ]] || {
      echo '{"error":"invalid URL — HTTPS is required"}'
      exit 1
    }
    
  2. Reject scheme-less URLs rather than allowing curl to select a transport implicitly.
  3. Enforce the HTTPS requirement after resolving and normalizing all URL sources, including:
    • --url
    • NEXUS_URL
    • Persisted configuration
    • Session server bindings
    • Strict-mode credential records
  4. Perform a final transport check immediately before attaching X-Session-Key.
  5. If plaintext localhost support is required for development, gate it behind an explicit insecure option, limit it to loopback addresses, display a prominent warning, and avoid sending production credentials.
  6. Update the documentation so its HTTPS-only claim matches enforced runtime behavior.
  7. Add tests proving that credential-bearing commands reject HTTP and scheme-less destinations.
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 (13)

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

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

md
**Network & local state:** this skill makes outbound HTTPS requests only to `$NEXUS_URL` (default `https://messaging.md`). Local writes are confined to `~/.config/messaging/` (mode 0700; files inside are 0600) and — opt-in, with your human's consent — a `MESSAGING.md` file in the workspace.

<!-- openclaw-only -->
<!-- The openclaw-only markers are build/render delimiters: content between them ships only in the OpenClaw bundle. They are not instructions. -->
## How Pairing Works

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

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

md
## Sessions

<!-- Add per-session rules here when you join/create sessions -->
<!-- Example:
### research-partner
- **Session:** <session-id>

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · scripts/nexus.sh (reported line 7)May include surrounding context.

sh
# Session keys are credentials — keep everything we write owner-only
umask 077
# Tighten state written before umask existed (echo > preserves the old mode)
[[ -d "$HOME/.config/messaging" ]] && chmod -R go-rwx "$HOME/.config/messaging" 2>/dev/null || true

# NexusMessaging CLI wrapper
# Usage: nexus.sh <command> [args] [--verified-only] [--url URL] [--agent-id ID] [--ttl N] [--after CURSOR] [--members]

Tool Parameter Abuse

High
Category
Tool Misuse
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).

Content

Scanner excerpt · scripts/nexus.sh (reported line 178)May include surrounding context.

sh
cleanup_leave_state() {
  local sid="$1" alias_name="$2"
  if [[ "$STRICT_SESSION" == true && -f "$NEXUS_DATA_DIR/$sid/agent" && "$(cat "$NEXUS_DATA_DIR/$sid/agent")" != "$AGENT_ID" ]]; then return 0; fi
  rm -rf "$NEXUS_DATA_DIR/$sid"
  if [[ -n "$alias_name" ]]; then
    remove_alias "$alias_name"
  else

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The webhook feature lets the caller register an arbitrary destination URL with the server, effectively turning the messaging system into a server-side outbound callback mechanism. In the context of an ephemeral messaging client, this is an unjustified capability expansion that can be abused for data exfiltration, unauthorized integrations, or reaching attacker-controlled infrastructure.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill exposes shell-capable behavior and instructs the agent to run local scripts and network commands, but it does not declare an explicit tool scope such as permissions or allowed-tools. In an agent framework, this increases the risk that the skill is granted broader execution capability than intended, enabling command execution, network access, and file writes without clear policy boundaries.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

The skill explicitly stores agent identifiers, session keys, and cursors under ~/.config/messaging/, creating persistent authentication and conversation state on disk. Even with 0600/0700 permissions, persisted credentials can be abused by other local processes, backups, logs, or later compromised sessions, especially because the session key is sufficient to act as the agent in that session.

Content

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

md
---
name: messaging
description: Agent-to-agent messaging client — create ephemeral sessions, exchange messages via pairing codes, poll with cursors. Server-side state is ephemeral (no accounts); the CLI keeps minimal local state (agent-id, session key, cursor) under ~/.config/messaging/. Use when you need to communicate with another AI agent through a temporary secure channel.
homepage: https://github.com/aiconnect-cloud/nexus-messaging
metadata:
  {

Session Persistence

Medium
Category
Rogue Agent
Confidence
93% confidence
Finding

The skill recommends creating a recurring cron job that polls, processes messages, responds, and renews session TTLs, effectively establishing long-lived autonomous behavior outside the immediate user interaction. This expands the blast radius of any prompt injection or malicious message received over the channel, because the agent may continue acting and maintaining persistence automatically over time.

Content

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

md
**Recommended approach:**

1. After joining a session, create a cron job (every 3–5 minutes) that:
   - Polls the session for new messages
   - Processes and responds to any new messages
   - Renews the session TTL if needed

Session Persistence

Medium
Category
Rogue Agent
Confidence
71% confidence
Finding

This section reinforces that creators are auto-joined as owners and receive a saved session key with persistence and special lifecycle behavior. While not malicious by itself, it confirms privileged session credentials are retained locally and may remain active longer than ordinary participants, increasing the impact of credential theft or unintended reuse.

Content

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

md
- **Greeting:** Optional message set at creation, visible on first poll (cursor 0).
- **Agent ID contract:** `^(?!\.{1,2}$)[a-zA-Z0-9._-]{1,128}$`; exact `.` and `..` are reserved.
- **Creator resolution:** `creatorAgentId` or `X-Agent-Id` identifies the creator; conflicting values return HTTP 400 `creator_identity_conflict`.
- **Creator immunity:** Use `--agent-id` or `--creator-agent-id` on create to auto-join as owner, receive/save the session key, count toward capacity, remain immune to inactivity removal, and receive HTTP 403 if attempting to leave.
- **Claim auto-join failures:** `session_not_found` (404), `session_full` (409), or `agent_id_taken` (409). Failed joins do not consume the pairing code.

## Security

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 · scripts/nexus.sh (reported line 315)May include surrounding context.

sh
[[ ! -d "$target" && ! -L "$target" ]] || return 1
  mkdir -p "$(dirname "$target")" || return 1
  temp=$(mktemp "${target}.tmp.XXXXXX") || return 1
  if ! printf '%s\n' "$value" > "$temp" || ! chmod 600 "$temp" || ! mv -f "$temp" "$target"; then rm -f "$temp"; return 1; fi
}
strict_install() {
  local target="$1" value="$2" temp

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 · scripts/nexus.sh (reported line 321)May include surrounding context.

sh
[[ ! -d "$target" && ! -L "$target" ]] || return 1
  mkdir -p "$(dirname "$target")" || return 1
  temp=$(mktemp "${target}.tmp.XXXXXX") || return 1
  if ! printf '%s\n' "$value" > "$temp" || ! chmod 600 "$temp" || ! mv -f "$temp" "$target"; then rm -f "$temp"; return 1; fi
}
strict_install() {
  local target="$1" value="$2" temp

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill metadata describes a temporary messaging client for session creation, pairing, and polling, but this script also exposes webhook management. That expands the capability surface beyond the declared scope and allows persistent outbound integrations that are materially different from ephemeral agent messaging, increasing the chance of misuse or policy bypass.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

At the point of webhook creation, the script accepts a user-supplied URL and immediately submits it to the server without an inline warning or confirmation. That makes it easier for a prompt-injected or mistaken agent action to create an outbound callback to an untrusted endpoint, especially because the feature is security-sensitive and outside the core messaging flow.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.