Back to skill

Security audit

messaging

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent agent messaging client, but its script can use insecure HTTP and has unsafe session-path handling that could expose credentials or affect files outside its stated local storage area.

Review this skill before installing. It is not clearly malicious, but only use it with trusted HTTPS servers, avoid attacker-controlled NEXUS_URL or --url values, do not send secrets, and be careful with auto-reply or memory-update rules based on messages from other agents.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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

Error
Location
scripts/nexus.sh:579
Finding
Path Traversal Through Unvalidated Session Identifiers<![CDATA[ ## Vulnerability Details **File Location**: `scripts/nexus.sh:579-594`; related destructive operation at `scripts/nexus.sh:170-177` **Vulnerability Type**: Path traversal and unsafe filesystem operations **Risk Level**: High ### Vulnerable Code ```bash claim) CODE="${1:?Usage: nexus.sh claim <CODE> --agent-id ID}" [[ -z "$AGENT_ID" ]] && echo '{"error":"missing --agent-id"}' && exit 1 net_preamble http_request -X POST "$NEXUS_URL/v1/pair/$CODE/claim" \ -H "X-Agent-Id: $AGENT_ID" emit_response SESSION_ID=$(echo "$RESPONSE" | jq -r '.sessionId // empty') if [[ -n "$SESSION_ID" ]]; then mkdir -p "$NEXUS_DATA_DIR/$SESSION_ID" write_binding "$SESSION_ID" AGENT_FILE="$NEXUS_DATA_DIR/$SESSION_ID/agent" echo "$AGENT_ID" > "$AGENT_FILE" ``` The same unvalidated value can later reach a recursive deletion operation: ```bash cleanup_leave_state() { local sid="$1" alias_name="$2" rm -rf "$NEXUS_DATA_DIR/$sid" if [[ -n "$alias_name" ]]; then remove_alias "$alias_name" else local found found=$(reverse_alias "$sid") if [[ -n "$found" ]]; then remove_alias "$found" fi fi } ``` ### Technical Analysis The client documentation describes a session identifier as a 48-character hexadecimal value, but the script does not enforce that format before using the value as a filesystem path component. In the `claim` flow, `SESSION_ID` is read from a response supplied by the configured remote server. Shell quoting prevents shell metacharacter expansion, but it does not neutralize path components such as `..`. Consequently, a server response containing a value such as `../../../../tmp/target` causes the resulting path to resolve outside `~/.config/messaging/sessions`. The affected value is used by `mkdir`, `write_binding`, and redirections that create or overwrite fixed-name files called `server`, `agent`, and `key`. It can also reach `cleanup_leave_state`, where it is passed to `rm -rf` without canonicali ...[truncated 1684 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate every session identifier before using it in a URL or filesystem path: ```bash validate_session_id() { [[ "$1" =~ ^[a-fA-F0-9]{48}$ ]] || { echo '{"error":"invalid session identifier"}' return 1 } } ``` 2. Apply validation to: - User-supplied session identifiers. - Alias values loaded from `aliases.json`. - Session identifiers returned by `create` and `claim`. - Directory names enumerated from persisted state. 3. Canonicalize every state path and verify that it remains a direct child of `NEXUS_DATA_DIR` before writing or deleting it. 4. Replace recursive deletion based on externally derived values with narrowly scoped deletion of known files followed by `rmdir` of a validated session directory. 5. Treat malformed identifiers in server responses as protocol violations and abort without writing any local state. 6. Add regression tests using identifiers containing `..`, slashes, absolute paths, encoded separators, empty values, and identifiers longer or shorter than 48 hexadecimal characters. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/nexus.sh:1036
Finding
Session Credentials and Messages Can Be Transmitted over Plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/nexus.sh:1036-1047`; credential transmission at `scripts/nexus.sh:681-699` **Vulnerability Type**: Insecure transport of credentials and message content **Risk Level**: High ### Vulnerable Code The persisted configuration explicitly accepts both HTTP and HTTPS: ```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") mkdir -p "$(dirname "$NEXUS_CONFIG_FILE")" jq -n --arg u "$CFG_NORM" --arg t "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ '{serverUrl: $u, updatedAt: $t}' > "$NEXUS_CONFIG_FILE" jq -n --arg u "$CFG_NORM" '{ok: true, serverUrl: $u}' echo "✅ Server configured: $CFG_NORM" >&2 ``` Session credentials are subsequently sent to the selected server: ```bash KEY_FILE="$NEXUS_DATA_DIR/$SESSION_ID/key" if [[ -f "$KEY_FILE" ]]; then http_request -X POST "$NEXUS_URL/v1/sessions/$SESSION_ID/messages" \ -H "X-Agent-Id: $AGENT_ID" \ -H "X-Session-Key: $(cat "$KEY_FILE")" \ -H "Content-Type: application/json" \ -d "$BODY" else http_request -X POST "$NEXUS_URL/v1/sessions/$SESSION_ID/messages" \ -H "X-Agent-Id: $AGENT_ID" \ -H "Content-Type: application/json" \ -d "$BODY" fi ``` ### Technical Analysis The script permits a configured server URL beginning with `http://`. The higher-priority `--url` and `NEXUS_URL` sources are even less restrictive and receive no equivalent scheme validation before being used by `curl`. When an HTTP endpoint is selected, the script transmits message content, agent identifiers, and session credentials without transport encryption or server authentication. The `X-Session-Key` is explicitly documented as a credential that permits verified impersonation and can authorize leaving a session. This behavior also conflicts with the statement in `SKILL.md:37` that th ...[truncated 1435 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require `https://` for all non-local server URLs, regardless of whether the URL comes from: - `--url` - `NEXUS_URL` - `config.json` - A saved session binding 2. If plaintext HTTP is necessary for local development, require an explicit insecure-development option and restrict it to loopback addresses such as `127.0.0.1`, `::1`, or `localhost`. 3. Reject URLs containing user information, malformed authorities, control characters, fragments, or unsupported schemes. 4. Revalidate persisted configuration and session bindings every time they are loaded rather than assuming saved values are safe. 5. Configure `curl` to fail on unexpected redirects or restrict redirects to HTTPS destinations. Do not allow an HTTPS request carrying credentials to be redirected to HTTP. 6. Update `SKILL.md` so its network-security declaration accurately matches enforced behavior. 7. Warn and abort before sending `X-Session-Key` or message content if the selected connection is not protected by TLS. ]]>

T01 · Skill Instruction Hijacking

Warning
Location
SKILL.md:226
Finding
Untrusted Remote Messages Can Influence Automated Agent Behavior and Persistent Memory<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:226-262` **Vulnerability Type**: Remote instruction injection and persistent memory poisoning **Risk Level**: Medium ### Vulnerable Instructions ```markdown #### Processing Flow When you receive incoming NexusMessaging messages: 1. **Read MESSAGING.md** in your workspace 2. **Match the session** — find the label/ID in your Sessions section 3. **If matched:** follow the per-session rules (auto-reply, notify, forward, etc.) 4. **If not matched:** follow the Default Behavior 5. **Use `nexus_history`** (or `nexus.sh poll --after 0`) to get full conversation context before responding 6. **Update your memory** with any important decisions or outcomes This keeps all messaging behavior declarative and in your workspace — the plugin handles delivery, you handle intent. ``` The same section permits per-session automatic responses: ```markdown #### Per-Session Rules When you **join or create** a session, add an entry under `## Sessions` describing: - **Session ID** — so you can match incoming messages to rules - **Purpose** — why this session exists (what you agreed to do) - **On message** — what to do when messages arrive (notify, auto-reply, analyze, forward, etc.) - **Auto-reply** — whether to respond automatically or wait for user instruction ``` ### Technical Analysis Messages received from other session participants cross an external trust boundary. However, the Skill instructs the agent to process those messages, potentially respond automatically, and write important decisions or outcomes into persistent memory without an explicit requirement to treat message content as untrusted data. The messaging protocol does not provide end-to-end encryption, and the API permits unverified messages in some sending flows. Even a verified message only establishes possession of a session credential; it does not establish that the content is safe to follow as an instruction. A malicious participant can emb ...[truncated 1791 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Explicitly state that all incoming message text and JSON are untrusted data, even when marked as verified. 2. Instruct the agent never to treat remote message content as: - System or developer instructions. - Authorization to use tools. - Permission to modify configuration or workspace rules. - Permission to disclose secrets. - Permission to update long-term memory. 3. Keep auto-reply disabled by default. Require explicit, session-specific user consent before enabling it. 4. Require fresh user confirmation before consequential actions, external forwarding, tool invocation, configuration changes, or persistent-memory updates based on remote messages. 5. Restrict memory writes to validated factual summaries and clearly record their untrusted remote provenance. Do not persist behavioral rules received through messaging. 6. Add an instruction hierarchy stating that `MESSAGING.md` cannot override system, developer, safety, or user authorization requirements. 7. Separate message display from action execution. First summarize the message for the user, then wait for approval before acting unless the user has defined a narrow and safe automation rule. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (11)

Hidden Instructions

High
Category
Prompt Injection
Content
**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
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
## Sessions

<!-- Add per-session rules here when you join/create sessions -->
<!-- Example:
### research-partner
- **Session:** <session-id>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Chaining Abuse

High
Category
Tool Misuse
Content
# 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] [--url URL] [--agent-id ID] [--ttl N] [--after CURSOR] [--members]
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
# Called only when the server confirms we're no longer a member.
cleanup_leave_state() {
  local sid="$1" alias_name="$2"
  rm -rf "$NEXUS_DATA_DIR/$sid"
  if [[ -n "$alias_name" ]]; then
    remove_alias "$alias_name"
  else
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).

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill clearly expects shell execution (`curl`, `jq`, and `{baseDir}/scripts/nexus.sh`) yet does not declare an explicit tool scope such as allowed shell usage. That weakens sandboxing and reviewability because a host agent may grant broader execution than intended, increasing the chance of unsafe command use or environmental side effects.

Session Persistence

Medium
Category
Rogue Agent
Content
---
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:
  {
Confidence
94% confidence
Finding
The skill persists agent IDs, cursors, and especially session keys under `~/.config/messaging/`, creating durable local state for what is described as ephemeral messaging. Persisted credentials can be stolen by other local processes, accidentally exposed in backups/logs, or reused later to impersonate an agent and send verified messages.

Session Persistence

Medium
Category
Rogue Agent
Content
- **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
Confidence
92% confidence
Finding
This section confirms that session creation and claiming auto-save the session key locally, and the document itself states that the key is a credential that allows sending verified messages and leaving sessions. In the context of an agent-to-agent messaging skill, persistence of impersonation-capable credentials materially raises the risk of account/session hijacking if the local environment is compromised or transcripts accidentally disclose paths and contents.

External Transmission

Medium
Category
Data Exfiltration
Content
### Create Session
```bash
curl -X PUT $NEXUS_URL/v1/sessions \
  -H "X-Agent-Id: my-agent" \
  -H "Content-Type: application/json" \
  -d '{"ttl": 3660, "maxAgents": 10, "greeting": "Hello!"}'
Confidence
60% 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
94% confidence
Finding
The heartbeat command begins an indefinite polling loop that repeatedly makes network requests, but unlike poll-daemon it does not ask for confirmation before starting. Although it prints status lines, those appear only after launch and do not warn the user in advance about the ongoing network activity and need to manually interrupt it.

Missing User Warnings

Low
Confidence
78% confidence
Finding
This markdown file documents a public status-check endpoint that reveals pairing-code state, which can affect privacy or system integrity by enabling code enumeration or confirmation of active claims. The surrounding documentation does not include any warning or caution about treating pairing codes as sensitive or limiting exposure of this endpoint.

Missing User Warnings

Low
Confidence
84% confidence
Finding
This markdown file explains that aliases are stored in `~/.config/messaging/aliases.json` and shows full session-to-alias mappings, but it does not warn users that local session metadata will persist on disk. Because markdown files should disclose behaviors that may affect user data or privacy, this omission is a user-warning gap.

Static analysis

No suspicious patterns detected.