29 days ago by Kurt Tomlinson
Want to learn more about CORS? Check out CORS in Action: Creating and consuming cross-origin APIs.
Thanks to Jens Mueller, I was alerted to this issue. He was kind enough to send me the email below:
*Please forward to tech/developer/security team*
TL;DR +++ bloopist.com generates the
Access-Control-Allow-Origin header in a dangerous way +++
websites like bloopist.com.evil.com are allowed CORS access +++
leads to SOP bypass (aka completely taking over accounts) and
SSL bypass +++ Fix: disable CORS dynamic header generation or
re-config to trusted URLs +++
- Affected service: bloopist.com
- OWASP Top 10 category: A5 (Security Misconfiguration)
- Impact: Take over user accounts, SSL/TLS bypass
Dear bloopist.com security team,
In the scope of academic research on web security, we touched
upon a vulnerability in bloopist.com. The website uses
Cross-Origin Resource Sharing (CORS) in an insecure way:
*** Weakness: Post-domain wildcard origin reflection ***
bloopist.com's *Access-Control-Allow-Origin* header is
dynamically generated based on the browser's *Origin: ...*
request header. The generation code however only checks if the
Origin *starts* with bloopist.com. Furthermore, the
*Access-Control-Allow-Credentials* header is present. This
allows an attacker to bypass access controls such as the
same-origin policy. For example, a malicious website like
bloopist.com.evil.com visited by a client logged into
bloopist.com can perform actions in the context of the logged in
user on bloopist.com. Furthermore, this allows a MitM attacker
to bypass SSL encryption.
*** Exploit: SSL-bypass (scenario: MitM attacker) ***
/A http origin is allowed CORS access to a https resource,/
/this allows a man-in-the-middle to break https encryption/
https://bloopist.com allows CORS-access from non-encrypted
origins like "Origin: http://bloopist.com". This enables a
man-in-the-middle to practically bypass SSL encryption: The
attacker just has to wait until the victim visits *any*
unencrypted website, insert a redirect to a fake
http://bloopist.com.whatever site she set up -- and then embed
https://bloopist.com. Now -- via CORS -- she can access the SSL
encrypted content of https://bloopist.com/some-private-user-info
or perform arbitrary actions in the context of the logged in
user. Of course, a MitM is a strong attacker model. However,
it's what SSL actually was supposed to protect from.
More details on CORS-misconfiguration issues can be found here:
Proof-of-concept code can be sent on request.
Feel free to contact me for any questions.
Chair for Network and Data Security, Ruhr-University
M.Sc. Jens Mueller
Building ID 2/469
Phone: +49 (0) 234 / 32-29177
Basically, the regular expressions I was using to allow CORS access were broken. I needed to modify them to only allow https access, and ensure that only domains that ended in bloopist.com should be allowed.
To test which origins were allowed by my CORS configuration, I used a simple curl command:
curl -H "Origin: https://bloopist.com.evil.com" --verbose https://bloopist.com 2>&1 | grep Origin
This command let me pick the origin that I wanted to pretend to be and printed out any header lines that included the word "Origin". From that, I could see if the server was sending back an Access-Control-Allow-Origin string that would allow attacks from other domains or not.
Before implementing my fixed CORS whitelist, I'd get outputs from curl like the one below.
$ curl -H "Origin: https://bloopist.com.evil.com" --verbose https://bloopist.com 2>&1 | grep Origin
> Origin: https://bloopist.com.evil.com
< Access-Control-Allow-Origin: https://bloopist.com.evil.com
< Vary: Origin
I updated my CORS regular expression to force https, allow either a subdomain of bloopist.com or the bare domain by itself, and to force the origin to end with bloopist.com. I use Rack::Cors in my Ruby on Rails applications, and I configured it like this:
config.middleware.insert_before 0, Rack::Cors do
if Rails.env == "development"
elsif Rails.env == "production"
resource '*', :headers => :any, :methods => :any
After updating my configuration, I double checked which origins were allowed CORS access. Domains other than bloopist.com are no longer allowed access. However, I was unable to figure out how to make curl indicate that it was coming from the null origin, so I was unable to test that that particular vulnerability was closed.
Do you know how to get curl to use the null origin? Did you find this information helpful? Let me know in the comments.