Headless CMS Security: What Changes When the Editor Leaves Your Web Server

Security teams know the classic CMS attack surface well: a login page on the public domain, a long list of plugins, and a database on the same server that answers visitors’ requests. A headless CMS changes that picture, and the change is easy to misread in either direction.

Some of the old risks disappear. Others move into places a traditional review does not look, such as API tokens, roles, dataset visibility and browser access rules. This guide follows them there, with Sanity as the worked example.

What a Monolithic CMS Exposes

In a traditional setup such as WordPress, the admin login, the plugins, the database and the pages visitors see all run on one server under one domain. An attacker who finds a weak plugin or a reused password reaches the content, the user accounts and often the server itself, so every plugin update becomes a security task.

That is why hardening guides for monolithic CMSs spend so much time on login limits, file permissions and plugin audits. The attack surface grows with every feature added to the site.

What Moves When the CMS Goes Headless

A headless CMS stores content in a hosted service and delivers it through an API, while a separate front end such as a Next.js app renders the pages. Visitors mostly receive prebuilt or cached pages, the editing interface can live on a different domain, and there is no content database on the web server to attack.

With Sanity, the editing interface (Sanity Studio) can be deployed to Sanity’s own hosting or embedded in the Next.js app. Deploying it separately keeps the login off the public site, and sign-in goes through Sanity’s authentication instead of a user table on your own server.

Tokens, Roles and CORS: The New perimeter

In a headless setup, access is decided by API tokens, user roles and CORS rules. Those settings live in a dashboard, far from any code review, which makes them easy to forget. A single write token committed to a public repository can expose the whole content store, so each of these deserves a line in the review.

  • Tokens: Sanity creates them under Settings, API, Tokens in the project console, and its documentation warns against keeping them in public places such as code committed to GitHub. Store them in the hosting platform’s environment variables.
  • Browser exposure: in Next.js, only environment variables prefixed with NEXT_PUBLIC_ reach the browser, so a token without that prefix stays on the server.
  • Datasets: anyone can query a public dataset, while a private dataset requires a valid personal or robot token to read any data.
  • CORS origins: they decide which websites can access project data from a browser, so remove localhost and old preview domains after launch.
  • Roles: Viewer is read-only, and on Growth plans and above a Contributor can edit drafts but cannot publish. Custom roles are available on certain Enterprise plans.

Planning A Secure Move Off A Legacy CMS

Treat the migration as a chance to reset access. Inventory every account and integration on the old system, decide which ones the new setup needs, issue fresh tokens with the narrowest permission that works, and retire the old admin panel on the day of the switch instead of leaving it running in the background.

Legacy custom systems are often the hardest to secure, since every patch depends on the few people who still know the code. Pagepro, a Next.js and Sanity migration specialist (https://pagepro.co/services/sanity-development), replatformed GP Notebook, a medical reference platform with 100,000+ subpages used by UK GPs, from a legacy custom CMS to Next.js + Sanity.

Until the redirect map is verified, keep the old system read-only and reachable only from your own network, then shut it down and revoke every credential it held.

A Security Review Checklist For A Headless Setup

Review a headless site on two levels: the front end, which is a normal web application with its own dependencies and headers, and the content platform, where access is configured in settings. Fixes in the second group are configuration changes, so schedule the review before launch and repeat it every quarter.

  1. List every API token, its permission level and where it is stored
  2. Search the repository history for committed tokens and rotate any you find
  3. Confirm which datasets are public and whether that is intended
  4. Prune CORS origins to production and current preview domains
  5. Check each user’s role and remove people who have left
  6. Scan front-end dependencies and set security headers in the Next.js config

Put the first review on the calendar for the week before launch, and make one person the owner of the token list afterwards, so no new integration ends up holding a token nobody tracks.