Back to skill

Security audit

Omie ERP

Security checks for vulnerabilities and agentic risk

Overview

This Omie ERP skill appears legitimate, but it needs review because its webhook server is exposed by default and can log sensitive business data.

Review before installing in a real Omie environment. Use least-privilege Omie credentials, avoid exposing the webhook as shipped, bind it locally or place it behind authenticated HTTPS infrastructure, add body limits and request verification, and do not log full ERP webhook payloads.

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
scripts/omie_webhook.py:12
Finding
Webhook Receiver Accepts Unauthenticated Events on All Network Interfaces## Vulnerability Details **File Location**: `scripts/omie_webhook.py`, lines 12-15 and 64-70 **Vulnerability Type**: Unauthenticated webhook endpoint and insecure default network exposure **Risk Level**: High **Vulnerable Code**: ```python def do_POST(self): """Handle POST requests from Omie.""" content_length = int(self.headers.get('Content-Length', 0)) body = self.rfile.read(content_length) ``` ```python def main(): """Start the webhook receiver.""" parser = argparse.ArgumentParser(description='Omie ERP Webhook Receiver') parser.add_argument('--port', type=int, default=8089, help='Port to listen on') parser.add_argument('--host', default='0.0.0.0', help='Host to bind to') args = parser.parse_args() server_address = (args.host, args.port) httpd = HTTPServer(server_address, OmieWebhookHandler) ``` ### Technical Analysis The receiver binds to `0.0.0.0` by default, making it reachable through every network interface permitted by host and firewall configuration. The POST handler accepts JSON without validating a cryptographic signature, shared secret, source identity, request path, timestamp, or unique event identifier. Consequently, any party able to reach the port can construct an arbitrary JSON document, assign any value to its `event` field, and have it treated and logged as a successfully received event. The endpoint returns HTTP 200 after parsing the JSON, regardless of whether the request originated from Omie. The current code only logs received events and does not itself modify ERP records. Nevertheless, fabricated events undermine the integrity of the receiver's logs and could be incorrectly trusted by external log consumers or future downstream integrations. ### Attack Path 1. The operator launches the receiver with its documented defaults. 2. The process binds TCP port 8089 to `0.0.0.0`. 3. An attacker with network access connects to the ...[truncated 876 chars]
Remediation
## Remediation Suggestions 1. Bind to `127.0.0.1` by default and require an explicit option to expose the listener externally. 2. Implement Omie's supported webhook authentication or signature-verification mechanism. Verify the signature over the raw request body before parsing or processing it. 3. If a shared secret is used, store it in an environment variable or secret manager and compare authentication values with a constant-time function such as `hmac.compare_digest`. 4. Validate timestamps and unique event identifiers to reject stale or replayed requests. 5. Restrict requests to a dedicated webhook path and reject unsupported methods, paths, content types, and event types. 6. Place the receiver behind a production HTTPS reverse proxy with firewall rules, rate limiting, and source restrictions where Omie publishes reliable source ranges. 7. Do not regard source-IP filtering as a replacement for cryptographic request authentication.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/omie_webhook.py:12
Finding
Unbounded Webhook Request Reads Permit Denial of Service## Vulnerability Details **File Location**: `scripts/omie_webhook.py`, lines 12-15 and 68-70 **Vulnerability Type**: Unrestricted request-body size and single-threaded resource exhaustion **Risk Level**: Medium **Vulnerable Code**: ```python def do_POST(self): """Handle POST requests from Omie.""" content_length = int(self.headers.get('Content-Length', 0)) body = self.rfile.read(content_length) ``` ```python server_address = (args.host, args.port) httpd = HTTPServer(server_address, OmieWebhookHandler) ``` ### Technical Analysis `Content-Length` is controlled by the remote client and is converted to an integer without validation or an upper bound. The handler then attempts to read that amount of data into memory before parsing it. A very large positive value can cause excessive memory consumption. A negative value is also not rejected and can cause stream-reading behavior inconsistent with a bounded webhook request. The receiver uses Python's single-threaded `HTTPServer` and does not configure a request or socket timeout. A client can therefore declare a body and send it very slowly or incompletely, occupying the only request-handling thread. While that request is blocked, legitimate webhook events cannot be processed. ### Attack Path 1. An attacker obtains network connectivity to the webhook port. 2. The attacker opens an HTTP connection and supplies a very large `Content-Length`, or declares a normal body length and transmits the body extremely slowly. 3. The handler calls `self.rfile.read(content_length)` without a size limit or read timeout. 4. The process allocates resources for the oversized body or blocks while waiting for the remaining bytes. 5. Because `HTTPServer` handles requests serially, legitimate webhook processing is delayed or stopped. 6. Repeated requests can sustain the service disruption or potentially exhaust process memory. ### Impact Assessment A remote attacker can d ...[truncated 395 chars]
Remediation
## Remediation Suggestions 1. Define a conservative maximum webhook-body size appropriate for Omie events. 2. Validate `Content-Length` before reading and return HTTP 411 when it is required but missing, HTTP 400 when it is malformed or negative, and HTTP 413 when it exceeds the configured limit. 3. Read the request incrementally with a strict cumulative byte limit rather than relying solely on the declared length. 4. Configure connection, header, and body-read timeouts. 5. Deploy behind a production HTTP server or reverse proxy that enforces body-size limits, request timeouts, connection limits, and rate limits. 6. Use a concurrency model with bounded workers so one slow request cannot block every legitimate event. 7. Add tests covering oversized, negative, malformed, incomplete, and slowly transmitted request bodies.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/omie_webhook.py:20
Finding
Complete ERP Webhook Payloads Are Written to Application Logs## Vulnerability Details **File Location**: `scripts/omie_webhook.py`, lines 20-30 **Vulnerability Type**: Sensitive information exposure through logging **Risk Level**: Medium **Vulnerable Code**: ```python payload = json.loads(body.decode('utf-8')) event_type = payload.get('event', 'unknown') timestamp = datetime.now().isoformat() # Log event log_entry = { "timestamp": timestamp, "event": event_type, "data": payload } print(json.dumps(log_entry, indent=2, ensure_ascii=False), file=sys.stderr) ``` ### Technical Analysis The complete parsed webhook payload is placed in the `data` field and printed to stderr without filtering or redaction. Events involving customers, invoices, orders, and financial transactions may contain personally identifiable information, tax identifiers, commercial information, or payment-related business data. In common deployments, stderr is captured by a process supervisor, container runtime, CI service, or centralized logging platform. Such logs may have broader access permissions and longer retention periods than the ERP source data. The unauthenticated nature of the webhook endpoint also permits remote users to insert arbitrary payload content into these logs, increasing log volume and contaminating audit records. ### Attack Path 1. Omie sends a legitimate webhook containing customer, fiscal, order, or financial details, or an attacker submits arbitrary JSON to the exposed endpoint. 2. The handler parses the entire document. 3. The unmodified payload is embedded in `log_entry`. 4. The complete entry is printed to stderr. 5. The runtime or operating environment captures and retains stderr. 6. Users or systems with access to those logs can view data that was not necessary for operational logging. ### Impact Assessment Sensitive ERP and customer information may be exposed to administrators, support personnel, log-aggregation services, backups, or other prin ...[truncated 380 chars]
Remediation
## Remediation Suggestions 1. Do not log complete webhook bodies by default. 2. Log only operational metadata such as a validated event type, event identifier, receipt timestamp, processing result, and correlation identifier. 3. Create an explicit allowlist of fields that may be logged; redact, omit, or irreversibly hash personal, tax, financial, authentication, and free-form data. 4. Use structured logging configured to escape untrusted values and cap field lengths. 5. Apply least-privilege access controls to log storage and encrypt logs in transit and at rest. 6. Establish retention and deletion periods appropriate for sensitive ERP metadata. 7. Add automated tests that submit representative sensitive fields and verify that they never appear in emitted logs.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 (7)

