Quiz - URLs, origins, and security boundaries
You build a search URL by hand: `?q=${encodeURIComponent(searchTerm)}`. Later, on the server, you parse it with new URLSearchParams(req.url.search). A user searches for the literal string a+b. What goes wrong?
encodeURIComponent and URLSearchParams agree on every character, so the round trip is safe.encodeURIComponent leaves the + untouched, and URLSearchParams decodes that + as a space — so the search term comes back as a b.URLSearchParams throws because the query string was not built by a URLSearchParams instance.+. In a form-urlencoded query, + means space, so URLSearchParams reads a+b as a b. The fix is a posture, not a character lookup: encode and decode with the same model end to end — do both with URLSearchParams.Your base URL comes from a validated environment variable at boot, while a next redirect target comes from a query string a user controls. Which construction pattern fits each?
new URL() for the env-derived base and let it throw; guard the user-supplied next with URL.canParse() before parsing.try/catch so neither can ever crash the request.URL.canParse() for the base and new URL() for next, since user input is the one you want to fail fast on.new URL() throw. Bad user input is data you fully expected to receive, so guard it with URL.canParse() instead of throwing.Classify the pair https://a.github.io and https://b.github.io on both axes.
github.io), different origin.github.io is on the Public Suffix List as an eTLD, so the registrable domain is the whole a.github.io.github.io is an eTLD on the Public Suffix List, so eTLD+1 is the full a.github.io / b.github.io — two unrelated owners, two different sites.A developer wires account deletion to GET /account/delete?id=42 and assumes the same-origin policy protects it from evil.com. Why is the account still deletable from an attacker’s page?
GET fires (e.g. from an <img>), the session cookie attaches, the delete runs — and no CORS error ever appears because the attacker never needed to read the response.fetch, so embedding the URL in an <img> bypasses it entirely as a loophole.GET and show a CORS error, so the account is safe.POST/PUT/PATCH/DELETE, defended by SameSite cookies and CSRF tokens — never a GET.Which of these cross-origin fetch calls trigger a preflight OPTIONS request? Select all that apply.
POST sending Content-Type: application/json.GET carrying an Authorization: Bearer … header.GET with no custom headers and no body.Content-Type all stay on the CORS-safelist. application/json is not safelisted, and Authorization is not a safelisted header — so both preflight. The working reality: any JSON or token-bearing call preflights, which is nearly your whole authenticated API surface.Your client sends fetch(url, { credentials: 'include' }) and the server replies with Access-Control-Allow-Origin: * plus Access-Control-Allow-Credentials: true. The browser blocks the read. What is the fix?
Origin against an allow-list, echo that exact origin back in Access-Control-Allow-Origin, and add Vary: Origin.credentials: 'same-origin' so the wildcard becomes legal again.Access-Control-Max-Age so the browser caches the preflight and stops re-checking the wildcard.Origin, send Vary: Origin so caches key by origin.A cross-origin call fails with the console error “Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.” Where is the bug?
OPTIONS preflight handler returned a non-2xx status — it should return 204 with the CORS headers.fetch call set the wrong mode; switch it to 'no-cors'.Access-Control-Allow-Origin is missing from the real request’s response — add it to the GET/POST handler.OPTIONS and got back a non-OK status, so it cancelled the real request. A CORS error is almost always a server fix — here, make the OPTIONS export return 204 with the headers.Quiz complete
Score by topic