CORS Demos

Welcome to a lab which contains examples of many of the CORS request types you'll commonly see on tests. Some work and some fail, hopefully I've explained why, but in case not, there are a bunch of references at the end which might come in handy.

For more information on the project, see The CORS Demos Project.

Basic GET

A basic GET request to a page which returns the header Access-Control-Allow-Origin:


Basic GET Origin Not Allowed

A basic GET to a page which returns the header Access-Control-Allow-Origin: made-up-site.not.exists. As this does not match the origin, the request will be rejected.


Basic POST

A basic POST request to a page which returns the header Access-Control-Allow-Origin:



A GET request to a page which returns the header Access-Control-Allow-Methods: PUT.

This might be expected to fail as GET != PUT, but will succeed as there is no preflight check for basic GET and POST requests and so the header is ignored.



A PUT request to a page which returns the header Access-Control-Allow-Methods: PUT.

This will succeed as the methods match. Watch for the OPTIONS request go first, this is the preflight check, assuming it matches, the PUT is sent second.



A DELETE request to a page which returns the header Access-Control-Allow-Methods: PUT.

This will fail as the preflight will see that the endpoint only allows PUTs and so will not make the DELETE request.


Basic GET Allowed by CSP

This is the same as "Basic GET", but separated out to highlight that the Content Security Policy has a connect-src entry for the page which allows the connection to be made.

Something to note, it is the Content Security Policy for this page that is in charge of what content can be accessed, not the CSP on the destination page.


Basic GET Blocked by CSP

Same as "Basic GET Allowed by CSP", but this time, the endpoint is not covered by this site's Content Security Policy, and so the browser will not allow the request to be made.



To make the next three calls a bit more realistic, click here to go over to the server to start a session and to be logged in as a user.

With Authentication Credentials

The Access-Control-Allow-Credentials response header tells a browser whether or not to allow the calling script to access the response when credentials were passed with a request.

Credentials are defined as cookies, authorization headers and TLS client certificates, and so in most cases this will probably be standard session cookies.

By default, these are not sent with requests created by either XMLHttpRequest or fetch(). To ask them to send credentials, set the withCredentials flag on the XMLHttpRequest object to true or credentials: 'include' if using fetch().

Setting this flag does not trigger a preflight request, the decision to do so is made based on other rules covered in these demos. When the browser receives the response, it will check for the Access-Control-Allow-Credentials. If the header is set to true, the script is allowed to see the contents of the response. If it is false, or the header is not present, then the script is not allowed to see the response.


With Authentication Credentials Not Allowed

Same as above, but this time, the server will reply with Access-Control-Allow-Credentials: false, to indicate it does not want the response passed on to the calling JavaScript.

The GET request will still be sent with any credentials the browser has stored, the server will handle the request taking into consideration those credentials, and the response will be returned to the browser, however, the browser will not pass the response through to the calling JavaScript. You can confirm this by running your requests through a proxy and watching the traffic.


With Authentication Credentials Wildcard Origin

Again, same as above, but this time, despite the server returning Access-Control-Allow-Credentials: true, the request will be rejected as the Access-Control-Allow-Origin header is set to a wildcard (*) rather than a specific hostname.


With Extra Header Allowed

The request will contain an extra header, username. The server will return Access-Control-Allow-Headers: username, saying that it will accept the header.


With Extra Header Not Allowed

Same as above, but this time trying to send the header password. The server does not accept this header and so the request will not be made after the preflight.


Cross-Origin Read Blocking - CORB

OK, CORB isn't CORS, but I'm throwing it in as a bonus as I did some research on it while building this lab.

If you don't know about CORB, it is an in-browser protection where the browser sniffs the response to certain requests to check if the data returned is of a type which will cause problems when used by the calling object. One example is an image tag making a request and getting a JSON object returned. Trying to render a JSON object as an image will obviously fail and can potentially be used for malicious purposes. Because of this, the browser will prevent the response from being passed to the image, stating CORB as the reason.

As you can see from the demos below, it is not the MIME type which is being looked at, it is the actual data in the response body which is being checked.

This is an over simplification, for a better explanation, see this CORB Explainer.

Chrome reports this as a warning in the console, Firefox does not.

CORB Allowed

An image is written into the DOM, the data loaded into the image is a valid PNG file.


CORB Not Allowed - Correct MIME Type

Same as above, but this time rather than returning image data, the server will return a JSON object with the MIME type of application/json.


CORB Not Allowed - Incorrect MIME Type

Same as above, but this time the data will be returned with a MIME type of image/png.



Lab created by Digininja, for more information see The CORS Demos Project.