Back to skill

Security audit

Manus AI Skill for OpenClaw

Security checks for vulnerabilities and agentic risk

Overview

The skill is a mostly coherent Manus API integration, but it exposes broad remote-agent, file-upload, connector, and webhook capabilities without enough scoping or safety controls.

Install only if you intend to use Manus as a remote autonomous service. Do not upload secrets or sensitive documents unless you accept sending them to Manus, use least-privilege/test connector accounts where possible, review prompts before asking it to act in Gmail/Slack/Calendar/Notion, and avoid exposing the webhook server publicly without authentication and request limits.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/webhook_server.py:38
Finding
Publicly Exposed Webhook Receiver Lacks Authentication and Request-Size Limits## Vulnerability Details **File Location**: `scripts/webhook_server.py`, lines 38–59 and line 174 **Vulnerability Type**: Unauthenticated webhook processing and unbounded request-body handling **Risk Level**: Medium ### Vulnerable Code ```python def do_POST(self): """Handle webhook POST requests.""" if self.path == "/webhook/manus": content_length = int(self.headers.get("Content-Length", 0)) body = self.rfile.read(content_length) try: data = json.loads(body.decode("utf-8")) self.handle_manus_webhook(data) self.send_response(200) self.send_header("Content-Type", "application/json") self.end_headers() self.wfile.write(b'{"status": "ok"}') except Exception as e: print(f"❌ Error processing webhook: {e}") self.send_response(400) self.end_headers() else: self.send_response(404) self.end_headers() ``` ```python server = HTTPServer(("0.0.0.0", args.port), WebhookHandler) ``` ### Technical Analysis The HTTP server binds to `0.0.0.0`, making it reachable through every available network interface unless external firewall rules prevent access. The webhook endpoint accepts JSON events without verifying a cryptographic webhook signature, shared secret, timestamp, source identity, or other proof that the request originated from Manus. The handler also converts the attacker-controlled `Content-Length` header to an integer and passes it directly to `self.rfile.read()` without enforcing a maximum request size. This permits excessive memory consumption and allows clients to hold the single-threaded server while slowly transmitting a declared request body. Attacker-controlled event fields—including task identifiers, titles, and error messages—are printed to the terminal without sanitizing control characters ...[truncated 1514 chars]
Remediation
## Remediation Suggestions 1. Bind to `127.0.0.1` by default. Require an explicit command-line option to listen on public or non-loopback interfaces. 2. Verify the webhook provider's cryptographic signature over the raw request body. Reject requests with missing, malformed, stale, or invalid signatures, and use constant-time comparison where applicable. 3. Add replay protection by validating a signed timestamp and rejecting events outside a short permitted time window. Track event identifiers if the provider supports them. 4. Enforce a small maximum request-body size before calling `read()`. Return HTTP `413 Payload Too Large` when the declared size exceeds the limit. 5. Configure connection and read timeouts. Consider a hardened, concurrent production HTTP server when public exposure is required. 6. Require an appropriate JSON `Content-Type` and validate the event payload against a strict schema before processing it. 7. Sanitize carriage returns, newlines, escape sequences, and other terminal-control characters before printing remote fields. 8. Place any externally reachable deployment behind a TLS-enabled reverse proxy with firewall rules, rate limiting, and request-size limits.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (43)

