diff --git a/.changeset/revalidate-fail-closed.md b/.changeset/revalidate-fail-closed.md new file mode 100644 index 000000000..568e5e353 --- /dev/null +++ b/.changeset/revalidate-fail-closed.md @@ -0,0 +1,5 @@ +--- +"gitbook": patch +--- + +Fail closed in `/~gitbook/revalidate` when `GITBOOK_SECRET` is not configured, returning `403 Revalidation is disabled` instead of skipping the signature check, consistent with `force-revalidate`. diff --git a/packages/gitbook/src/lib/routes.ts b/packages/gitbook/src/lib/routes.ts index 24f114114..4b4e56b9b 100644 --- a/packages/gitbook/src/lib/routes.ts +++ b/packages/gitbook/src/lib/routes.ts @@ -10,26 +10,29 @@ export async function withVerifySignature( request: Request, fn: (body: T) => Promise ) { + // Fail closed when no secret is configured, consistent with force-revalidate. + if (!GITBOOK_SECRET) { + return NextResponse.json({ error: 'Revalidation is disabled' }, { status: 403 }); + } + try { const rawBody = await request.text(); const body = JSON.parse(rawBody) as T; - if (GITBOOK_SECRET) { - // Retrieve the signature header from the request - const incomingSignature = request.headers.get('x-gitbook-signature'); - if (!incomingSignature) { - return NextResponse.json({ error: 'Missing signature header' }, { status: 400 }); - } + // Retrieve the signature header from the request + const incomingSignature = request.headers.get('x-gitbook-signature'); + if (!incomingSignature) { + return NextResponse.json({ error: 'Missing signature header' }, { status: 400 }); + } - const computedSignature = crypto - .createHmac('sha256', GITBOOK_SECRET) - .update(rawBody) - .digest('hex'); + const computedSignature = crypto + .createHmac('sha256', GITBOOK_SECRET) + .update(rawBody) + .digest('hex'); - // Compare incoming signature to computed signature - if (incomingSignature !== computedSignature) { - return NextResponse.json({ error: 'Invalid signature' }, { status: 401 }); - } + // Compare incoming signature to computed signature + if (incomingSignature !== computedSignature) { + return NextResponse.json({ error: 'Invalid signature' }, { status: 401 }); } return await fn(body);