Back to skill

Security audit

Openclaw Skill for Odoo

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real Odoo ERP connector, but its broad live-business write powers and unsafe network defaults need Review before installation.

Install only if you are prepared to grant live Odoo access. Use a dedicated least-privilege Odoo API user, require HTTPS for any non-local server, avoid production until tested on staging, set a strong webhook secret and bind webhooks to localhost or a protected interface, and treat smart actions as write-capable automation that can create or change real business records.

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

T09 · Insecure Skill Coding Practices

Error
Location
odoo_skill/config.py:61
Finding

Odoo API Keys Can Be Transmitted over Plaintext HTTP

Content
View full analysis
xmlrpc.client.ServerProxy: """``/xmlrpc/2/common`` endpoint (lazy, cached).""" if self._common is None: self._common = xmlrpc.client.ServerProxy( f"{self.config.url}/xmlrpc/2/common", allow_none=True, ) return self._common @property def models(self) -> xmlrpc.client.ServerProxy: """``/xmlrpc/2/object`` endpoint (lazy, cached).""" if self._models is None: self._models = xmlrpc.client.ServerProxy( f"{self.config.url}/xmlrpc/2/object", allow_none=True, ) return self._models ``` `odoo_skill/client.py:128-134`: ```python uid = self.common.authenticate( self.config.db, self.config.username, self.config.api_key, {}, ) ``` `odoo_skill/client.py:174-182`: ```python return self.models.execute_kw( self.config.db, self.uid, self.config.api_key, model, method, list(args), kwargs if kwargs else {}, ) ``` ### Technical Analysis Configuration validation explicitly accepts both `http://` and `https://` URLs. The resulting URL is used directly to construct XML-RPC endpoints. Both authentication and every authenticated model operation include the reusable Odoo API key in the XML-RPC request. When a non-loopback HTTP endpoint is configured, transport encryption and server authentica ...[truncated 1894 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
odoo_skill/sync/webhook.py:116
Finding

Webhook Server Is Publicly Exposed and Unauthenticated by Default

Content
View full analysis
None: self.port = port self.host = host self.secret = secret ``` `odoo_skill/sync/webhook.py:153-166`: ```python def start(self) -> None: """Start the webhook server in a background thread.""" # Inject config into the handler class _WebhookHandler.webhook_secret = self.secret _WebhookHandler.callbacks = self._callbacks _WebhookHandler.default_callback = self._default_callback self._server = HTTPServer((self.host, self.port), _WebhookHandler) self._thread = threading.Thread( target=self._server.serve_forever, name="odoo-webhook", daemon=True, ) self._thread.start() logger.info("Webhook server listening on %s:%d", self.host, self.port) ``` ### Technical Analysis The webhook server ...[truncated 2360 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
odoo_skill/sync/webhook.py:36
Finding

Unbounded Webhook Request Body Enables Remote Denial of Service

Content
View full analysis
None: """Handle an incoming webhook POST request.""" content_length = int(self.headers.get("Content-Length", 0)) if content_length == 0: self._respond(400, {"error": "Empty body"}) return body = self.rfile.read(content_length) ``` ### Technical Analysis The handler converts the attacker-controlled `Content-Length` header directly to an integer and passes that value to `read()` without imposing a maximum request size. It also does not handle malformed integer input. A client can declare an extremely large body and transmit it slowly, causing the single-threaded `HTTPServer` to remain blocked while waiting for data. If the body is supplied, the server can consume excessive memory while reading and parsing it. A nonnumeric header can raise an uncaught `ValueError`. The use of the single-threaded standard-library `HTTPServer` increases the availability impact because one blocked request prevents legitimate requests from being processed concurrently. ### Attack Path 1. An attacker connects to the webhook port. 2. The attacker sends a very large `Content-Length`, or declares a large length and transmits the body very slowly. 3. The handler calls `self.rfile.read(content_length)` with no maximum size or read deadline. 4. The webhook thread blocks or consumes excessive memory. 5. Because the server is single-threaded, legitimate webhook and health-check requests cannot be serviced while the malicious request is active. 6. Repeated requests sustain service disruption. A malformed `Content-Length` can additionally trigger an uncaught parsing exception. ### Impact Assessment No additional system or Odoo privileges are directly gained. The primary impact is availabilit ...[truncated 556 chars]
Remediation
View remediation
MAX_BODY_SIZE: self._respond(413, {"error": "Request body too large"}) return ``` 2. Configure socket read timeouts to mitigate slow-body attacks. 3. Reject transfer modes the implementation does not explicitly support. 4. Consider a hardened production HTTP server or reverse proxy that enforces body-size, connection, and rate limits. 5. Apply per-source rate limiting and connection limits. 6. Authenticate at a reverse proxy before requests reach the Python handler where practical. 7. Keep request-size enforcement before reading the body and before performing JSON parsing or callback dispatch. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (35)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 74)May include surrounding context.

md
1. Log in to Odoo
2. Go to **Settings** → **Users & Companies** → **Users**
3. Open your user record
4. Scroll to **Access Tokens**
5. Click **Generate**
6. Copy the key into `config.json`

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 275)May include surrounding context.

md
1. Log in to Odoo
2. Go to **Settings** → **Users & Companies** → **Users**
3. Open your user record
4. Scroll to **Access Tokens**
5. Click **Generate**
6. Copy the key into `config.json`

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

If the underlying implementation includes webhook handling or an HTTP server not reflected in the description, that introduces hidden network-facing attack surface. Undocumented inbound listeners and callback processing can materially change the threat model, especially when paired with business-system credentials.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

