Skip to main content

Session lifecycle or replay control may be missing

Investigates stale sessions, replayable signed links, and missing invalidation or idempotency across lifecycle transitions.

DetailValue
Check IDSESSION_LIFECYCLE_AND_REPLAY
SeverityHigh
How it runsAgent review

app/routes/webhooks.app.uninstalled.tsx

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

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

export const action = async ({ request }: ActionFunctionArgs) => {
const { shop } = await authenticate.webhook(request);

// Shopify revokes the access token on uninstall, but the
// session rows stay behind. Code that treats a stored session
// as proof the shop still has the app installed keeps trusting
// a shop that removed it.
console.log(`Uninstalled: ${shop}`);

return new Response();
};

Invalidate stale authority and enforce replay protection or re-authorization before sensitive actions.

app/routes/webhooks.app.uninstalled.tsx

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

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

export const action = async ({ request }: ActionFunctionArgs) => {
const { shop, session } = await authenticate.webhook(request);

// Delete the shop's sessions on uninstall. Do the same on
// logout, scope downgrade, and account disconnect.
if (session) await prisma.session.deleteMany({ where: { shop } });

return new Response();
};


Was this page helpful?