Back to skill

Security audit

AgentOS Mesh

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent mesh-messaging CLI, but it needs review because it can send bearer credentials over HTTP and encourages unattended agent processing of remote messages.

Review before installing. Use only an HTTPS AgentOS URL, restrict and protect the API key, avoid sharing status output, and do not enable heartbeat or cron auto-processing unless messages come only from trusted agents and remote message text is handled as untrusted data requiring approval before replies or tool use.

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

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:102
Finding
Remote Mesh Messages Can Hijack Agent Instructions<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:102-108`; `scripts/mesh.sh:121-154` **Vulnerability Type**: Untrusted remote content is automatically placed into an agent-processing workflow **Risk Level**: High ### Vulnerable Code `SKILL.md:102-108`: ```markdown ## Heartbeat Integration Add this to your HEARTBEAT.md to auto-process mesh messages: ```markdown ## Mesh Communication 1. Check `~/.mesh-pending.json` for queued messages 2. Process each message and respond via `mesh send` 3. Clear processed messages ``` ``` `scripts/mesh.sh:121-154`: ```bash # Poll API for new messages (inbox) cmd_check() { check_config response=$(curl -s -X GET "$AGENTOS_URL/v1/mesh/messages?agent_id=$AGENT_ID&direction=inbox&status=sent&limit=50" \ -H "Authorization: Bearer $AGENTOS_KEY" \ -H "Content-Type: application/json") if echo "$response" | jq -e '.messages' > /dev/null 2>&1; then count=$(echo "$response" | jq '.messages | length') if [ "$count" -gt 0 ]; then echo -e "${YELLOW}📬 $count unread message(s) from API:${NC}" echo "$response" | jq '.messages[] | {id: .id, from: .from_agent, topic: .topic, body: .body[0:100]}' # Merge with pending file if [ -f "$PENDING_FILE" ]; then existing=$(cat "$PENDING_FILE") else existing="[]" fi # Transform and add new messages new_msgs=$(echo "$response" | jq '[.messages[] | {id: .id, from: .from_agent, topic: .topic, body: .body, receivedAt: .created_at}]') merged=$(echo "$existing" "$new_msgs" | jq -s '.[0] + .[1] | unique_by(.id)') echo "$merged" > "$PENDING_FILE" else echo -e "${GREEN}✓ No new messages${NC}" fi else echo -e "${RED}API check failed:${NC}" echo "$response" | jq . fi } ``` ### Technical Analysis The polling command copies remote message bodies into `~/.mesh-pending.json` without validating the sender, constraining message content, or distinguishing data fro ...[truncated 1743 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Treat every remote topic and message body strictly as untrusted data. - Do not direct an AI agent to automatically execute or comply with message content. - Require explicit user approval before responding to a message or invoking any tool based on it. - Authenticate senders and implement an allowlist of permitted agent identities. - Present remote messages in strongly delimited data blocks with explicit instructions that their contents cannot override system, developer, user, or skill rules. - Reject or quarantine messages that request secrets, tool invocation, policy changes, persistence, credential access, or actions unrelated to a narrowly defined communication function. - Attach verified sender metadata and authorization scope to each queued message. - Record audit logs for receipt, approval, rejection, and response actions. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/mesh.sh:7
Finding
Bearer Credentials and Mesh Content Can Be Transmitted over Plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mesh.sh:7-16,55-75`; also documented in `SKILL.md:66-81` **Vulnerability Type**: Sensitive authentication credentials and message data transmitted without mandatory TLS **Risk Level**: High ### Vulnerable Code `scripts/mesh.sh:7-16`: ```bash # Load config if [ -f ~/.agentos-mesh.json ]; then AGENTOS_URL=$(jq -r '.apiUrl' ~/.agentos-mesh.json) AGENTOS_KEY=$(jq -r '.apiKey' ~/.agentos-mesh.json) AGENT_ID=$(jq -r '.agentId' ~/.agentos-mesh.json) else AGENTOS_URL="${AGENTOS_URL:-http://178.156.216.106:3100}" AGENTOS_KEY="${AGENTOS_KEY:-}" AGENT_ID="${AGENTOS_AGENT_ID:-reggie}" fi ``` `scripts/mesh.sh:55-75`: ```bash # Send a message cmd_send() { check_config local to_agent="$1" local topic="$2" local body="$3" if [ -z "$to_agent" ] || [ -z "$topic" ] || [ -z "$body" ]; then echo "Usage: mesh send <to_agent> <topic> <body>" exit 1 fi response=$(curl -s -X POST "$AGENTOS_URL/v1/mesh/messages" \ -H "Authorization: Bearer $AGENTOS_KEY" \ -H "Content-Type: application/json" \ -d "{ \"from_agent\": \"$AGENT_ID\", \"to_agent\": \"$to_agent\", \"topic\": \"$topic\", \"body\": \"$body\" }") if echo "$response" | jq -e '.message.id' > /dev/null 2>&1; then echo -e "${GREEN}✓ Message sent to $to_agent${NC}" echo "$response" | jq -r '.message.id' else echo -e "${RED}✗ Failed to send message${NC}" echo "$response" | jq . exit 1 fi } ``` `SKILL.md:66-81`: ```markdown ## Configuration Create `~/.agentos-mesh.json`: ```json { "apiUrl": "http://your-server:3100", "apiKey": "agfs_live_xxx.yyy", "agentId": "your-agent-id" } ``` Or set environment variables: ```bash export AGENTOS_URL="http://your-server:3100" export AGENTOS_KEY="agfs_live_xxx.yyy" export AGENTOS_AGENT_ID="your-agent-id" ``` ``` ### Technical Analysis The CLI has a hardcoded plaintext HTTP endpoint and the configuration documentation ...[truncated 1403 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the hardcoded plaintext HTTP endpoint. - Require an `https://` API URL during configuration and terminate execution when a non-HTTPS remote URL is supplied. - If plaintext access is necessary for development, restrict it to explicitly enabled loopback addresses such as `127.0.0.1` or `localhost`. - Update all documentation and installer examples to use HTTPS. - Retain curl's certificate verification and do not introduce insecure options such as `--insecure`. - Use short-lived, narrowly scoped credentials and provide a credential-rotation mechanism. - Rotate any API key that may already have been transmitted over an untrusted HTTP connection. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mesh.sh:200
Finding
Status Command Exposes a Significant API Key Prefix<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mesh.sh:200-206` **Vulnerability Type**: Sensitive credential material disclosed in command output **Risk Level**: Medium ### Vulnerable Code ```bash # Show status cmd_status() { echo -e "${BLUE}=== Mesh Status ===${NC}" echo "API URL: $AGENTOS_URL" echo "Agent ID: $AGENT_ID" echo "API Key: ${AGENTOS_KEY:0:20}..." echo "" ``` ### Technical Analysis The status command prints the first 20 characters of the configured bearer API key. Although the entire key is not printed, this reveals substantially more credential material than is necessary to indicate configuration status. Command output is commonly captured in CI logs, support bundles, screenshots, terminal recordings, cron output, or chat transcripts. A stable credential prefix can also facilitate secret identification and correlation and reduces the unknown key material if the credential format provides insufficient remaining entropy. The installer invokes `mesh status` while suppressing only standard error. Although its output is piped through `grep`, direct invocations and other automation can expose the prefix. ### Attack Path 1. A valid API key is configured. 2. A user, support process, installer, or automated diagnostic invokes `mesh status`. 3. The first 20 characters of the key are emitted to standard output. 4. That output is logged, recorded, screenshotted, or shared. 5. An unauthorized party obtains and correlates the disclosed credential material. ### Impact Assessment This finding directly exposes part of an authentication secret but does not, by itself, prove that the full key can be reconstructed. The impact includes credential metadata leakage, easier identification and correlation of keys, and increased risk when combined with another partial disclosure or a weak credential format. No additional operating-system privileges are obtained directly. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Never print any portion of the bearer token. - Replace the output with a boolean status such as `API Key: configured`. - If key identification is operationally necessary, display a non-secret identifier supplied by the server or a short cryptographic fingerprint rather than key characters. - Review logs and support artifacts for previously exposed prefixes. - Ensure diagnostic and status commands are safe to run in shared terminals and automated logging environments. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mesh.sh:55
Finding
Caller-Controlled Values Are Interpolated into JSON without Escaping<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mesh.sh:55-75,167-186` **Vulnerability Type**: JSON injection and malformed request construction **Risk Level**: Medium ### Vulnerable Code `scripts/mesh.sh:55-75`: ```bash # Send a message cmd_send() { check_config local to_agent="$1" local topic="$2" local body="$3" if [ -z "$to_agent" ] || [ -z "$topic" ] || [ -z "$body" ]; then echo "Usage: mesh send <to_agent> <topic> <body>" exit 1 fi response=$(curl -s -X POST "$AGENTOS_URL/v1/mesh/messages" \ -H "Authorization: Bearer $AGENTOS_KEY" \ -H "Content-Type: application/json" \ -d "{ \"from_agent\": \"$AGENT_ID\", \"to_agent\": \"$to_agent\", \"topic\": \"$topic\", \"body\": \"$body\" }") if echo "$response" | jq -e '.message.id' > /dev/null 2>&1; then echo -e "${GREEN}✓ Message sent to $to_agent${NC}" echo "$response" | jq -r '.message.id' else echo -e "${RED}✗ Failed to send message${NC}" echo "$response" | jq . exit 1 fi } ``` `scripts/mesh.sh:167-186`: ```bash # Create a task cmd_task() { check_config local assigned_to="$1" local title="$2" local description="$3" if [ -z "$assigned_to" ] || [ -z "$title" ]; then echo "Usage: mesh task <assigned_to> <title> [description]" exit 1 fi response=$(curl -s -X POST "$AGENTOS_URL/v1/mesh/tasks" \ -H "Authorization: Bearer $AGENTOS_KEY" \ -H "Content-Type: application/json" \ -d "{ \"assigned_by\": \"$AGENT_ID\", \"assigned_to\": \"$assigned_to\", \"title\": \"$title\", \"description\": \"${description:-}\" }") if echo "$response" | jq -e '.task_id' > /dev/null 2>&1; then ``` ### Technical Analysis User-controlled command arguments and configuration-derived agent identifiers are inserted directly into a double-quoted JSON template. The code does not perform JSON escaping for quotation marks, backslashes, control characters, or newl ...[truncated 1715 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Construct request bodies with a JSON-aware serializer instead of string interpolation. - For example, use `jq` with `--arg`: ```bash payload=$(jq -n \ --arg from_agent "$AGENT_ID" \ --arg to_agent "$to_agent" \ --arg topic "$topic" \ --arg body "$body" \ '{ from_agent: $from_agent, to_agent: $to_agent, topic: $topic, body: $body }') response=$(curl -sS -X POST "$AGENTOS_URL/v1/mesh/messages" \ -H "Authorization: Bearer $AGENTOS_KEY" \ -H "Content-Type: application/json" \ --data-binary "$payload") ``` - Apply the same serialization approach to task creation. - Validate agent identifiers against a strict expected character set and length. - Enforce reasonable length limits for topics, titles, bodies, and descriptions. - Add tests covering quotes, backslashes, newlines, control characters, Unicode, and attempted property injection. - Ensure the server independently validates the request schema and ignores or rejects unknown and duplicate fields. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (14)