Tainted flow: 'headers' from os.environ.get (line 28, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
"description": description
    }
    
    response = requests.post(url, json=data, headers=headers)
    
    if response.status_code != 200:
        print(f"❌ Error: {response.text}")
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'headers' from os.environ.get (line 28, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
"API_KEY": api_key
    }
    
    response = requests.get(url, headers=headers)
    
    if response.status_code != 200:
        print(f"❌ Error: {response.text}")
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'headers' from os.environ.get (line 28, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
"API_KEY": api_key
    }
    
    response = requests.get(url, headers=headers)
    
    if response.status_code != 200:
        print(f"❌ Error: {response.text}")
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'headers' from os.environ.get (line 64, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
if title:
        data["title"] = title
    
    response = requests.post(url, json=data, headers=headers)
    
    if response.status_code != 200:
        print(f"❌ Error creating task: {response.text}")
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'headers' from os.environ.get (line 64, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
"API_KEY": api_key
    }
    
    response = requests.get(url, headers=headers)
    
    if response.status_code != 200:
        print(f"❌ Error getting task: {response.text}")
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'headers' from os.environ.get (line 32, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
with open(file_path, "rb") as f:
        files = {"file": (os.path.basename(file_path), f)}
        response = requests.post(url, files=files, headers=headers)
    
    if response.status_code != 200:
        print(f"❌ Error uploading: {response.text}")
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'headers' from os.environ.get (line 106, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
]
    }
    
    response = requests.post(url, json=data, headers=headers)
    
    if response.status_code != 200:
        print(f"❌ Error registering webhook: {response.text}")
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The description claims a general-purpose autonomous Manus AI agent with expansive capabilities, but the provided code only implements a narrow status-checking script for existing Manus tasks. It fetches an API key, calls the Manus tasks endpoint, and displays task metadata. This is a materially different primary purpose from the declared agent capabilities, so the description does not accurately represent the code.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description presents a broad autonomous AI agent with research, development, automation, and media-generation capabilities. The supplied code instead implements a narrow utility script whose sole purpose is to create a Manus project through the Manus REST API using an API key from environment variables or a local config file. This is a materially different primary purpose and includes concrete external API/project-management behavior not reflected in the description. Therefore, the description does not accurately represent the code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The description claims a broad autonomous Manus AI agent with multiple high-level capabilities, but the provided code only implements a narrow result-retrieval script. Its primary purpose is to look up a Manus task by ID, using an API key from an environment variable or local config file, then print extracted assistant text and metadata. It does not perform autonomous task execution, research, development, automation, or media generation itself. The code also accesses local configuration and the Manus API, which are operational details not reflected in the declared purpose. This is a material description-to-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description presents a broad autonomous AI agent with research, development, automation, and media-generation capabilities. The supplied code does not implement those agent behaviors; it is a narrow helper script whose sole purpose is uploading a local file to Manus via HTTP. It accesses local filesystem paths, reads credentials from environment variables and a local config file, and sends file contents to an external API. Those are materially different concrete behaviors from the declared purpose, so this is a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
La descripción declarada presenta un agente de IA autónomo de propósito amplio con capacidades de investigación, desarrollo, automatización y generación de medios. Sin embargo, este fragmento no implementa ninguna de esas capacidades principales. Su función real es mucho más específica e infraestructural: abrir un servidor HTTP en 0.0.0.0, aceptar POST en /webhook/manus, procesar eventos task.created/task.completed/task.failed y, opcionalmente, registrar el webhook usando una API key. Esto constituye un propósito materialmente distinto y añade capacidades de red/recepción de eventos no reflejadas en la descripción. Aunque esté relacionado con Manus, la descripción no representa con precisión este comportamiento concreto.

Credential Access

High
Category
Privilege Escalation
Content
DEFAULT_TIMEOUT = 120  # seconds

def get_api_key():
    """Get API key from environment or config."""
    api_key = os.environ.get("MANUS_API_KEY")
    
    # Try to read from config file
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The README encourages use of Gmail, Notion, Google Calendar, and Slack actions that can read or modify third-party account data, but it does not warn users that these operations may access private content or create external side effects. In an autonomous agent skill, this omission is risky because users may invoke actions without understanding privacy exposure or account-impact consequences.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The file upload section tells users to upload local files for context but does not clearly disclose that file contents will be transmitted to the external Manus service. Because this skill is designed for autonomous research and analysis, users may inadvertently send sensitive local documents, credentials, or proprietary data off-system.

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill declares access to environment variables and external network services but does not define an explicit permission or allowed-tools scope. For a skill that can read API keys and send prompts, files, and task data to a remote service, this weakens reviewability and can enable over-broad use beyond what a user may expect.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill advertises internet access and actions through authenticated connectors but does not clearly warn users that prompts, retrieved data, and account content may be transmitted to or acted on by an external service. In this context, the omission increases the chance of accidental disclosure of sensitive emails, documents, calendar data, or internal messages.

External Transmission

Medium
Category
Data Exfiltration
Content
| Endpoint | Descripción |
|----------|-------------|
| `https://api.manus.ai/v1/tasks` | Crear y gestionar tareas |
| `https://api.manus.ai/v1/projects` | Gestión de proyectos |
| `https://api.manus.ai/v1/files` | Subir archivos |
| `https://api.manus.ai/v1/webhooks` | Webhooks para notificaciones |
Confidence
91% confidence
Finding
The skill explicitly sends task data to an external API endpoint. In this skill context, prompts may contain sensitive business data and can be combined with authenticated-service actions, so external transmission is security-relevant and should be treated as a real data-exposure surface.

External Transmission

Medium
Category
Data Exfiltration
Content
| Endpoint | Descripción |
|----------|-------------|
| `https://api.manus.ai/v1/tasks` | Crear y gestionar tareas |
| `https://api.manus.ai/v1/projects` | Gestión de proyectos |
| `https://api.manus.ai/v1/files` | Subir archivos |
| `https://api.manus.ai/v1/webhooks` | Webhooks para notificaciones |
Confidence
90% confidence
Finding
Project-management requests are transmitted to the external Manus projects endpoint using stored credentials. This creates a real external control and data-flow surface, especially if project names/descriptions include confidential information or trigger actions in a linked remote environment.

External Transmission

Medium
Category
Data Exfiltration
Content
|----------|-------------|
| `https://api.manus.ai/v1/tasks` | Crear y gestionar tareas |
| `https://api.manus.ai/v1/projects` | Gestión de proyectos |
| `https://api.manus.ai/v1/files` | Subir archivos |
| `https://api.manus.ai/v1/webhooks` | Webhooks para notificaciones |

## Uso Básico
Confidence
97% confidence
Finding
The files endpoint is a concrete exfiltration channel because local file contents are uploaded to an external service. Given the skill's stated workflow around context files and analysis, users may unintentionally transmit proprietary, personal, or secret material.

External Transmission

Medium
Category
Data Exfiltration
Content
| `https://api.manus.ai/v1/tasks` | Crear y gestionar tareas |
| `https://api.manus.ai/v1/projects` | Gestión de proyectos |
| `https://api.manus.ai/v1/files` | Subir archivos |
| `https://api.manus.ai/v1/webhooks` | Webhooks para notificaciones |

## Uso Básico
Confidence
89% confidence
Finding
Webhook registration involves transmitting endpoint information and enabling asynchronous callbacks with an external service. In this skill context, that increases exposure by linking a local or user-controlled endpoint to remote events, which can reveal metadata and open a network-reachable integration surface.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The Gmail, Slack, Notion, and Calendar examples encourage actions against authenticated services without explicit notice that the skill may read from or modify those connected accounts. In a skill with broad automation claims, this can mislead users into exposing sensitive organizational data or triggering unintended side effects in production accounts.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The upload_file documentation tells users to send local files to the Manus API without warning that file contents leave the local environment and are transmitted to a third party. This is dangerous because users may upload secrets, internal documents, or regulated data under the assumption they remain local.

External Transmission

Medium
Category
Data Exfiltration
Content
client = OpenAI(
    api_key="sk-...",  # Tu API key de Manus
    base_url="https://api.manus.ai/v1"
)

response = client.chat.completions.create(
Confidence
90% confidence
Finding
The OpenAI-compatible example shows chat completion content being sent to Manus via a custom base_url. This is a real external transmission path and can be mistaken for local model use unless the docs make the remote destination and data-sharing implications explicit.

External Transmission

Medium
Category
Data Exfiltration
Content
Las tareas consumen créditos. Ver uso con:

```bash
curl "https://api.manus.ai/v1/usage" \
  -H "API_KEY: sk-..."
```
Confidence
82% confidence
Finding
The usage-check curl command sends account-authenticated requests to an external endpoint. The risk is lower than file upload or connector actions, but it still involves remote disclosure of account usage metadata and demonstrates use of sensitive credentials in command examples.

Static analysis

No suspicious patterns detected.