Back to skill

Security audit

Ekybot Connector

Security checks for vulnerabilities and agentic risk

Overview

This connector mostly matches its remote-agent-management purpose, but it gives Ekybot broad background control over local agents and contains consent and deletion-safety issues that require review before use.

Install only if you are comfortable giving Ekybot background access to manage local OpenClaw agents and relay prompts into them. Use a low-privilege account, back up OpenClaw workspaces, avoid running the daemon with sudo, restrict tools available to remotely reachable agents, review memory files before enabling sync, and verify/disable background services after setup.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
Findings (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
runtime/src/config-manager.js:413
Finding
Cloud-Controlled Recursive Workspace Deletion Uses an Insufficient Path Boundary Check<![CDATA[ ## Vulnerability Details **File Location**: `runtime/src/companion-executor.js:162-180` and `runtime/src/config-manager.js:413-434` **Vulnerability Type**: Inadequate authorization and path validation for remote destructive operations **Risk Level**: High ### Vulnerable Code ```js // runtime/src/companion-executor.js:162-180 if (operation.type === 'delete_agent') { const payload = operation.payload || {}; const removeInfo = this.configManager.removeAgentFromConfig({ openclawAgentId: payload.openclawAgentId, workspacePath: payload.workspacePath, name: payload.name, }); const preserveWorkspace = payload.preserveWorkspace === true; const workspaceInfo = preserveWorkspace ? { deleted: false, preserved: true, reason: 'preserve_workspace_requested', workspacePath: payload.workspacePath || null, } : this.configManager.deleteWorkspace(payload.workspacePath); ``` ```js // runtime/src/config-manager.js:413-434 deleteWorkspace(workspacePath) { if (!workspacePath) { return { deleted: false, reason: 'missing_workspace_path' }; } const resolvedPath = this.resolveHomePath(workspacePath); if (!fs.existsSync(resolvedPath)) { return { deleted: false, reason: 'workspace_missing', workspacePath: resolvedPath }; } const normalizedPath = resolvedPath.replace(/\\/g, '/'); const looksLikeOpenClawWorkspace = normalizedPath.includes('/.openclaw/') || normalizedPath.includes('/openclaw/') || path.basename(resolvedPath).startsWith('workspace-'); if (!looksLikeOpenClawWorkspace) { return { deleted: false, reason: 'workspace_path_not_safe', workspacePath: resolvedPath }; } fs.rmSync(resolvedPath, { recursive: true, force: true }); return { deleted: true, workspacePath: resolvedPath }; } ``` ### Technical Analysis The persistent daemon obtains pending operations and their payloads from the Ekybot cloud. For a `delete_agent` operation, the cloud-provided `workspa ...[truncated 2259 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define one explicit managed-workspace root, such as `~/.openclaw/managed-workspaces`. 2. Resolve both the approved root and deletion target with `fs.realpathSync()` before performing any operation. 3. Verify containment using `path.relative()`: - Reject absolute relative results. - Reject `..` and paths beginning with `../`. - Reject deletion of the workspace root itself. 4. Reject symbolic links at the target and at relevant path components, or use filesystem operations that cannot traverse them unexpectedly. 5. Verify that the target belongs to the locally recorded managed agent rather than trusting the remote `workspacePath`. 6. Default `preserveWorkspace` to true and require an explicit local confirmation or separately authorized destructive-action token before deleting files. 7. Maintain recoverable backups or move workspaces to a quarantine/trash directory instead of immediately deleting them. 8. Log the canonical target and operation identifier before deletion, without exposing credentials. 9. Add tests covering traversal, symlinks, `.openclaw` parent directories, unrelated `workspace-*` directories, filesystem roots, and malformed paths. ]]>

T01 · Skill Instruction Hijacking

Error
Location
runtime/src/companion-relay-processor.js:105
Finding
Untrusted Cloud Relay Messages Are Injected Directly into Local Agent Prompts<![CDATA[ ## Vulnerability Details **File Location**: `runtime/src/companion-relay-processor.js:105-158` **Vulnerability Type**: Prompt injection across a remote-to-local trust boundary **Risk Level**: High ### Vulnerable Code ```js buildRelayPrompt(notification) { const relay = notification?.relay || {}; const source = relay.source || {}; const target = relay.target || {}; const message = relay.message || {}; const type = relay.type || 'agent_notification'; const sourceAgentName = source.agentName || notification.fromAgentName || source.agentId || 'Un autre agent'; const targetAgentName = target.name || target.agentId || notification?.toAgentId || 'Agent cible'; const sourceChannel = normalizeChannelKey(source.channelKey) || normalizeChannelKey(notification.threadId) || 'general'; const content = typeof message.content === 'string' ? message.content.trim() : typeof notification.content === 'string' ? notification.content.trim() : ''; if (type === 'channel_dispatch') { const timingHint = content.includes('TEST_CONTINUITY_DELAY_70') ? [ 'Le marqueur TEST_CONTINUITY_DELAY_70 sert a tester la continuite du transport, pas a te faire promettre une reponse plus tard.', 'Le systeme affiche deja l accuse de reception immediatement.', 'Donne donc directement la reponse finale demandee quand tu reponds. Ne reponds pas seulement "je reviens plus tard".', ] : [ 'Ne consomme pas ta reponse avec une promesse de retour plus tard.', 'Quand tu reponds, donne directement la reponse utile/finale attendue.', ]; return [ '[CHANNEL DISPATCH]', `Target agent: ${targetAgentName}`, `Source channel: #${sourceChannel}`, `Sender: ${sourceAgentName}`, 'Tu réponds au message utilisateur de ton propre channel.', 'Réponds normalement, sans recopier ce préambule technique.', 'Ta réponse sera republiée automatiquement dans le ...[truncated 3076 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat every relay message and all sender metadata as untrusted external data. 2. Place immutable safety and authorization rules in a trusted system-level message rather than concatenating them with relay content. 3. Pass relay content through a structured interface that clearly labels it as quoted data, not connector instructions. 4. Run remote relay sessions under a dedicated low-privilege agent profile with no shell, credential, configuration, or unrestricted filesystem tools by default. 5. Require explicit local approval for actions involving file deletion, command execution, credential access, external communication, or configuration changes. 6. Enforce sender, workspace, channel, and target-agent authorization before dispatch. 7. Apply content-length limits and reject malformed or unexpectedly structured relay payloads. 8. Ensure the agent cannot use remote content to change persistent instructions or memory without a separate trusted approval step. 9. Record auditable relay provenance, including authenticated sender and channel identifiers, while avoiding sensitive message logging where unnecessary. ]]>

T06 · System Persistence

Warning
Location
scripts/setup.sh:151
Finding
Setup Starts a Background Daemon After the User Declines Daemon Installation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.sh:151-189` **Vulnerability Type**: Background persistence without effective user consent **Risk Level**: Medium ### Vulnerable Code ```bash case "$INSTALL_DAEMON" in [yY]|[yY][eE][sS]) echo "" echo "📦 Installing background daemon..." if [[ "$OSTYPE" == "darwin"* ]]; then npm run companion:install-launchd 2>&1 echo "✅ macOS LaunchAgent installed" else echo " Starting daemon in background..." mkdir -p "$HOME/.openclaw/logs" nohup npm run companion:daemon > "$HOME/.openclaw/logs/ekybot-companion.log" 2>&1 & echo "✅ Daemon started (PID: $!)" echo " Logs: $HOME/.openclaw/logs/ekybot-companion.log" fi ;; *) echo " Skipped daemon install. Start manually with:" echo " cd $CONNECTOR_DIR && npm run companion:daemon" ;; esac # ── Step 7: Verify daemon is running ───────────────────────────────── echo "" echo "🔍 Verifying daemon is running..." sleep 3 if pgrep -f companion-daemon > /dev/null 2>&1; then echo "✅ Daemon is running (PID: $(pgrep -f companion-daemon | head -1))" else echo "⚠️ Daemon does NOT appear to be running!" echo " Starting it now..." mkdir -p "$HOME/.openclaw/logs" nohup node scripts/companion-daemon.js > "$HOME/.openclaw/logs/ekybot-companion.log" 2>&1 & sleep 3 if pgrep -f companion-daemon > /dev/null 2>&1; then echo "✅ Daemon started (PID: $(pgrep -f companion-daemon | head -1))" else echo "❌ Daemon failed to start. Check logs:" echo " tail -20 $HOME/.openclaw/logs/ekybot-companion.log" echo "" echo " ⛔ Installation is INCOMPLETE — the daemon must be running for Ekybot to work." exit 1 fi fi ``` ### Technical Analysis The setup script asks whether the user wants to install a background daemon. If the user answers negat ...[truncated 1688 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Track the user’s choice explicitly and skip both daemon verification and startup when the answer is negative. 2. Change the negative branch to exit setup successfully after displaying the manual-start command. 3. Separate these actions into independently consented options: - Run one reconciliation cycle now; - Start a temporary background process; - Install an operating-system startup service. 4. Do not describe setup as incomplete merely because the user declines persistent operation. 5. Provide clear stop and uninstall commands immediately before enabling any background process. 6. In non-interactive mode, default to no daemon unless `EKYBOT_INSTALL_DAEMON=yes` is explicitly supplied. 7. Add tests confirming that all negative responses leave no daemon, LaunchAgent, systemd unit, or detached process running. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
runtime/scripts/companion-install-launchd.js:17
Finding
Unescaped Path Values Are Embedded in a LaunchAgent XML File<![CDATA[ ## Vulnerability Details **File Location**: `runtime/scripts/companion-install-launchd.js:17-86` **Vulnerability Type**: XML injection and malformed service configuration **Risk Level**: Medium ### Vulnerable Code ```js function ensureSafePath(value, label) { if (/[\x00-\x1f]/.test(value)) { throw new Error(`Unsafe ${label}: contains control characters`); } return value; } function buildLaunchdPlist({ nodePath, daemonScript, workingDirectory, envFilePath }) { const logDir = path.join(os.homedir(), 'Library', 'Logs'); const stdoutPath = path.join(logDir, 'ekybot-companion.log'); const stderrPath = path.join(logDir, 'ekybot-companion.error.log'); return `<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.ekybot.companion</string> <key>ProgramArguments</key> <array> <string>${nodePath}</string> <string>${daemonScript}</string> </array> <key>WorkingDirectory</key> <string>${workingDirectory}</string> <key>EnvironmentVariables</key> <dict> <key>EKYBOT_COMPANION_ENV_FILE</key> <string>${envFilePath}</string> </dict> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> <key>StandardOutPath</key> <string>${stdoutPath}</string> <key>StandardErrorPath</key> <string>${stderrPath}</string> </dict> </plist> `; } async function installLaunchdService() { const daemonScript = ensureSafePath( path.join(process.cwd(), 'scripts', 'companion-daemon.js'), 'daemon script path' ); const nodePath = ensureSafePath(process.execPath, 'node path'); const workingDirectory = ensureSafePath(process.cwd(), 'working directory'); const envFilePath = ensureSafePath(resolveEnvFilePath(), 'env file path'); const plistPath = path.join( os.homedir(), 'Library', 'LaunchAgents', 'com.ekybot.companion.plist' ); fs.mkdirSync(path ...[truncated 2153 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Generate the plist with a structured property-list serializer rather than manual XML concatenation. 2. If manual generation is retained, XML-escape every interpolated value, including `&`, `<`, `>`, `"`, and `'`. 3. Canonicalize all paths and validate that they are absolute where required. 4. Restrict `EKYBOT_COMPANION_ENV_FILE` to an expected connector-owned directory unless the user explicitly approves another location. 5. Validate the generated file using `plutil -lint` before instructing the user to load it. 6. Write the plist atomically with restrictive permissions. 7. Add tests using directory and environment-file names containing ampersands, angle brackets, quotes, spaces, and Unicode characters. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (140)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
If the packaged runtime creates agent workspaces, modifies OpenClaw configuration, restarts the gateway, and creates remote channels, those are materially broader and more invasive actions than a simple connector setup description implies. Such behavior can alter local agent topology and remote collaboration state, which increases blast radius beyond basic enrollment or health monitoring.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the packaged runtime creates agent workspaces, modifies OpenClaw configuration, restarts the gateway, and creates remote channels, those are materially broader and more invasive actions than a simple connector setup description implies. Such behavior can alter local agent topology and remote collaboration state, which increases blast radius beyond basic enrollment or health monitoring.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
If the packaged runtime creates agent workspaces, modifies OpenClaw configuration, restarts the gateway, and creates remote channels, those are materially broader and more invasive actions than a simple connector setup description implies. Such behavior can alter local agent topology and remote collaboration state, which increases blast radius beyond basic enrollment or health monitoring.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the packaged runtime creates agent workspaces, modifies OpenClaw configuration, restarts the gateway, and creates remote channels, those are materially broader and more invasive actions than a simple connector setup description implies. Such behavior can alter local agent topology and remote collaboration state, which increases blast radius beyond basic enrollment or health monitoring.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
If the packaged runtime creates agent workspaces, modifies OpenClaw configuration, restarts the gateway, and creates remote channels, those are materially broader and more invasive actions than a simple connector setup description implies. Such behavior can alter local agent topology and remote collaboration state, which increases blast radius beyond basic enrollment or health monitoring.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
If the packaged runtime creates agent workspaces, modifies OpenClaw configuration, restarts the gateway, and creates remote channels, those are materially broader and more invasive actions than a simple connector setup description implies. Such behavior can alter local agent topology and remote collaboration state, which increases blast radius beyond basic enrollment or health monitoring.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
If the packaged runtime creates agent workspaces, modifies OpenClaw configuration, restarts the gateway, and creates remote channels, those are materially broader and more invasive actions than a simple connector setup description implies. Such behavior can alter local agent topology and remote collaboration state, which increases blast radius beyond basic enrollment or health monitoring.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
If the packaged runtime creates agent workspaces, modifies OpenClaw configuration, restarts the gateway, and creates remote channels, those are materially broader and more invasive actions than a simple connector setup description implies. Such behavior can alter local agent topology and remote collaboration state, which increases blast radius beyond basic enrollment or health monitoring.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
If the packaged runtime creates agent workspaces, modifies OpenClaw configuration, restarts the gateway, and creates remote channels, those are materially broader and more invasive actions than a simple connector setup description implies. Such behavior can alter local agent topology and remote collaboration state, which increases blast radius beyond basic enrollment or health monitoring.

Credential Access

High
Category
Privilege Escalation
Content
class AuthManager {
  constructor() {
    this.tokenFile = path.join(process.cwd(), '.ekybot-token');
    this.configFile = path.join(process.cwd(), '.env');
  }

  // Load API token from environment or token file
Confidence
88% confidence
Finding
The code stores an API key in a project-local `.env` file under `process.cwd()`. Even with mode 0600, this is risky because project directories are commonly committed, copied, backed up, or exposed to other tooling, which can lead to credential disclosure and unauthorized remote control of the connected service.

Credential Access

High
Category
Privilege Escalation
Content
return process.env.EKYBOT_API_KEY;
    }

    // Try .env file
    if (fs.existsSync(this.configFile)) {
      const envContent = fs.readFileSync(this.configFile, 'utf8');
      const match = envContent.match(/EKYBOT_API_KEY=(.+)/);
Confidence
82% confidence
Finding
Reading credentials from a project `.env` file means any user or process with access to the working directory contents can recover the token. In this connector context, the token appears to enable remote agent control and memory sync, so exposure could let an attacker access or control external systems tied to the account.

Credential Access

High
Category
Privilege Escalation
Content
return null;
  }

  // Save API token to .env file
  saveToken(token) {
    try {
      let envContent = '';
Confidence
91% confidence
Finding
The function explicitly saves the API token to `.env`, creating persistent plaintext credential storage in the current working directory. In a tool that connects to a remote control service, theft of this token could enable unauthorized access, impersonation, or manipulation of agent operations and synced project memory.

Credential Access

High
Category
Privilege Escalation
Content
try {
      let envContent = '';

      // Read existing .env if it exists
      if (fs.existsSync(this.configFile)) {
        envContent = fs.readFileSync(this.configFile, 'utf8');
      }
Confidence
80% confidence
Finding
Reading and rewriting the entire `.env` file to manage the API key increases the chance that secrets remain in an insecure, broadly accessible project artifact. This also normalizes storing operational credentials alongside application configuration, which is dangerous in shared development environments and CI/CD workspaces.

Self-Modification

High
Category
Rogue Agent
Content
echo "  --agents <number>     Number of agents to setup (default: 2)"
    echo "  --preset <type>       Agent preset: personal|team|enterprise (default: personal)"
    echo "  --dry-run            Show what would be done without making changes"
    echo "  --force              Overwrite existing configuration"
    echo "  --help               Show this help"
}
Confidence
85% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
" > /tmp/agents_config.json
    
    agents_json=$(cat /tmp/agents_config.json)
    rm -f /tmp/agents_config.json
    
    # Create new configuration
    if [[ -f "$OPENCLAW_CONFIG" ]]; then
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).

External Script Fetching

High
Category
Supply Chain
Content
# Send health data to EkyBot
print_status "Sending health report to EkyBot..."

RESPONSE=$(curl -s -X GET "$HEALTH_ENDPOINT" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json")
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
print_status "Registering workspace with EkyBot..."

# Make registration request
RESPONSE=$(curl -s -X POST "$EKYBOT_API_BASE/workspaces/register" \
  -H "Content-Type: application/json" \
  -d "$REGISTRATION_DATA")
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Credential Access

High
Category
Privilege Escalation
Content
mkdir -p "$CONNECTOR_DIR"
fi

# Copy bundled files (preserve existing .env config)
cp -r "$RUNTIME_DIR/src" "$CONNECTOR_DIR/"
cp -r "$RUNTIME_DIR/scripts" "$CONNECTOR_DIR/"
cp "$RUNTIME_DIR/package.json" "$CONNECTOR_DIR/"
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
mkdir -p "$CONNECTOR_DIR"
fi

# Copy bundled files (preserve existing .env config)
cp -r "$RUNTIME_DIR/src" "$CONNECTOR_DIR/"
cp -r "$RUNTIME_DIR/scripts" "$CONNECTOR_DIR/"
cp "$RUNTIME_DIR/package.json" "$CONNECTOR_DIR/"
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
mkdir -p "$CONNECTOR_DIR"
fi

# Copy bundled files (preserve existing .env config)
cp -r "$RUNTIME_DIR/src" "$CONNECTOR_DIR/"
cp -r "$RUNTIME_DIR/scripts" "$CONNECTOR_DIR/"
cp "$RUNTIME_DIR/package.json" "$CONNECTOR_DIR/"
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Memory Manipulation

High
Category
Memory Poisoning
Content
```
📨 [Sender → Receiver]

Message content here with clear context and action items.

— Sender Name
```
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Exfiltration Commands

High
Category
Prompt Injection
Content
### Session Communication
```bash
# Send message to specific agent
sessions_send sessionKey=agent:target-agent-id message="Your message"

# List active agent sessions
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill declares required environment and clearly instructs users to run shell commands, install services, read/write local files, and connect to a remote cloud service, but it does not declare any explicit tool scope or permissions boundaries. That omission weakens reviewability and informed consent, because the effective capabilities are broad and include shell execution, persistence, filesystem modification, and network access.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The activation text is broad and encourages use across installation, configuration, connectivity validation, onboarding, and 'improving' workflows without clearly limiting when high-impact actions should or should not occur. In a skill that performs enrollment, local config changes, daemon installation, telemetry, and possible persistence, overly broad triggering language increases the chance of unintended execution in sensitive environments.

Session Persistence

Medium
Category
Rogue Agent
Content
```bash
cd ~/.openclaw/ekybot-connector
nohup node scripts/companion-daemon.js > ~/.openclaw/logs/ekybot-companion.log 2>&1 &
mkdir -p ~/.openclaw/logs
sleep 3 && tail -10 ~/.openclaw/logs/ekybot-companion.log
```
Confidence
96% confidence
Finding
The nohup-based manual daemon start creates a detached background process that continues operating after the initiating shell exits. Because the daemon mediates remote control and sync behavior, running it persistently without strong visibility or controls can increase host risk.

Static analysis

Detected: suspicious.env_credential_access, suspicious.exposed_secret_literal

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
runtime/src/companion-api-client.js:39

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
runtime/src/openclaw-gateway-client.js:26

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
references/api.md:16