Ghost: 400 Request made from incorrect origin on login after upgrading to v2.2.1.

Issue Summary

Can’t login to the ghost instance after upgrading to v2.2.1 from v2.2.0 using CLI. It can be reproduced in latest version of Chrome and Safari browsers with clearing cache with hard reload, too.

To Reproduce

  1. Head to https://jakubturek.com/admin.
  2. Enter valid credentials.

I receive 400 Request made from incorrect origin. error page. Stacktrace:

[2018-10-09 15:54:18] ERROR "GET /ghost/api/v2/admin/users/me/?include=roles" 400 7ms

NAME: BadRequestError
MESSAGE: Request made from incorrect origin.

level: normal

empty
empty
ERROR DETAILS:
    empty

BadRequestError: Request made from incorrect origin.
    at new BadRequestError (/var/www/ghost/versions/2.2.1/node_modules/ghost-ignition/lib/errors/index.js:94:23)
    at cookieCsrfProtection (/var/www/ghost/versions/2.2.1/core/server/services/auth/session/middleware.js:108:21)
    at Layer.handle [as handle_request] (/var/www/ghost/versions/2.2.1/node_modules/express/lib/router/layer.js:95:5)
    at next (/var/www/ghost/versions/2.2.1/node_modules/express/lib/router/route.js:137:13)
    at /var/www/ghost/versions/2.2.1/node_modules/express-session/index.js:489:7
    at SessionModel.findOne.then (/var/www/ghost/versions/2.2.1/core/server/services/auth/session/store.js:26:17)
    at tryCatcher (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromise0 (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/promise.js:614:10)
    at Promise._settlePromises (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/promise.js:693:18)
    at Async._drainQueue (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/async.js:133:16)
    at Async._drainQueues (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/async.js:143:10)
    at Immediate.Async.drainQueues (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/async.js:17:14)
    at runCallback (timers.js:672:20)
    at tryOnImmediate (timers.js:645:5)

[2018-10-09 15:54:18] ERROR "GET /ghost/api/v2/admin/settings/?type=blog%2Ctheme%2Cprivate" 400 10ms

NAME: BadRequestError
MESSAGE: Request made from incorrect origin.

level: normal

empty
empty
ERROR DETAILS:
    empty

BadRequestError: Request made from incorrect origin.
    at new BadRequestError (/var/www/ghost/versions/2.2.1/node_modules/ghost-ignition/lib/errors/index.js:94:23)
    at cookieCsrfProtection (/var/www/ghost/versions/2.2.1/core/server/services/auth/session/middleware.js:108:21)
    at Layer.handle [as handle_request] (/var/www/ghost/versions/2.2.1/node_modules/express/lib/router/layer.js:95:5)
    at next (/var/www/ghost/versions/2.2.1/node_modules/express/lib/router/route.js:137:13)
    at /var/www/ghost/versions/2.2.1/node_modules/express-session/index.js:489:7
    at SessionModel.findOne.then (/var/www/ghost/versions/2.2.1/core/server/services/auth/session/store.js:26:17)
    at tryCatcher (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromise0 (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/promise.js:614:10)
    at Promise._settlePromises (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/promise.js:693:18)
    at Async._drainQueue (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/async.js:133:16)
    at Async._drainQueues (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/async.js:143:10)
    at Immediate.Async.drainQueues (/var/www/ghost/versions/2.2.1/node_modules/bluebird/js/release/async.js:17:14)
    at runCallback (timers.js:672:20)
    at tryOnImmediate (timers.js:645:5)

Technical details:

  • Ghost Version: 2.2.1
  • Node Version: v6.11.1
  • Browser/OS: OS X Mojave, latest Chrome / latest Safari
  • Database: MySQL

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 1
  • Comments: 26 (11 by maintainers)

Commits related to this issue

Most upvoted comments

@turekj Thank very much for the bug report and the debugging - couldn’t have solved this without that!

@olivierlambert Thanks for helping out 👍

A fix for this has landed on master, I will release tomorrow morning as v2.2.2

👻

The browser is Chrome Version 69.0.3497.100 (Official Build) (64-bit). Probably the second configuration issue was related to Referrer-Policy header, which was set to no-referrer value. Changing it to add_header Referrer-Policy "origin"; solves described problem as well without any Access-Control-Allow headers. So in my case there was neither Origin or Referer header, and that’s why application was not working correctly. Thank you for clarifications.

You guys rock! 12 hours passed since the report and there’s already a PR to fix the issue ❤️

Will be happy to test the new release and see whether the issue is gone, but it sounds very reasonable. Once again, thank you, you’re doing an amazing job with Ghost!

@turekj @olivierlambert Thanks so much for your input - I believe the bug is caused by a misspelling of the “Referer” header in ghost - which I only noticed after reading through your comment! I’ve raised a PR for it now ☺️

@turekj The new authentication for ghost checks that a request is made from the same origin as the session was initiated from. We determine the origin via the Origin header or the Referrer if that is missing. It’s possible that cloudflare is messing with that. What’s strange is that upon login, an error should occur if neither of those headers are present. So it seems that the value of the header is changing between the login request and the subsequent ones.

@olivierlambert I cannot replicate this when behind an nginx proxy - would you share your config with me?