Everyone on the net wants to disable puppeteer from enforcing the same-origin policy, I actually want to test that same-origin-policy enforcement works! but it doesn't and i don't know why, this is what I do:
import puppeteer from 'puppeteer';
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com'); // <= THE ORIGIN
// Some error listeners
page.on("pageerror", function(err) {
theTempValue = err.toString();
console.log("Page error: " + theTempValue);
});
page.on("error", function (err) {
theTempValue = err.toString();
console.log("Error: " + theTempValue);
});
// THE EVALUATE
await page.evaluate(async (otherSiteURL, myOrigin) => {
console.log('the origin: '+ myOrigin); // prints https://example.com
console.log('otherSiteURL: '+ myOrigin); // prints https://some-other-site.com
let r = await fetch(otherSiteURL, {mode:'cors', method:"GET", headers: {Origin:myOrigin}});
r = await r.json();
// *** I have access to the response and no error has been triggered ***
console.log('Response is visible, while it shouldn't be due to cors: ' + JSON.stringify(r));
}, 'https://some-other-site.com', 'https://example.com');
await browser.close();
})();
As you can see I am in the context of page 'https://example.com'
and from evaluate function I am executing a fetch to some-other-site
url which i am the owner of and indeed I've checked that the
Access-Control-Allow-Origin header returned in the response is not *
and not https://example.com
, Hence this is 100% same-origin-policy violation and should result in the browser blocking access to the response, and reporting a CORS error
So Why on earth Puppeteer allows me to see the response and not throwing a CORS error ? what am I doing wrong - I WANT to see CORS error!
I believe your server CORS policy is set up incorrectly relative to your expectations in some way or another, or you're making some sort of fundamental mistake.
Puppeteer's evaluate
literally runs the same code you can in the console. From the perspective of the server, both should generate the exact same incoming HTTP request. As far as I know, page.evaluate()
does nothing special that'd change the CORS characteristics. It should be easy to corroborate this in the network tab.
For example, running a fetch
cross-origin from https://www.example.com to Wikipedia gives a CORS error when executed by hand (by typing the contents of evaluate
in the browser console dev tools), as well as programmatically with Puppeteer:
const puppeteer = require("puppeteer"); // ^19.1.0
const {setTimeout} = require("timers/promises");
let browser;
(async () => {
browser = await puppeteer.launch({
devtools: true,
headless: false,
});
const [page] = await browser.pages();
const url = "https://www.example.com";
await page.goto(url, {waitUntil: "domcontentloaded"});
const msg = await page.evaluate(`
fetch("https://en.wikipedia.org/wiki/Things_Fall_Apart")
.catch(err => err.message)
`);
console.log(msg); // => Failed to fetch
await setTimeout(10 ** 6); // keep open to view console
})()
.catch(err => console.error(err))
.finally(() => browser?.close());
In both cases, the console shows the expected error
Access to fetch at 'https://en.wikipedia.org/wiki/Things_Fall_Apart' from origin 'https://www.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
If this code allowed CORS to be bypassed, then either a fundamental security mechanism of the internet would be broken, clearly not something Puppeteer can do; or Puppeteer somehow ran the evaluate
from the Wikipedia origin, plainly not the case.