Back to skill

Security audit

Mirage Proxy

Security checks for vulnerabilities and agentic risk

Overview

This looks like a real OpenClaw proxy installer, but it adds a persistent local traffic proxy with sensitive access and installer risks that users should review first.

Install only if you trust the mirage-proxy upstream and are comfortable routing LLM prompts, responses, and provider authorization traffic through a local downloaded proxy. Prefer running it in an isolated container, verify release hashes, avoid the unpinned cargo fallback, do not enable restart persistence unless needed, and plan to remove the provider config manually on uninstall.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • 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
Findings (3)

T03 · Remote Payload Retrieval and Execution

Error
Location
setup.sh:81
Finding
Unpinned Remote Source Fallback Permits Mutable Payload Execution<![CDATA[ ## Vulnerability Details **File Location**: `setup.sh`, lines 81–107 **Vulnerability Type**: Remote payload retrieval and unsafe dependency sourcing **Risk Level**: High ### Vulnerable Code ```bash install() { echo "🔧 Installing mirage-proxy v${VERSION}..." # Download binary local plat=$(detect_platform) local url="https://github.com/${REPO}/releases/download/v${VERSION}/mirage-proxy-v${VERSION}-${plat}" local expected=$(expected_sha256 "$plat") echo " ↓ Downloading ${plat} binary..." curl -sL -o "${MIRAGE_BIN}" "${url}" chmod +x "${MIRAGE_BIN}" # Verify integrity if [ -n "$expected" ]; then verify_sha256 "${MIRAGE_BIN}" "$expected" else echo " ⚠ No checksum on record for platform ${plat} — skipping verification" fi # Verify it runs if ! "${MIRAGE_BIN}" --version >/dev/null 2>&1; then echo " ⚠ Binary failed (glibc mismatch?). Building from source..." if command -v cargo >/dev/null 2>&1; then cargo install --git "https://github.com/${REPO}" --root "${WORKSPACE}/.cargo-mirage" cp "${WORKSPACE}/.cargo-mirage/bin/mirage-proxy" "${MIRAGE_BIN}" else echo " ✗ No cargo found. Install Rust: https://rustup.rs" exit 1 fi fi ``` The checksum function also explicitly permits installation without verification: ```bash else echo " ⚠ No sha256sum or shasum found — skipping integrity check" return 0 fi ``` ### Technical Analysis The script retrieves a native executable from an external GitHub release and runs it locally. Although checksums are defined for supported platforms, verification fails open when neither `sha256sum` nor `shasum` is available. More critically, if the downloaded binary does not pass the `--version` execution check, the fallback runs: ```bash cargo install --git "https://github.com/${REPO}" --root "${WORKSPACE}/.cargo-mirage" ``` This command does not specify an immutable commit through `--rev`. Consequently, it builds whichever revision ...[truncated 2088 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin source installation to a reviewed immutable commit: ```bash cargo install \ --git "https://github.com/${REPO}" \ --rev "<reviewed-full-commit-hash>" \ --locked \ --root "${WORKSPACE}/.cargo-mirage" ``` 2. Fail closed when no supported checksum utility is available. Never execute an artifact whose digest has not been verified. 3. Download into a securely created temporary directory and do not mark the file executable until verification succeeds. 4. Use `curl --fail --show-error --location` and verify that the response is a successful artifact download. 5. Verify both release artifacts and source-build outputs against independently maintained, reviewed digests or signatures. 6. Prefer bundling auditable source code or a reviewed artifact with the Skill rather than downloading mutable executable content during installation. 7. Run the proxy under a dedicated least-privilege account or a restricted container with narrowly scoped filesystem and network permissions. 8. Document what request headers and environment variables the proxy can access, and avoid exposing credentials not required for forwarding. ]]>

T06 · System Persistence

Error
Location
setup.sh:109
Finding
Indefinite Proxy Relaunch and Optional Cross-Restart Persistence<![CDATA[ ## Vulnerability Details **File Location**: `setup.sh`, lines 109–130; persistence instructions in `SKILL.md`, lines 97–109 **Vulnerability Type**: Persistent execution of a remotely obtained component **Risk Level**: High ### Vulnerable Code ```bash # Create auto-restart wrapper cat > "${WRAPPER}" << 'SCRIPT' #!/bin/sh while true; do MIRAGE_BIN_PATH --log-level info >> MIRAGE_LOG_PATH 2>&1 sleep 2 done SCRIPT sed -i "s|MIRAGE_BIN_PATH|${MIRAGE_BIN}|g" "${WRAPPER}" 2>/dev/null || \ sed "s|MIRAGE_BIN_PATH|${MIRAGE_BIN}|g" "${WRAPPER}" > "${WRAPPER}.tmp" && mv "${WRAPPER}.tmp" "${WRAPPER}" sed -i "s|MIRAGE_LOG_PATH|${MIRAGE_LOG}|g" "${WRAPPER}" 2>/dev/null || \ sed "s|MIRAGE_LOG_PATH|${MIRAGE_LOG}|g" "${WRAPPER}" > "${WRAPPER}.tmp" && mv "${WRAPPER}.tmp" "${WRAPPER}" chmod +x "${WRAPPER}" # Start it nohup "${WRAPPER}" > /dev/null 2>&1 & sleep 2 ``` The documentation recommends adding the wrapper to the container startup command: ```yaml # docker-compose.yml command: sh -c "nohup /home/node/.openclaw/workspace/start-mirage.sh > /dev/null 2>&1 & exec openclaw start" ``` The uninstall path leaves provider configuration unchanged: ```bash uninstall() { echo "🗑 Removing mirage-proxy..." kill $(ps aux | grep start-mirage | grep -v grep | awk '{print $2}') 2>/dev/null || true kill $(ps aux | grep mirage-proxy | grep -v grep | awk '{print $2}') 2>/dev/null || true rm -f "${MIRAGE_BIN}" "${WRAPPER}" "${MIRAGE_LOG}" echo " ✓ Removed. Provider config in openclaw.json left untouched (remove manually if needed)." } ``` ### Technical Analysis Installation creates an executable wrapper containing an unconditional infinite loop. Whenever the proxy exits, the wrapper waits two seconds and starts it again. The wrapper is detached through `nohup`, so it survives the invoking shell's termination. The documentation additionally instructs users to modify the Docker Compose startup command to launch the wrapper whenever the ...[truncated 1987 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make persistence separately opt-in rather than enabling an indefinite detached process during normal installation. 2. Use an explicit service manager or container sidecar with: - A dedicated least-privilege identity - Restart-rate limits and exponential backoff - CPU and memory limits - Health checks and a failure circuit breaker - Read-only filesystem access where practical - Narrow outbound network permissions 3. Record and manage an exact PID or service identifier instead of killing processes through broad `ps | grep` matching. 4. Revalidate the executable's signature or digest before every persistent launch. 5. Ensure repeated setup runs detect and stop an existing instance before creating another wrapper. 6. Update uninstallation to offer removal or restoration of all generated OpenClaw provider configuration. 7. Clearly disclose the persistence scope and provide explicit commands for stopping, disabling, and fully removing the service. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
setup.sh:117
Finding
Incorrect Shell Operator Grouping Can Abort Wrapper Generation<![CDATA[ ## Vulnerability Details **File Location**: `setup.sh`, lines 117–120 **Vulnerability Type**: Unsafe shell control-flow construction **Risk Level**: Low ### Vulnerable Code ```bash sed -i "s|MIRAGE_BIN_PATH|${MIRAGE_BIN}|g" "${WRAPPER}" 2>/dev/null || \ sed "s|MIRAGE_BIN_PATH|${MIRAGE_BIN}|g" "${WRAPPER}" > "${WRAPPER}.tmp" && mv "${WRAPPER}.tmp" "${WRAPPER}" sed -i "s|MIRAGE_LOG_PATH|${MIRAGE_LOG}|g" "${WRAPPER}" 2>/dev/null || \ sed "s|MIRAGE_LOG_PATH|${MIRAGE_LOG}|g" "${WRAPPER}" > "${WRAPPER}.tmp" && mv "${WRAPPER}.tmp" "${WRAPPER}" ``` ### Technical Analysis In POSIX-style shell grammar, `&&` and `||` form left-associative AND-OR lists with equal precedence. The first statement is therefore interpreted effectively as: ```bash ( sed -i ... || sed ... > "${WRAPPER}.tmp" ) && mv "${WRAPPER}.tmp" "${WRAPPER}" ``` If `sed -i` succeeds, the fallback command does not create `${WRAPPER}.tmp`, but the final `mv` is still executed because the parenthesized expression succeeded. The move then fails because the temporary file does not exist. The script enables `set -e`, so this failure can terminate installation after the remote executable and wrapper file have already been written. This produces a partial installation state. The same defect is repeated for both placeholder substitutions. ### Attack Path 1. The script runs in an environment where `sed -i` succeeds. 2. The first in-place substitution completes successfully. 3. Because of the ungrouped `||` and `&&` expression, the shell still executes `mv "${WRAPPER}.tmp" "${WRAPPER}"`. 4. No temporary file was created, so `mv` returns an error. 5. `set -e` terminates the setup procedure. 6. The installation is left incomplete, with downloaded artifacts remaining in the workspace and no successful service verification or cleanup. This issue primarily causes reliability and availability failures. No direct privilege escalation or confidentiality compromise is demonstrated by the reviewed ...[truncated 414 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Group each fallback operation explicitly so that `mv` runs only when the portable fallback is used: ```bash if ! sed -i "s|MIRAGE_BIN_PATH|${MIRAGE_BIN}|g" "${WRAPPER}" 2>/dev/null; then sed "s|MIRAGE_BIN_PATH|${MIRAGE_BIN}|g" "${WRAPPER}" > "${WRAPPER}.tmp" mv "${WRAPPER}.tmp" "${WRAPPER}" fi if ! sed -i "s|MIRAGE_LOG_PATH|${MIRAGE_LOG}|g" "${WRAPPER}" 2>/dev/null; then sed "s|MIRAGE_LOG_PATH|${MIRAGE_LOG}|g" "${WRAPPER}" > "${WRAPPER}.tmp" mv "${WRAPPER}.tmp" "${WRAPPER}" fi ``` Additional hardening should include: 1. Add an `EXIT` trap that removes temporary and partially installed files when setup fails. 2. Generate the final wrapper in a securely created temporary file and atomically rename it only after all substitutions succeed. 3. Run a shell syntax checker and platform-specific installation tests for GNU and BSD/macOS `sed`. 4. Make installation idempotent and verify the final wrapper contents before marking it executable. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (9)

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill clearly instructs the user to execute shell commands and a setup script, yet it declares no tool scope or permissions metadata. That omission weakens reviewability and allows a powerful skill to appear less privileged than it really is, increasing the chance that users or orchestration systems invoke code-executing behavior without adequate scrutiny.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The setup flow tells the user to run a bundled script that downloads a binary, installs persistence helpers, starts a local service, and modifies OpenClaw provider configuration, but the skill does not prominently warn about those system and config changes. In a security-sensitive context, encouraging execution of an opaque installer without clear disclosure materially raises supply-chain and unauthorized-modification risk.

Session Persistence

Medium
Category
Rogue Agent
Content
**Docker entrypoint (recommended):**
```yaml
# docker-compose.yml
command: sh -c "nohup /home/node/.openclaw/workspace/start-mirage.sh > /dev/null 2>&1 & exec openclaw start"
```

**Heartbeat check (fallback):**
Confidence
88% confidence
Finding
The recommended use of nohup to launch a restart script in the background creates session persistence for a network-facing proxy process. Persistence is not inherently malicious, but in an agent skill it is dangerous because it can outlive the initiating session, continue intercepting LLM traffic, and make removal or auditing harder if the binary or configuration is compromised.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
If the downloaded binary fails to run, the installer falls back to fetching and building code directly from a remote Git repository via Cargo. That expands the trust boundary from a pinned release artifact to live repository content and its dependency graph, creating a remote code execution and supply-chain risk during installation. In an installer skill, compiling and executing network-fetched code is materially more dangerous than simply installing a verified release binary.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The script silently starts an infinite-loop wrapper under nohup in the background, causing the proxy to persist beyond the install session without explicit consent at execution time. Persistent background services can alter traffic flow, continue logging data, and be difficult for users to notice or stop, especially for a proxy handling sensitive prompts and secrets.

Session Persistence

Medium
Category
Rogue Agent
Content
chmod +x "${WRAPPER}"

  # Start it
  nohup "${WRAPPER}" > /dev/null 2>&1 &
  sleep 2

  # Verify it's running
Confidence
90% confidence
Finding
Using nohup to launch the wrapper in the background creates session persistence, allowing the proxy to continue intercepting or routing LLM API traffic after the installer exits. Because this skill is specifically a transparent proxy for PII/secrets filtering, persistence increases sensitivity: the process may continue handling confidential data and writing logs without the user's ongoing awareness.

Session Persistence

Medium
Category
Rogue Agent
Content
echo "     (it will read the mirage-proxy skill and patch the config)"
  echo ""
  echo "  2. For persistence across container restarts, add to docker-compose.yml:"
  echo "     command: sh -c \"nohup ${WRAPPER} > /dev/null 2>&1 & exec openclaw start\""
  echo ""
  echo "  3. Switch models:"
  echo "     /model mirage-opus     → Anthropic Opus via mirage"
Confidence
65% 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

Low
Confidence
80% confidence
Finding
The uninstall function removes files from the user's workspace using rm -f, which is a destructive action. While deletion is expected for uninstall behavior, the script does not include an explicit confirmation step or detailed warning immediately before removing those files.

Context-Inappropriate Capability

Low
Confidence
81% confidence
Finding
The manifest focuses on installing and configuring mirage-proxy, but the uninstall logic scans the process table and terminates any processes matching broad name patterns. Process enumeration and killing may be practical for cleanup, but it is a host-control capability not stated in the skill description.

Static analysis

No suspicious patterns detected.