Cubed Docs
Customization

Security and headers

The protections the theme ships with, and the one line you must remove before going live.

All of this lives in next.config.ts at the root of the project. You do not need to understand every line, but there is one change every customer should make.

Remove the development origins

Do this before you go live.

next.config.ts
allowedDevOrigins: ["100.117.62.95", "100.91.160.187"],   

Those are private network addresses from the theme author's development machine. They do nothing for you. Delete the line entirely, or replace the addresses with your own if you develop across a local network.

It only affects the development server, not production — but leaving somebody else's addresses in your configuration is untidy at best.

Allowed image hosts

Next.js refuses to load and optimise images from hosts you have not listed. The theme lists three — two fixed, and your own Supabase project:

HostWhy
dunb17ur4ymx4.cloudfront.netPackage images served by Tebex
mc-heads.netPlayer avatar renders
yourref.supabase.coYour uploaded logo and favicon

The Supabase one differs per install, so it is derived from SUPABASE_URL at build time rather than hardcoded:

next.config.ts
const supabaseHost = supabaseHostname();   // parsed from SUPABASE_URL

images: {
  remotePatterns: [
    { protocol: "https", hostname: "dunb17ur4ymx4.cloudfront.net" },
    { protocol: "https", hostname: "mc-heads.net" },
    ...(supabaseHost ? [{ protocol: "https" as const, hostname: supabaseHost }] : []),
  ],
},

This is why SUPABASE_URL must exist at build time. If it is missing during the build, the Supabase host never reaches this list or the Content-Security-Policy, and your uploaded logo is blocked in the browser — even though the site otherwise works and the admin panel uploads fine.

Set it, then trigger a new build. Editing the variable alone changes nothing.

To use images from anywhere else — your own CDN, say — add its hostname to that list and rebuild:

{ protocol: "https", hostname: "cdn.yourdomain.com" },

The security headers

Sent with every response:

HeaderWhat it does
X-Content-Type-Options: nosniffStops browsers guessing file types, which is a classic attack route
Referrer-Policy: strict-origin-when-cross-originDoes not leak your full URLs to other sites
X-Frame-Options: SAMEORIGINStops other sites embedding your store in a frame
Permissions-PolicyTurns off camera, microphone and location access
Strict-Transport-SecurityForces HTTPS. Production only
Content-Security-Policy-Report-OnlySee below

About Strict-Transport-Security

Once a browser sees this header, it refuses to talk to your domain over plain HTTP for two years. That is good for a live store, and it is why the header is only sent in production — you do not want it stuck on a domain you are still testing.

The Content Security Policy

A CSP restricts where a page may load scripts, styles and images from, which is the main defence against injected scripts.

The theme ships it in report-only mode:

next.config.ts
{ key: "Content-Security-Policy-Report-Only", value: cspReportOnly },

Report-only means violations appear in the browser console but nothing is blocked. That is deliberate: the admin panel and the theme's inline dark-mode script both need careful handling, and an enforcing policy that is slightly wrong takes your site down.

Should you turn on enforcement?

Only if you are comfortable debugging it. If you want to:

Watch for violations first

Browse your live site — home page, store, basket, checkout, and the whole admin panel — with the browser console open. Note every CSP violation.

Widen the policy to cover them

Add the hosts and directives your site genuinely needs to the cspReportOnly array in next.config.ts.

Only then switch the header name

{ key: "Content-Security-Policy", value: cspReportOnly },

Test everything again

Especially the admin panel, which is the most likely thing to break.

If you add an image host to remotePatterns, add it to the CSP's img-src list too, or you will get a violation once enforcement is on.

The cross-origin guard

Basket requests are rejected in production when they do not come from your own site. This is why NEXT_PUBLIC_SITE_URL has to be exactly right — the check compares the request's origin against it.

It is deliberately skipped outside production and when NEXT_PUBLIC_SITE_URL is unset, so local development and testing are unaffected.

Getting 403 Cross-origin request rejected on a live site means the two do not match: check www versus no www, and http versus https.

Keeping your secrets secret

  • TEBEX_TOKEN, SERVER_SECRET and SUPABASE_SERVICE_ROLE_KEY are only ever read on the server. Never rename them with a NEXT_PUBLIC_ prefix — that ships them to every visitor's browser.
  • The Supabase service_role key is the worst of the three to leak: it bypasses row-level security and grants full read/write access to your entire project. Rotate it in the Supabase dashboard if it is ever exposed.
  • .env.local is in .gitignore. Keep it there, and check git status before your first push.
  • Use a different PAYLOAD_SECRET for your live site than for your local copy.
  • Rotate a token immediately if you ever paste it somewhere public. Tebex lets you regenerate both from the Creator Panel.

Keeping things patched

Security fixes reach you through dependency updates:

bun update
bun run check

bun run check runs the linter, the type checker and a build, so you find out before deploying if an update broke something.

On this page