Back to skill

Security audit

Shopify Manager Cli

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent Shopify admin skill, but it handles a powerful store token and destructive store operations with under-scoped safeguards.

Review before installing on a production store. Use a least-privilege Shopify custom app token, set SHOPIFY_STORE_URL only to your exact shop domain, avoid uploading sensitive local files, and require explicit human confirmation for deletes and other store-changing actions. Consider hardening the script to validate the Shopify host and add force/dry-run safeguards before use with valuable store data.

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

Error
Location
scripts/shopify_admin.py:25
Finding

Unvalidated Shopify Store URL Can Disclose the Admin API Access Token

Content
View full analysis

Vulnerability Details

File Location: scripts/shopify_admin.py, lines 25-27 and 45-66
Vulnerability Type: Credential disclosure through an attacker-controlled API endpoint
Risk Level: High

Vulnerable Code

python
STORE_URL = os.environ.get("SHOPIFY_STORE_URL", "").rstrip("/")
TOKEN = os.environ.get("SHOPIFY_ACCESS_TOKEN", "")
API_VERSION = os.environ.get("SHOPIFY_API_VERSION", "2025-01")


def _endpoint() -> str:
    if not STORE_URL or not TOKEN:
        die(
            "SHOPIFY_STORE_URL and SHOPIFY_ACCESS_TOKEN must be set.",
            details={"SHOPIFY_STORE_URL": bool(STORE_URL), "SHOPIFY_ACCESS_TOKEN": bool(TOKEN)},
        )
    return f"{STORE_URL}/admin/api/{API_VERSION}/graphql.json"


def graphql(query: str, variables: dict | None = None) -> dict:
    """Execute a GraphQL request and return the parsed JSON response."""
    body = json.dumps({"query": query, "variables": variables or {}}).encode()
    req = urllib.request.Request(
        _endpoint(),
        data=body,
        headers={
            "X-Shopify-Access-Token": TOKEN,
            "Content-Type": "application/json",
        },
    )

Technical Analysis

The CLI obtains SHOPIFY_STORE_URL directly from the process environment and uses it to construct the GraphQL endpoint without validating its scheme, hostname, port, user-information component, or relationship to Shopify. The resulting request always includes the privileged SHOPIFY_ACCESS_TOKEN in the X-Shopify-Access-Token header.

Consequently, any party capable of influencing SHOPIFY_STORE_URL can direct authenticated requests to an arbitrary server. Requiring only that the environment variable be nonempty does not establish that the destination is the intended Shopify store. Redirect behavior is also not explicitly constrained or validated.

Attack Path

  1. An attacker gains the ability to influence the CLI environment, its launcher configuration, or instructions used to configure `SHOPIFY_ ...[truncated 1066 chars]
Remediation
View remediation

Remediation Suggestions

  1. Parse SHOPIFY_STORE_URL with urllib.parse.urlsplit rather than concatenating an untrusted string.
  2. Require the https scheme and reject plaintext HTTP.
  3. Require an exact approved store hostname or a hostname ending in .myshopify.com with a nonempty, validated store subdomain.
  4. Prefer an explicit allowlist containing the single expected store hostname; suffix validation alone is weaker.
  5. Reject embedded credentials, fragments, query strings, unexpected paths, and nonstandard ports.
  6. Validate SHOPIFY_API_VERSION against a strict Shopify API-version format before incorporating it into a URL.
  7. Prevent authenticated requests from following redirects to a different origin. Either disable redirects or revalidate the scheme, hostname, and port at every redirect and never forward the token cross-origin.
  8. Fail closed with a clear error before constructing or sending any authenticated request when validation fails.
  9. Grant the Shopify custom application only the minimum scopes required for the current operation, and rotate the access token if it may have been sent to an untrusted endpoint.

A hardened endpoint builder should enforce an exact expected origin before the access-token header is attached to a request.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (12)

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/shopify_admin.py (reported line 75)May include surrounding context.

python
last_exc: Exception | None = None
    for _ in range(3):
        try:
            with urllib.request.urlopen(req) as resp:
                return json.loads(resp.read())
        except urllib.error.HTTPError as exc:
            err_body = exc.read().decode(errors="replace")

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/shopify_admin.py (reported line 152)May include surrounding context.

python
last_exc: Exception | None = None
    for _ in range(3):
        try:
            with urllib.request.urlopen(req) as resp:
                return json.loads(resp.read())
        except urllib.error.HTTPError as exc:
            err_body = exc.read().decode(errors="replace")

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

md
Environment variables required:
    SHOPIFY_STORE_URL      – e.g. https://my-store.myshopify.com
    SHOPIFY_ACCESS_TOKEN   – Admin API access token (shpat_…)
    SHOPIFY_API_VERSION    – optional, defaults to 2025-01
"""

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 · scripts/shopify_admin.py (reported line 9)May include surrounding context.

python
Environment variables required:
    SHOPIFY_STORE_URL      – e.g. https://my-store.myshopify.com
    SHOPIFY_ACCESS_TOKEN   – Admin API access token (shpat_…)
    SHOPIFY_API_VERSION    – optional, defaults to 2025-01
"""

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill invokes a Python script that necessarily uses environment variables and network access to call the Shopify Admin API, but it does not declare explicit tool scope such as allowed tools or permissions. That omission weakens policy enforcement and user transparency, increasing the risk that a broadly invocable skill can access credentials and transmit store data without sufficiently constrained execution boundaries.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill supports uploading local files and transmitting store content to Shopify over the Admin API, but the description and usage guidance do not prominently warn that local paths and store data will be sent to an external service. This can lead users to provide sensitive files or data without informed consent, especially because the tool accepts paths directly and performs networked uploads.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill is user-invocable and includes broad natural-language mappings like 'list all active products' or 'write an article,' which can easily overlap with ordinary conversation and trigger sensitive store operations unintentionally. In a skill that can read and modify production e-commerce content, ambiguous invocation increases the chance of accidental data access or administrative changes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The product delete command performs an irreversible deletion immediately from a single CLI invocation with no confirmation, dry-run, or force flag. In an agent or automation context, this increases the chance of accidental destructive actions from prompt mistakes, parameter mix-ups, or unsafe chaining.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

Metaobject deletion executes without any explicit guardrail, so a mistaken ID or unsafe agent instruction can remove content/configuration immediately. Because this tool is intended for automated store administration, lack of confirmation materially increases the risk of accidental data loss.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

Article deletion is destructive and currently has no user-facing confirmation or protective workflow. In an automation-capable admin CLI, that makes accidental publication loss more likely, especially when invoked by higher-level agents or scripts.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest description limits the skill to managing products, metafields, metaobjects, blogs, and articles via the Shopify Admin GraphQL API. This file also implements a separate file upload capability that uploads arbitrary files, videos, and 3D models to Shopify Files, which is a broader resource area not disclosed in the manifest description.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest describes managing products, metafields, metaobjects, blogs, and articles via the Shopify Admin GraphQL API. This file also defines staged upload and file creation mutations, which add a separate file/media management capability not mentioned in the stated scope.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.