TryGhost/Ghost · error · BadRequestError
Request made from incorrect origin. Expected '${adminOrigin}
Error message
Request made from incorrect origin. Expected '${adminOrigin}' received '${origin}'. What it means
A BadRequestError from CSRF/origin protection in `cookieCsrfProtection`. Every authenticated request's `Origin` (or `Referer`-derived origin) must match the configured admin URL origin (`urlUtils.getAdminUrl()` falling back to site URL). A mismatch means the request came from a different host, which the server treats as a cross-origin form post and rejects before touching the session.
Source
Thrown at ghost/core/core/server/services/auth/session/session-service.js:137
}
/**
* cookieCsrfProtection
*
* @param {Req} req
* @param {Session} session
* @returns {Promise<void>}
*/
function cookieCsrfProtection(req, session) {
const origin = getOriginOfRequest(req);
// Check that the origin matches the admin URL to prevent cross-origin
// requests (e.g. no-cors form submissions from phishing sites)
const adminUrl = urlUtils.getAdminUrl() || urlUtils.getSiteUrl();
const adminOrigin = new URL(adminUrl).origin;
if (origin !== adminOrigin) {
throw new BadRequestError({
message: `Request made from incorrect origin. Expected '${adminOrigin}' received '${origin}'.`
});
}
// If there is no origin on the session object it means this is a *new*
// session, that hasn't been initialised yet. So we don't need CSRF protection
if (!session.origin) {
return;
}
if (session.origin !== origin) {
throw new BadRequestError({
message: `Request made from incorrect origin. Expected '${session.origin}' received '${origin}'.`
});
}
}
/**View on GitHub (pinned to 47d8b0e2ad)
Solutions
- Set `url` (and `admin.url` if used) in `config.*.json` to the exact origin users reach the admin through, including scheme.
- Ensure the reverse proxy preserves/sets `X-Forwarded-Host`/`X-Forwarded-Proto` and that Ghost trusts the proxy (`url` matches the public origin).
- Make all admin links/embeds use the configured admin origin consistently.
- After a domain migration, update `url` and run `ghost setup ssl`/update the config to the new origin.
Example fix
// before — config.production.json
{
"url": "http://example.com",
"admin": {"url": "https://admin.example.com"}
}
// after — single consistent public origin
{
"url": "https://example.com",
"admin": {"url": "https://example.com/ghost"}
} Defensive patterns
Strategy: validation
Validate before calling
function assertOriginMatchesConfig(reqOrigin, adminUrl) {
const expected = new URL(adminUrl).origin;
if (reqOrigin !== expected) {
throw new Error(`Origin mismatch: expected ${expected}, got ${reqOrigin}. Fix config.url/admin.url.`);
}
} Type guard
const originsMatch = (reqOrigin, adminUrl) => {
try { return reqOrigin === new URL(adminUrl).origin; } catch { return false; }
}; Try / catch
try {
await api.admin.someAction();
} catch (err) {
if (err.type === 'BadRequestError' && /incorrect origin/i.test(err.message)) fixConfigOrigin();
else throw err;
} Prevention
- Keep `url`/`admin.url` in config equal to the public origin users actually visit.
- Configure the reverse proxy to preserve Host and X-Forwarded-Proto/Host.
- After any domain change, update config and re-issue SSL.
When it happens
Trigger: An authenticated request whose `Origin` header (or `Referer`-derived origin) differs from the admin URL origin. Happens with a misconfigured `url`/`admin.url` in config, behind a proxy that rewrites the host, when accessing admin via an alternate domain, or when a phishing/no-cors form posts to the admin API.
Common situations: Config `url` set to `http://example.com` but the user accesses `https://example.com`; a reverse proxy/Cloudflare rewrites Host and the `Origin` becomes the proxy host; the site was migrated to a new domain but config wasn't updated; the admin is reached via an IP or localhost while `url` is the public domain.
Related errors
- Request made from incorrect origin. Expected '${session.orig
- Could not determine origin of request. Please ensure an Orig
- Could not fetch user from the session.
- Please verify your email settings
- Failed to update newsletter
AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13).
Data as JSON: /api/errors/b01cb7b4e5be61f3.
Report an issue: GitHub.