ASVS 5.0 requirement V3.5.8 says authenticated resources, such as images, videos, scripts and other documents, must be loadable or embeddable on behalf of the user only when intended. You can do it by strictly validating Sec-Fetch-* request headers, or by setting a restrictive Cross-Origin-Resource-Policy response header so the browser blocks the returned content. It is a Level 3 requirement.
Why it matters
A hostile page can embed your private resources with an img, video, script or iframe tag. The browser sends the victim's cookies, your server returns the file, and while the attacker cannot read the bytes directly, side channels leak information: whether the resource exists, its size, its type, timing, and for scripts the values they define. Cross-site search attacks use these signals to learn private data character by character.
How to implement it
Option one is a response header on authenticated resources:
Cross-Origin-Resource-Policy: same-origin
Use same-site if sibling subdomains load them, and cross-origin only for public assets.
location /files/ {
add_header Cross-Origin-Resource-Policy "same-origin" always;
}
Option two is checking fetch metadata on the server:
function allowSameSiteLoads(req, res, next) {
const site = req.get("Sec-Fetch-Site");
if (site === "same-origin" || site === "same-site" || site === "none") return next();
res.status(403).end();
}
app.use("/files", requireAuth, allowSameSiteLoads);
none covers a user typing the URL or opening a bookmark. Decide what to do when the header is absent, since old clients do not send it. For authenticated resources, refusing is the safer default.
How to test it
curl -sI https://app.example.com/files/report.png -b cookies.txt | grep -i cross-origin-resource-policy
curl -si https://app.example.com/files/report.png -b cookies.txt \
-H "Sec-Fetch-Site: cross-site" -H "Sec-Fetch-Mode: no-cors" -H "Sec-Fetch-Dest: image" | head -1
The first should show the policy, the second should return 403. Then place an image tag pointing at the private file on a page from another origin and confirm it does not render in a signed in browser.
Common mistakes
Policy only on documents. Cover images, media, downloads and scripts.
cross-origin applied by default. Reserve it for public files.
Treating missing Sec-Fetch headers as allowed.
Forgetting CDNs. Make sure the header survives the edge.
Quick check
Is CORP the same as CORS?
No. CORP tells the browser who may load a resource at all. CORS controls whether a page may read a cross-origin response.
Sources
- OWASP ASVS 5.0, requirement V3.5.8
- MDN: Cross-Origin-Resource-Policy