Back to skill

Security audit

Shopify Runtime

Security checks for vulnerabilities and agentic risk

Overview

This Shopify skill is mostly coherent, but it exposes live store credentials and local runtime access in ways that need careful review before use.

Install only in a tightly controlled environment with least-privilege Shopify app scopes, a verified *.myshopify.com store domain, and no unrelated secrets in the runtime environment. Avoid letting autonomous or untrusted prompts supply execute scripts, and treat raw response output as sensitive customer or order data.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
lib/shopify-provider.mjs:27
Finding

Shopify Client Credentials Can Be Sent to an Attacker-Controlled Host

Content
View full analysis
{ const storeDomain = readString(connection.storeDomain) const clientId = readString(connection.clientId) const apiKey = readString(connection.apiKey) const apiVersion = readString(connection.apiVersion) if (!storeDomain || !clientId || !apiKey) { return undefined } return { storeDomain, clientId, apiKey, apiVersion, } } const getShopifyAccessToken = async (connection, signal) => { const response = await fetch(`https://${connection.storeDomain}/admin/oauth/access_token`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: new URLSearchParams({ grant_type: "client_credentials", client_id: connection.clientId, client_secret: connection.apiKey, }).toString(), signal, }) ``` ```js validateConnection(connection) { return normalizeConnection(connection) ? { ok: true } : { ok: false, reason: "Set SHOPIFY_STORE_DOMAIN, SHOPIFY_CLIENT_ID, and configure this skill's apiKey so OpenClaw can inject SHOPIFY_CLIENT_SECRET.", } }, ``` ### Technical Analysis The Skill declares that `SHOPIFY_STORE_DOMAIN` should identify a Shopify `*.myshopify.com` store. However, `normalizeConnection()` and `validateConnection()` only require the value to be a non-empty string. They do not verify that it is a Shopify-controlled hostname. `getShopifyAccessToken()` interpolates this unvalidated value directly into the token endpoint and sends both `SHOPIFY_CLIENT_ID` and `SHOPIFY_CLIENT_SECRET` in the request body. HTTPS protects the request in transit, but it does not ensure that the destination is Shopify. If configuration is m ...[truncated 1641 chars]
Remediation
View remediation
{ const hostname = readString(value)?.toLowerCase() if ( !hostname || hostname.includes("/") || hostname.includes("@") || hostname.includes(":") || !/^[a-z0-9][a-z0-9-]*\.myshopify\.com$/u.test(hostname) ) { return undefined } return hostname } ``` For stronger control, validate the normalized hostname against the exact store domain configured by a trusted administrator. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
lib/runtime.mjs:360
Finding

Host-Realm Functions Exposed to an Untrusted Node.js VM Permit Sandbox Escape

Content
View full analysis
{ logs.push(serializeLogArgs(args)) }, error: (...args) => { logs.push(serializeLogArgs(args)) }, }), }), AbortController: undefined, Buffer: undefined, process: undefined, globalThis: undefined, require: undefined, fetch: undefined, module: undefined, exports: undefined, }, { ...[truncated 3588 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (11)

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 48)May include surrounding context.

md
Status output intentionally exposes only safe connection details. Secret values are never returned.

At runtime the skill exchanges `clientId + apiKey` for a Shopify Admin access token through Shopify's client-credentials flow, then uses that token for Admin API requests.

## Local Runtime Rules Versus Shopify Access

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 · lib/shopify-provider.mjs (reported line 68)May include surrounding context.

js
Status output intentionally exposes only safe connection details. Secret values are never returned.

At runtime the skill exchanges `clientId + apiKey` for a Shopify Admin access token through Shopify's client-credentials flow, then uses that token for Admin API requests.

## Local Runtime Rules Versus Shopify Access

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 · lib/shopify-provider.mjs (reported line 75)May include surrounding context.

js
Status output intentionally exposes only safe connection details. Secret values are never returned.

At runtime the skill exchanges `clientId + apiKey` for a Shopify Admin access token through Shopify's client-credentials flow, then uses that token for Admin API requests.

## Local Runtime Rules Versus Shopify Access

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 · lib/shopify-provider.mjs (reported line 86)May include surrounding context.

js
Status output intentionally exposes only safe connection details. Secret values are never returned.

At runtime the skill exchanges `clientId + apiKey` for a Shopify Admin access token through Shopify's client-credentials flow, then uses that token for Admin API requests.

## Local Runtime Rules Versus Shopify Access

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 · references/shopify-provider.md (reported line 25)May include surrounding context.

md
Status output intentionally exposes only safe connection details. Secret values are never returned.

At runtime the skill exchanges `clientId + apiKey` for a Shopify Admin access token through Shopify's client-credentials flow, then uses that token for Admin API requests.

## Local Runtime Rules Versus Shopify Access

Dynamic Request Target

Medium
Category
Server-Side Request Forgery
Confidence
90% confidence
Finding

The fetch target is built directly from connection.storeDomain with no allowlist or strict hostname validation, so a malicious or misconfigured domain could redirect requests and client credentials to an attacker-controlled endpoint. Because this request includes the Shopify client_id and client_secret equivalent (apiKey) in the POST body, the impact is elevated beyond generic SSRF to credential disclosure and arbitrary outbound network access.

Content

Scanner excerpt · lib/shopify-provider.mjs (reported line 51)May include surrounding context.

js
}

const getShopifyAccessToken = async (connection, signal) => {
  const response = await fetch(`https://${connection.storeDomain}/admin/oauth/access_token`, {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The request logger stores full parsed response bodies in rawResponses for every Shopify request, which can include customer, order, address, token-adjacent, or other sensitive administrative data. In an agent runtime context, retaining and potentially surfacing raw API responses increases the chance of unintended disclosure through logs, downstream tooling, debugging output, or later prompts.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The documentation explicitly describes how the skill obtains live Shopify connection details, including a secret mapped into an environment variable, but does not warn that these credentials enable authenticated access to a real store. In a portable skill that exposes runtime execution, this omission increases the chance that users or downstream agents will treat the setup as harmless configuration rather than privileged access to production resources.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The examples show a command that executes JavaScript against a configured Shopify store, yet they do not clearly warn that execution is live and may read or modify external systems depending on available provider capabilities and credentials. Because this skill is specifically for direct runtime access, omission of a strong warning materially increases the risk of unintended real-world actions by users or autonomous agents.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This file exposes an execute command that allows --mode write and passes arbitrary loaded JavaScript directly into executeScript against a configured Shopify store, but it provides no explicit confirmation, friction, or safeguard before destructive actions are attempted. In the context of a runtime skill whose stated purpose is direct store access, this materially increases the risk of accidental or unauthorized modification of products, orders, customers, or settings if a user, upstream agent, or prompt-influenced workflow invokes write mode unexpectedly.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The code accesses configuration values from environment variables, including SHOPIFY_CLIENT_SECRET, in inspectShopifyRuntime and loadShopifyConnectionFromEnv. In this file there is no confirmation prompt, user-facing notice, or explanatory comment/docstring disclosing that the skill reads credentials from the environment.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.env_credential_access, suspicious.exposed_secret_literal

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
lib/runtime.mjs:70

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
lib/runtime.mjs:37

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
lib/shopify-provider.mjs:59