Embedded app frame-ancestors uses a wildcard
Detects literal wildcard or clearly permissive frame-ancestors policies in embedded app code.
| Detail | Value |
|---|---|
| Check ID | STATIC_FRAME_ANCESTORS |
| Severity | High |
| How it runs | Deterministic scan and agent review |
| Applies to | Embedded apps |
Anchor to Vulnerable exampleVulnerable example
app/entry.server.tsx
export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
reactRouterContext: EntryContext,
) {
// A hand-written wildcard policy: any origin can frame the
// embedded app, which is what clickjacking needs. "https:",
// "*", and "https://*.myshopify.com" all count as permissive.
responseHeaders.set("Content-Security-Policy", "frame-ancestors *");
// ... the rest of the template's handleRequest is unchanged.
}
Anchor to How to fixHow to fix
Restrict frame-ancestors to Shopify Admin and the authenticated shop origin.
For more detail, see Set up iframe protection.
app/entry.server.tsx
import { addDocumentResponseHeaders } from "./shopify.server";
export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
reactRouterContext: EntryContext,
) {
// Let Shopify build the policy: it restricts frame-ancestors to
// admin.shopify.com and the shop this request authenticated as.
// Drop any hand-written wildcard policy elsewhere in the app.
addDocumentResponseHeaders(request, responseHeaders);
// ... the rest of the template's handleRequest is unchanged.
}
// Written by hand, the only acceptable shape names both origins
// explicitly, with no wildcard:
//
// frame-ancestors https://admin.shopify.com https://<shop>.myshopify.com
shopify app security check, the command that runs this check- All app security checks
Was this page helpful?