Tainted flow: 'req' from os.environ.get (line 25, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
)

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            return json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        body = e.read().decode("utf-8", errors="replace")
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 code clearly matches much of the declared Omie ERP domain: it accesses Omie API endpoints for clients, products, orders, invoices, financials, and stock. However, the description overstates capabilities in two material ways. First, it claims webhook handling for real-time events, but the supplied code contains no webhook server, listener, trigger handling, or event processing. Second, it says 'manage' clients, products, orders, invoices, financials, and stock, which implies broader CRUD or operational actions; the actual code is limited to retrieval functions (list, search, consult, status) plus a CLI wrapper. Since these are material capability differences rather than minor implementation details, this should be flagged as a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The code chunk’s actual function is narrowly limited to receiving webhook POST requests, parsing JSON, logging the event, and acknowledging receipt. While the description mentions webhook handling, its primary claim is a full Omie ERP API integration for managing multiple business objects and financial workflows. None of those capabilities appear in the code: there are no outbound API calls, authentication, CRUD operations, ERP queries, or stock/financial/order handling. Therefore the description materially overstates the implemented behavior, making it a mismatch.

Lp3

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding
The skill documents use of environment variables and networked API/webhook operations, but it declares no explicit tool scope or permission boundaries. In an agent setting, missing scope declarations can cause the skill to be invoked with broader-than-necessary access, increasing the chance of unintended secret exposure or unauthorized outbound requests.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The trigger description is very broad for ERP, financial, order, invoice, stock, and client-related requests, which can cause the skill to activate on many ordinary prompts involving sensitive business data. In a context backed by live ERP credentials, overbroad routing increases the chance of unnecessary data access, disclosure, or execution in situations where a narrower skill should not run.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The documentation instructs operators to provide sensitive API credentials via environment variables but gives no warning about secret handling, logging, redaction, or least-privilege practices. In an agent environment, this increases the risk that credentials are mishandled, exposed in transcripts, shell history, debugging output, or reused insecurely across tasks.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This code file performs outbound HTTP POST requests to the Omie API and includes both environment-sourced credentials and user/system query parameters in the request payload. While network access is central to the client's purpose, there is no confirmation prompt, user-facing notice, or warning that potentially sensitive ERP/customer/financial data will be transmitted to an external service.

Static analysis

No suspicious patterns detected.