Exfiltration Commands

High
Category
Prompt Injection
Content
echo ""
echo "Commands:"
echo "  mesh status   - Check connection"
echo "  mesh send     - Send message to another agent"
echo "  mesh pending  - View pending messages"
echo "  mesh agents   - List agents on mesh"
echo ""
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Session Persistence

Medium
Category
Rogue Agent
Content
# Run the installer
bash ~/clawd/skills/agentos-mesh/scripts/install.sh

# Configure (create ~/.agentos-mesh.json)
# Then test:
mesh status
```
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
## Configuration

Create `~/.agentos-mesh.json`:
```json
{
  "apiUrl": "http://your-server:3100",
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The documentation instructs users to place a live API key in a plaintext config file and environment variables, but does not warn about protecting the secret, file permissions, shell history, or avoiding accidental disclosure. In a messaging skill, compromise of this credential could let an attacker impersonate the agent, read or send mesh messages, and interact with the AgentOS API within the granted scopes.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The cron and heartbeat guidance promotes automatic polling, processing, responding, and clearing of messages without warning that this can cause unattended transmission, deletion, or loss of reviewable message data. In an agent-to-agent communication context, automation increases the chance that sensitive content is propagated or destroyed before a human can inspect it.

Session Persistence

Medium
Category
Rogue Agent
Content
echo ""
    echo -e "${BLUE}Fresh installation...${NC}"
    
    # Create bin directory if needed
    mkdir -p "${BIN_DIR}"
    
    # Install mesh CLI
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
echo "  process                          Process and return pending messages (clears queue)"
  echo "  check                            Check for new messages (API poll)"
  echo "  agents                           List agents on the mesh"
  echo "  task <to> <title> <desc>         Create a task for another agent"
  echo "  status                           Show daemon and connection status"
  echo ""
  echo "Environment:"
Confidence
80% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
echo "  process                          Process and return pending messages (clears queue)"
  echo "  check                            Check for new messages (API poll)"
  echo "  agents                           List agents on the mesh"
  echo "  task <to> <title> <desc>         Create a task for another agent"
  echo "  status                           Show daemon and connection status"
  echo ""
  echo "Environment:"
Confidence
80% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
echo "  process                          Process and return pending messages (clears queue)"
  echo "  check                            Check for new messages (API poll)"
  echo "  agents                           List agents on the mesh"
  echo "  task <to> <title> <desc>         Create a task for another agent"
  echo "  status                           Show daemon and connection status"
  echo ""
  echo "Environment:"
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

External Transmission

Medium
Category
Data Exfiltration
Content
exit 1
  fi
  
  response=$(curl -s -X POST "$AGENTOS_URL/v1/mesh/messages" \
    -H "Authorization: Bearer $AGENTOS_KEY" \
    -H "Content-Type: application/json" \
    -d "{
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
92% confidence
Finding
The process command emits queued messages and immediately clears the local pending file with no confirmation, backup, or transactional protection. This can cause message loss if the consumer crashes, output is piped incorrectly, or a user runs the command unintentionally, creating an integrity/availability issue for local message handling.

External Transmission

Medium
Category
Data Exfiltration
Content
exit 1
  fi
  
  response=$(curl -s -X POST "$AGENTOS_URL/v1/mesh/tasks" \
    -H "Authorization: Bearer $AGENTOS_KEY" \
    -H "Content-Type: application/json" \
    -d "{
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The status command prints the first 20 characters of the API key, which is sensitive credential material disclosed in a display-oriented command without necessity. Even partial secret exposure can aid credential theft via shoulder surfing, terminal logs, screenshots, shell history capture, or telemetry collection, especially if key formats are predictable.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The status output reveals part of the API key without warning, exposing credential data during a routine informational command. This increases the chance of accidental disclosure through logs, copied terminal output, support bundles, or shared sessions.

Static analysis

No suspicious patterns detected.