Permissions-Policy

No Permissions-Policy header restricts powerful browser features. Any script on the page, including third-party embeds and injected code, may request the camera, microphone, location and similar APIs.

Do this: Send Permissions-Policy denying camera, microphone and geolocation. Without it, any embedded frame can ask for the camera, microphone or location in your site's name.
PassA Permissions-Policy header restricts powerful browser features.
LowNo valid Permissions-Policy header restricts browser features.

The fix, in one snippet

Example to adapt Deny what you do not use
Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=()

Illustrative values. Change the paths, hostnames and options to match your own site before using it.

The sections below explain what is tested, why it matters and the alternatives.

What we test

Scan.now reads the Permissions-Policy header on the response to / and parses it as a structured dictionary, for example camera=(), microphone=(), geolocation=(self). The check passes when a syntactically valid header is present and restricts at least one feature. It is reported as low when the header is absent. It also flags a header written in the old Feature-Policy syntax (camera 'none'), which browsers will not parse as Permissions-Policy, and notes when a legacy Feature-Policy header is present on its own. Features granted to everyone with * are listed for review. Because Chromium implements the header fully while Firefox and Safari support only a subset (mainly through the iframe allow attribute), the protection is strongest for Chrome and Edge users.

Why it matters

Permissions-Policy lets a page declare which powerful features it and its iframes may use. It does not fix a vulnerability by itself; it limits the blast radius of one. If an advert iframe or an injected script asks for the camera, the browser normally shows a permission prompt in your site's name, and a distracted user may accept. With camera=() the request is denied before any prompt appears. The same applies to geolocation, microphone, payment handlers, USB and screen capture. The header also has a privacy role: browsing-topics=() opts the page out of Chrome's Topics API, and interest-cohort=() was the equivalent for the earlier FLoC trial. A site that never uses these features has no reason to leave them enabled. The security headers guide lists the feature names.

How to fix it

Deny everything you do not use. A conservative starting point for a typical content site:

Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), browsing-topics=()

nginx:

add_header Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), browsing-topics=()" always;

Apache:

Header always set Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), browsing-topics=()"

Helmet does not set this header, so in Express add it directly:

app.use((req, res, next) => {
  res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
  next();
});

Cloudflare's Managed Transform "Add security headers" does not add Permissions-Policy; use a Transform Rule that sets a static response header. To allow a feature for your own origin only, use geolocation=(self); to grant it to a specific embed, camera=(self "https://meet.example") plus a matching allow="camera" attribute on the iframe.

Where this fits

Permissions-Policy is check 6 of 13 that the website vulnerability scanner runs under http security headers, ordered the way they are worth fixing. That ordering is the point: Fixing this one while the check above it still fails buys less than it looks like.

Fix this one first

Above it in the same category sits Cross-Origin-Opener-Policy (low), where the page does not set Cross-Origin-Opener-Policy, so windows it opens, or that open it, from other origins keep a reference to it and share its browsing context group. An attacker who has that does not need this, so it is the better use of the same hour.

What fixing this still leaves open

Permissions-Policy closes one route in. Immediately below it: Referrer-Policy, where no Referrer-Policy is set, or it is set to a value that sends full URLs to other sites; Server version disclosure, where the Server header reveals the exact web server software and version, such as Apache/2.4.58 (Ubuntu) or nginx/1.24.0, which lets attackers and bots match it to known vulnerabilities without any probing; X-Content-Type-Options: nosniff, where responses lack X-Content-Type-Options: Nosniff, so browsers may guess a content type and execute a file as script or style when the server said it was something else.

Found in the same scan

The website vulnerability scanner reports this alongside checks from other categories that are at least as serious, including Certificate chain and hostname validation, where the certificate presented for this hostname did not validate: The chain does not reach a trusted root, an intermediate is missing, the name does not match, or the certificate is self-signed or expired, and Exposed .env configuration file, where a .env configuration file is served from the web root. A single run of website vulnerability scanner answers all of them at once.

Prompt for an AI Hand this check to an assistant Sign in to copy it
The first few lines
You are a senior web engineer. I ran a security and SEO scanner against my site and it reported the finding below. Fix it properly rather than suppressing the symptom.

Finding: Permissions-Policy (low severity)
Scanner check id: permissions-policy
17 more lines, including the evidence and the exact fix

The rest of this prompt names the pages and line numbers we found the problem on, the configuration to change, and the constraints a good answer has to respect. It is free, it just needs an account so the work is not scraped wholesale.

Sign in with Google

Signing in is free and takes one click. We store your email address and nothing else.

References

  1. MDN: Permissions-Policy
  2. W3C: Permissions Policy
  3. Chrome for Developers: Controlling browser features with Permissions Policy

Related guides