Conversation
Coverage report
Test suite run success4032 tests passing in 1541 suites. Report generated by 🧪jest coverage report action from 7aae5d3 |
|
/snapit |
|
🫰✨ Thanks @dmerand! Your snapshot has been published to npm. Test the snapshot by installing your package globally: npm i -g --@shopify:registry=https://registry.npmjs.org @shopify/cli@0.0.0-snapshot-20260327162821Caution After installing, validate the version by running |
e15c53b to
893af23
Compare
|
/snapit |
|
🫰✨ Thanks @dmerand! Your snapshot has been published to npm. Test the snapshot by installing your package globally: npm i -g --@shopify:registry=https://registry.npmjs.org @shopify/cli@0.0.0-snapshot-20260327203223Caution After installing, validate the version by running |
| const fail = (message: string) => { | ||
| res.statusCode = 400 | ||
| res.setHeader('Content-Type', 'text/html') | ||
| res.end(`<html><body><h1>Authentication failed</h1><p>${message}</p></body></html>`) |
Check failure
Code scanning / CodeQL
Reflected cross-site scripting
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 1 day ago
In general, to fix reflected XSS when writing user input into HTML, you must apply appropriate HTML-encoding/escaping to any untrusted data before interpolating it into the response. This converts characters like <, >, ", ', and & into their HTML entity equivalents so they are rendered as text instead of being interpreted as HTML/JavaScript.
The minimal, best fix here is to ensure that the message passed to fail is HTML-escaped before interpolation into the response body. Since most fail call sites use fixed strings, we only need to sanitize the one value coming from searchParams.get('error'). The safest change that preserves existing behavior is:
- Introduce a small HTML-escaping helper inside this file (since we don’t see any existing HTML-escape utility imported).
- Use this helper only when building the message that includes the
errorparameter: changefail(\Shopify returned an OAuth error: ${error}`)tofail(`Shopify returned an OAuth error: ${escapeHtml(error)}`). This keeps the general structure of the code intact and only encodes potentially unsafe characters coming from user input. All otherfailmessages remain unchanged. No external dependencies are strictly required; we can define a simple localescapeHtml` function that handles standard dangerous characters.
Concretely:
- In
packages/cli/src/cli/services/store/auth.ts, inside the shown region, add a smallescapeHtmlfunction (for example just above thecreateServercallback or near the top of the file code you control). - Modify the
if (error) { ... }block so thaterroris escaped before being included in the HTML string. This ensures that even iferrorcontains script tags or HTML, the browser will display them as text, eliminating the XSS vector.
| @@ -102,6 +102,14 @@ | ||
| settleWithError(new AbortError('Timed out waiting for OAuth callback.')) | ||
| }, timeoutMs) | ||
|
|
||
| const escapeHtml = (value: string): string => | ||
| value | ||
| .replace(/&/g, '&') | ||
| .replace(/</g, '<') | ||
| .replace(/>/g, '>') | ||
| .replace(/"/g, '"') | ||
| .replace(/'/g, ''') | ||
|
|
||
| const server = createServer((req, res) => { | ||
| const requestUrl = new URL(req.url ?? '/', `http://localhost:${port}`) | ||
|
|
||
| @@ -138,7 +146,7 @@ | ||
|
|
||
| const error = searchParams.get('error') | ||
| if (error) { | ||
| fail(`Shopify returned an OAuth error: ${error}`) | ||
| fail(`Shopify returned an OAuth error: ${escapeHtml(error)}`) | ||
| return | ||
| } | ||
|
|

What
Add
shopify store authandshopify store executeso Shopify CLI can authenticate an app against a store and then run Admin GraphQL without a local app project. Keep thestore executeflags aligned withshopify app execute, require--allow-mutationsfor writes, keep hidden--mocksupport for demos, and add a project-local Claude skill that routes merchant-style store tasks into this flow.Why
This demo is meant to show a clear app-authenticated store workflow in Shopify CLI: authenticate once for a store, verify access, and then run task-specific Admin API operations. That makes it easier to demo merchant-style tasks like adding products or updating inventory through the CLI.
How
Add
shopify store authto run a standard Shopify app OAuth flow against a store, request required scopes, open a localhost callback, exchange the code using a client secret file, and store an online access token locally.Update
shopify store executeto use the stored app session and tell the user to runshopify store authwhen the session is missing, expired, or lacks scopes.Keep mutations blocked unless
--allow-mutationsis passed.Keep
--mockso the command can still be demoed without auth or network access.Add
.claude/skills/manage-store-with-cliso Claude can steer merchant-style requests intostore auth, a safe verification query, and then the task-specificstore executecommand.For the final version, replace the current demo-oriented client-secret-file exchange with PKCE.
Refresh generated docs, README output, and the oclif manifest for the new command set.
Testing
http://localhost:3458/auth/callbackin the demo app redirect settingsprintf '%s' "$SHOPIFY_STORE_CLIENT_SECRET" > /tmp/shopify-store-client-secret.txtpnpm run shopify store auth --store shop.myshopify.com --scopes read_products,write_products --client-secret-file /tmp/shopify-store-client-secret.txtpnpm run shopify store execute --store shop.myshopify.com --query 'query { shop { name id } }'pnpm run shopify store execute --store shop.myshopify.com --query 'mutation { shop { id } }'should fail until--allow-mutationsis addedpnpm run shopify store execute --store shop.myshopify.com --query 'query { shop { name } }' --mockI want to add a draft product to my store with Shopify CLIHow do I update inventory with Shopify CLI?How do I tag products in my store from Shopify CLI?manage-store-with-cliskill loadspnpm run shopify store authfirst, then a safepnpm run shopify store execute --query 'query { shop { name id } }', and only then the task-specific command/tmp/shopify-store-client-secret.txt, and does not route topnpm run shopify app execute