Skip to main content

Cross-site request forgery protection may be missing

Investigates state-changing endpoints for missing request authenticity protections.

DetailValue
Check IDCSRF_MISSING_PROTECTION
SeverityMedium
How it runsAgent review

app/routes/api.discount.apply.tsx

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

import prisma from "../db.server";

// A state-changing endpoint with no session-token check: any
// site the merchant visits can POST here from their browser and
// it will succeed.
export const action = async ({ request }: ActionFunctionArgs) => {
const formData = await request.formData();

await prisma.discount.update({
where: { id: String(formData.get("id")) },
data: { active: true },
});

return { ok: true };
};

Require an authenticated session and CSRF protection on state-changing requests.

app/routes/api.discount.apply.tsx

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

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

export const action = async ({ request }: ActionFunctionArgs) => {
// The embedded app sends a session token on every request.
// Validating it is what proves the request came from your own
// admin UI, not a forged form.
const { session } = await authenticate.admin(request);

const formData = await request.formData();

await prisma.discount.updateMany({
where: { id: String(formData.get("id")), shop: session.shop },
data: { active: true },
});

return { ok: true };
};


Was this page helpful?