Back to skill

Security audit

drivethru-operations

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed Odoo operations skill that can read and change live ERP data, with notable setup hardening issues but no evidence of deception or malicious behavior.

Install only in an environment where the Odoo MCP token is narrowly scoped and the endpoint configuration is administrator-controlled, HTTPS, and trusted. Treat the skill as capable of live ERP changes, including purchase orders, stock transfers, and vendor bills, and require explicit human approval for write workflows.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/odoo_mcp.py:48
Finding

Bearer credential can be transmitted to an untrusted or plaintext endpoint

Content
View full analysis

Vulnerability Details

File Location: scripts/odoo_mcp.py:48-69
Vulnerability Type: Missing endpoint and transport validation for sensitive credential transmission
Risk Level: High

Vulnerable Code

python
def _config():
    url = (os.environ.get("ODOO_MCP_URL") or "").strip()
    token = (os.environ.get("ODOO_MCP_TOKEN") or "").strip()
    return url, token


async def _with_session(url: str, headers: dict, fn):
    async with streamablehttp_client(url, headers=headers) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            return await fn(session)


async def _run(fn) -> int:
    url, token = _config()
    if not url or not token:
        return _fail(
            "config_error",
            "Set ODOO_MCP_URL and ODOO_MCP_TOKEN before using this skill.",
            code=2,
        )
    headers = {"Authorization": f"Bearer {token}"}
    try:

The associated configuration documentation at SKILL.md:16-24 confirms that the URL is externally configurable and that the secret is sent as a Bearer token:

yaml
ODOO_MCP_URL:
  required: true
  description: >
    Full URL of the Odoo MCP endpoint, e.g.
    `https://odoo.example.com/drivethru_mcp/v1` (the MCP server exposed by
    the `drivethru_mcp` Odoo module, not the Odoo base URL).
ODOO_MCP_TOKEN:
  required: true
  description: >
    The `drivethru.mcp_key` value from the Odoo `drivethru_mcp` module,
    sent as `Authorization: Bearer`. Treat as a secret; never paste into
    chat.

Technical Analysis

The client accepts ODOO_MCP_URL as an arbitrary string and sends the static Odoo MCP token to that URL in the Authorization header. It does not independently enforce HTTPS, validate the expected hostname, reject embedded URL credentials, or restrict loopback, link-local, and other unexpected destinations.

Sending a credential to the configured Odoo MCP endpoint is necessary for the Skill's declare ...[truncated 1937 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse the URL with a standard URL parser and reject malformed URLs.
  2. Require the https scheme in production; permit HTTP only behind an explicit development-only option.
  3. Reject URLs containing embedded usernames or passwords.
  4. Enforce an administrator-controlled hostname allowlist or bind the expected endpoint host separately from user-controlled task input.
  5. Resolve and reject loopback, link-local, multicast, and private destinations unless an administrator explicitly permits the required internal Odoo host.
  6. Ensure redirects cannot forward the Authorization header to a different origin.
  7. Use normal TLS certificate verification and provide certificate or public-key pinning where the deployment model supports it.
  8. Replace broadly privileged static credentials with narrowly scoped, revocable, and regularly rotated tokens.
  9. Restrict who can modify the Skill's environment and endpoint configuration.
  10. Add tests confirming rejection of http://, embedded credentials, unexpected hosts, and unsafe redirect destinations.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:26
Finding

Security-sensitive MCP dependency is not reproducibly pinned

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:26-28
Vulnerability Type: Open-ended third-party dependency version
Risk Level: Medium

Vulnerable Code

yaml
install:
  uv:
    - mcp>=1.9.0

Technical Analysis

The Skill permits any installed mcp release at or above version 1.9.0. This package executes inside the Skill's process and handles a sensitive Bearer credential, HTTP transport, session initialization, and remote tool invocation.

