Cross-site request forgery protection may be missing
Investigates state-changing endpoints for missing request authenticity protections.
| Detail | Value |
|---|---|
| Check ID | CSRF_MISSING_PROTECTION |
| Severity | Medium |
| How it runs | Agent review |
Anchor to Vulnerable exampleVulnerable example
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 };
};
Anchor to How to fixHow to fix
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 };
};
shopify app security check, the command that runs this check- All app security checks
Was this page helpful?