If the underlying implementation includes webhook handling or an HTTP server not reflected in the description, that introduces hidden network-facing attack surface. Undocumented inbound listeners and callback processing can materially change the threat model, especially when paired with business-system credentials.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

If the underlying implementation includes webhook handling or an HTTP server not reflected in the description, that introduces hidden network-facing attack surface. Undocumented inbound listeners and callback processing can materially change the threat model, especially when paired with business-system credentials.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · requirements.txt (reported line 6)May include surrounding context.

text
# json — built-in Python
# http.server — built-in Python

# Optional: for .env file support
python-dotenv>=1.0.0

# Testing

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README advertises broad natural-language create/update actions and 'smart actions' that auto-create customers and products, but it does not prominently warn users that these commands can modify live ERP data. In an ERP context, ambiguous chat inputs can trigger irreversible business changes, accidental record creation, inventory/accounting corruption, or unauthorized operational actions if users misunderstand the automation scope.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill advertises capabilities that imply access to environment variables, filesystem, and network, but it does not declare any explicit tool scope or allowed-tools restrictions. In an agent setting, missing scope boundaries increases the chance the runtime grants broader access than users expect, enabling configuration reads, credential exposure, or unintended data modification.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
93% confidence
Finding

Using npx clawhub without pinning an exact version makes installation non-reproducible and exposes users to supply-chain risk if a newer or compromised package is published. This is especially risky for a skill that claims broad ERP access and may handle credentials and sensitive business records.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Automatic find-or-create behavior with fuzzy matching can silently create incorrect customers, products, projects, or employees when names are ambiguous or mistyped. In an ERP environment, that can corrupt master data, trigger downstream transactions against the wrong entity, and be abused through prompt-driven unintended record creation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill describes broad create, update, and potentially delete capabilities across sensitive ERP domains without clear user warnings about destructive or business-critical actions. In this context, the connector can affect orders, invoices, employees, inventory, and other production records, so under-warning materially increases the risk of accidental or unauthorized operational harm.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The create_lead and create_opportunity methods send contact and commercial data such as names, email addresses, phone numbers, partner IDs, and revenue estimates to the Odoo backend via client.create. While the code logs that a record was created, it does not provide any user-facing disclosure, confirmation prompt, or warning in the docstrings/comments that personal and business data will be transmitted and stored remotely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The move_stage, mark_won, and mark_lost methods modify remote CRM records, and mark_lost deactivates the record by setting active to False. Although there are logger.info entries, this file lacks user-facing disclosure or confirmation that these actions will change pipeline state and can have irreversible business impact, especially for marking records lost.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The module docstring explicitly describes the functionality as providing read-only access, but the implementation includes write operations that publish and unpublish products via product.template writes. This mismatch can mislead reviewers, downstream agents, or policy controls into granting the module broader trust than warranted, increasing the chance of unintended inventory or storefront changes in an ERP environment.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The method documentation implies a safe archival action, but the code attempts permanent deletion first and only archives on failure. In an ERP context, callers may invoke this method expecting reversible deactivation, but instead destroy customer records and related business data where Odoo permits unlink, causing integrity, audit, and availability issues.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code updates task assignments and stages via self.client.write(...), which changes remote project data. Although internal logging is present, there is no confirmation prompt or explicit user-facing disclosure in the method docs/comments warning that these operations modify live Odoo records.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The log_timesheet method creates a new account.analytic.line entry, which is a persistent business record that may affect billing or reporting. The docstring describes the operation, but it does not clearly warn users that invoking it records time in the live system and may have downstream business impact.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The method automatically writes inventory-affecting quantities to stock moves and validates incoming pickings, which can change stock state in Odoo without any explicit confirmation step, dry-run mode, or strong warning in the API contract. In an agent context, a caller may reasonably treat this as a read-like helper for receipts, but it performs irreversible business workflow actions that can corrupt inventory records, trigger downstream accounting/logistics effects, and increase the blast radius of prompt mistakes or unauthorized tool use.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The helper silently creates persistent ERP records when a fuzzy lookup misses, which turns an ambiguous read-like user request into a write operation. In an agent context, this can cause unintended partner/product creation, data pollution, and unauthorized business state changes if the caller did not explicitly approve writes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

Creating a quotation here can also auto-create customers and products as side effects, so a natural-language sales request may perform multiple persistent writes without explicit acknowledgement. In ERP systems, this is risky because small prompt ambiguities can generate bogus master data and downstream commercial documents.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Invoice creation is a sensitive financial operation, and this workflow can both create accounting records and optionally create products/partners without a separate confirmation boundary. If triggered unintentionally or through ambiguous input, it may produce financial documents that affect revenue reporting, receivables, and audit trails.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This purchase-order flow can create vendors, create products, and update supplier status on existing partners, all as implicit side effects of a fuzzy request. Because procurement actions can affect vendor master data and purchasing commitments, accidental execution can have significant operational and financial consequences.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The employee workflow can create employee and department records automatically based on fuzzy matching, which is a persistent HR data mutation. In enterprise contexts this is sensitive because incorrect HR identities or departments can affect access control, reporting, org structure, and compliance processes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This webhook receiver accepts inbound POST requests even when no shared secret is configured, because signature verification is only enforced if self.webhook_secret is non-empty. In that state, any party that can reach the listening socket can send arbitrary events and payloads to registered callbacks, which may trigger business actions in the ERP integration. In an Odoo connector context, that makes unauthenticated event injection materially dangerous rather than a theoretical issue.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.