Skip to main content

Query scoped by shop value taken from request input

Detects queries whose shop scope comes from request params rather than the authenticated session. Presence of a shop key is not proof of scoping when its value is attacker-controlled.

DetailValue
Check IDREQUEST_DERIVED_SHOP_SCOPE
SeverityHigh
How it runsAgent review

app/routes/app.settings.tsx

import type { LoaderFunctionArgs } from "react-router";

import { authenticate } from "../shopify.server";
import prisma from "../db.server";

export const loader = async ({ request }: LoaderFunctionArgs) => {
await authenticate.admin(request);

const shop = new URL(request.url).searchParams.get("shop");

// There is a shop filter, but its value is attacker-controlled,
// so it scopes the query to whichever shop the caller names.
return {
settings: await prisma.appSetting.findMany({ where: { shop } }),
};
};

Scope the query with the shop from the authenticated session, or verify the supplied shop against a signed session or HMAC first.

For more detail, see Session tokens.

app/routes/app.settings.tsx

import type { LoaderFunctionArgs } from "react-router";

import { authenticate } from "../shopify.server";
import prisma from "../db.server";

export const loader = async ({ request }: LoaderFunctionArgs) => {
const { session } = await authenticate.admin(request);

// Scope from the session. If a shop must arrive in the request,
// compare it to session.shop and reject a mismatch before
// querying.
return {
settings: await prisma.appSetting.findMany({
where: { shop: session.shop },
}),
};
};


Was this page helpful?