An open-ended lower-bound constraint does not provide reproducible installation. A future compromised, malicious, or behaviorally incompatible release could be selected without any modification to this audited project. No lockfile or package hash is present in the reviewed project structure to constrain the resolved artifact.

This finding concerns supply-chain hardening. The audit found no evidence that the currently referenced package name is itself malicious or typosquatted.

Attack Path

  1. A malicious or compromised future version of the mcp package becomes available through the configured package index, or dependency resolution otherwise selects an unsafe later release.
  2. The Skill is installed or rebuilt after that release is available.
  3. The mcp>=1.9.0 constraint accepts the unsafe version.
  4. scripts/odoo_mcp.py imports and executes the selected package:
    • from mcp import ClientSession
    • from mcp.client.streamable_http import streamablehttp_client
  5. Malicious dependency code executes in the Skill's process and can potentially read environment variables, intercept the Odoo token, alter destinations or requests, falsify responses, or perform actions with the process's local permissions.

Impact Assessment

A compromised dependency could obtain the ODOO_MCP_TOKEN and any Odoo business data processed by the client. It would also execute with the operating-system privileges of the Skill process and could tamper with MCP requests or responses.

The practical impac ...[truncated 241 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin mcp to an exact version that has been tested and reviewed, rather than using an unrestricted upper range.
  2. Commit a lockfile generated by the selected package-management workflow.
  3. Verify package artifacts with cryptographic hashes where supported.
  4. Use a trusted package index and disable unneeded fallback indexes to reduce dependency-confusion exposure.
  5. Review transitive dependencies and include them in automated vulnerability and provenance scanning.
  6. Update dependencies through explicit, reviewed changes rather than resolving arbitrary future versions during installation.
  7. Run the client in a minimally privileged environment with access only to the required token and network destination, limiting the impact of a compromised dependency.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill exposes environment-backed network access to an MCP server but does not declare any explicit tool scope or allowed-tools boundary. In practice, that leaves the runtime to infer broad capability from the manifest and instructions, increasing the chance the skill can invoke more tools than reviewers or callers expect.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The invocation criteria are extremely broad, covering many common ERP and logistics topics and encouraging use inside Odoo Discuss conversations. That can over-trigger the skill in ambiguous contexts and route requests into a privileged operations agent when a narrower or read-only tool would suffice, raising the risk of unintended access or action.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
`ODOO_MCP_URL` and `ODOO_MCP_TOKEN` must be in the environment. If either is
missing the script exits with `{"error": {"type": "config_error", ...}}` (exit
2) — stop and tell the user to configure them. Never ask the user to paste the
key into chat.

## The operations query surface — `ops_*`

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The file says there is exactly one way to touch Odoo, but later documents multiple additional read and write tool families. This contradiction can cause operators or downstream agents to misunderstand the true execution surface, undermining safe-use assumptions and making unauthorized or accidental writes more likely.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill is presented as an operations agent for purchasing→manufacturing→shipping, but it also documents accounts-payable capabilities including PO line updates and vendor-bill creation. That mismatch can mislead users, reviewers, and orchestration logic into granting or invoking financial write actions under a broader operational pretext, creating a scope-expansion risk.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · references/query_patterns.md (reported line 246)May include surrounding context.

md
compares `qty_received` to the *string* `"product_qty"`, not the column. Use
  `receipt_status` or an aggregate-and-subtract.
- **A guessed field name.** `product_type` (doesn't exist — use `product_id.type`);
  an assumed `purchase_order_id` / `status` on `vendor.tracking` without checking.
  Confirm with `ops_list_model_fields` first.
- **A number from memory.** Restating a prior count, or "it should be the same,"
  without re-running the query and reading the fresh `total_matched`.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The manifest describes an internal operations agent for ERP purchasing/manufacturing/shipping tasks and enumerates operational models and workflows. L182 expands behavior to searching internal SOPs and policies through knowledge_* tools, which is outside the manifest's operational domain description.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.