T09 · Insecure Skill Coding Practices
- 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: HighVulnerable 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_URLdirectly 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 privilegedSHOPIFY_ACCESS_TOKENin theX-Shopify-Access-Tokenheader.Consequently, any party capable of influencing
SHOPIFY_STORE_URLcan 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
- 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
- Parse
SHOPIFY_STORE_URLwithurllib.parse.urlsplitrather than concatenating an untrusted string. - Require the
httpsscheme and reject plaintext HTTP. - Require an exact approved store hostname or a hostname ending in
.myshopify.comwith a nonempty, validated store subdomain. - Prefer an explicit allowlist containing the single expected store hostname; suffix validation alone is weaker.
- Reject embedded credentials, fragments, query strings, unexpected paths, and nonstandard ports.
- Validate
SHOPIFY_API_VERSIONagainst a strict Shopify API-version format before incorporating it into a URL. - 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.
- Fail closed with a clear error before constructing or sending any authenticated request when validation fails.
- 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.
- Parse
