The Permissions-Policy Header Explained
AI generated
OWASP
0x00
Security · OWASP · HTTP Headers
The Permissions-Policy Header Explained
Locking down browser features on purpose

The Permissions-Policy header lets a page decide which powerful browser interfaces such as camera, microphone or location can be used at all, both for the page itself and for any embedded iframes. We cover the syntax, the difference from its predecessor Feature-Policy, and a practical configuration for a typical Magento shop.

14 min read HTTP Headers Browser Security

1. Why Controlling Browser Features Belongs in a Security Strategy

Modern browsers expose an ever growing set of powerful APIs to web pages: access to camera and microphone, location, vibration, motion sensors, or the Payment Request API. Every one of these interfaces can be useful for a legitimate purpose, a video call feature or a store locator relying on geolocation, but each also carries abuse potential if injected third party code, a compromised ad script, or a malicious embedded iframe reaches for it without the site owner ever knowing.

The Permissions-Policy header closes exactly that gap by defining, at the HTTP level, which browser features are even available to a document and all iframes embedded within it, regardless of whether some piece of JavaScript ever attempts to use them. Without the header, only the same-origin policy and the behavior of individual iframes decide which interfaces are reachable, which tends to be far more permissive than necessary.

2. Syntax and Fundamentals of the Permissions-Policy Header

The header follows the structured field syntax and lists, for every directive, an allowlist of origins permitted to use that feature. Two empty parentheses mean nobody may use the feature, not even the page's own origin. The keyword self permits only the page's own origin, while concrete domains in quotes unlock additional, trusted third parties, for example an embedded video widget.

Multiple directives are combined in a single header value, separated by commas. If a directive is missing entirely, the browser's specification default applies, and that default varies in how permissive it is depending on the feature. It is therefore worth naming every security-relevant feature explicitly rather than relying on browser defaults, which genuinely differ between Chrome, Firefox and Safari.


Permissions-Policy: camera=(), microphone=(), geolocation=(self),
  payment=(), usb=(), xr-spatial-tracking=(), fullscreen=(self),
  autoplay=(self), picture-in-picture=(self)

3. From Feature-Policy to Permissions-Policy: What Changed

Feature-Policy was the historical predecessor, introduced in browsers around 2018 with a syntactically different notation: origins were written in quotes and separated by spaces, for example camera 'self' https://example.com. Permissions-Policy replaces Feature-Policy, uses the more modern structured field syntax with parentheses, and is the authoritative standard in current browsers, while Feature-Policy has since been removed from many browsers or is treated as an alias at best.

Anyone who finds older documentation or code samples written in Feature-Policy syntax should not copy it unchanged, because modern browsers simply ignore a header whose syntax no longer matches the current specification. For maximum compatibility with older browser versions it can make sense to send both headers in parallel during a transition period, with the clear focus on Permissions-Policy since Feature-Policy is considered deprecated.

4. Available Directives at a Glance

The specification defines a growing list of directives, including camera, microphone, geolocation, payment, usb, midi, magnetometer, gyroscope, accelerometer, fullscreen, autoplay, encrypted-media, picture-in-picture and xr-spatial-tracking. Each directive controls exactly one browser feature, and not every API is equally supported across every browser, which makes checking current compatibility tables worthwhile before shipping a policy to production.

For most conventional web shops, the vast majority of these features are simply superfluous. A shop without its own video conferencing feature, without an in-browser payment integration through the Payment Request API, and without AR product previews needs neither camera nor usb nor xr-spatial-tracking, and should consistently disable these features to shrink the attack surface, even without a known concrete abuse case today.

5. Restricting Iframes: How the Header Acts as a Ceiling

The interplay with embedded iframes, from payment providers, ad networks or video platforms, matters most. The parent document's Permissions-Policy header acts as a ceiling: even when an iframe explicitly requests camera or microphone through its own allow attribute, access stays denied unless the parent page has granted that feature to the iframe's domain via the header.

This dual control layer, a header at the document level plus an allow attribute at the iframe level, prevents an embedded third party script from unilaterally gaining access to sensitive interfaces, even if it tries to manipulate its own iframe tag accordingly. Site owners should therefore review, for every embedded third party iframe, exactly which features it genuinely needs and unlock only those for that specific domain.

6. Difference from Content-Security-Policy: Two Complementary Headers

Permissions-Policy is frequently confused with Content-Security-Policy, even though the two serve different purposes. CSP controls which resources, scripts, stylesheets or images, may be loaded at all and from which sources, primarily protecting against cross-site scripting and data injection. Permissions-Policy operates one level higher and does not control resource loading but access to browser APIs after the code has already loaded and executed.

The two headers complement rather than overlap each other: a strict CSP prevents unauthorized code from ever reaching the page, while a strict Permissions-Policy additionally ensures that even legitimately loaded but compromised code cannot abuse sensitive hardware interfaces. A shop that only configures one of the two headers properly leaves an entire defense layer unused.

7. Practical Configuration for a Typical Magento Shop

For a typical Hyva-based Magento shop without its own video chat feature, without native payment hardware integration, and without AR features, a restrictive baseline configuration makes sense. Camera, microphone, usb, midi and xr-spatial-tracking get disabled entirely, geolocation is allowed at most for the page's own origin if a store locator genuinely needs it, and payment is only unlocked when an in-browser payment method through the Payment Request API is actually in use.

Fullscreen and picture-in-picture remain useful for the page's own origin, for embedded product videos for example, while autoplay likewise stays limited to self to stop embedded third party ads from playing automatically with sound. The header can be set centrally in the nginx vhost configuration or through a Magento response header extension, so it applies consistently to every response without touching individual templates.

8. Testing and Validation: Spotting Misconfigurations

After setting the header, a systematic check through the developer tools of any major browser pays off, where the actually delivered response headers can be inspected under the application security or network tab. Many browsers additionally log a console warning whenever a script tries to reach a feature blocked by policy, which provides valuable clues during testing about which features a page genuinely needs.

A common mistake is an overly restrictive configuration that breaks legitimate functionality, for example when a payment provider's iframe suddenly can no longer use its own payment feature because the parent policy never granted it for that domain. A structured test pass through every critical user flow after each policy change prevents a well-intentioned security measure from disrupting actual business operations.

9. Limitations of the Header and Browser Compatibility

Permissions-Policy reliably protects against abuse of the covered browser APIs, but it does not replace other security measures. An attacker who has already gained access to user data through an unrelated vulnerability, a classic cross-site scripting flaw with no connection to hardware APIs, is not stopped by this header. The measure addresses one specific attack vector and has to remain part of a broader security strategy, not a substitute for one.

Browser support is also not fully uniform: while Chrome and Chromium-based browsers support most directives comprehensively, individual features in Firefox or Safari sometimes lag behind or get interpreted differently. A shop should therefore consult current compatibility tables regularly and configure the header so it causes no harm in browsers that do not support a given directive, since unknown directives are simply ignored per the specification.

Directive Purpose Recommendation for a Magento Shop Risk of an Overly Open Configuration
camera Access to the device camera Disable entirely: camera=() Third party script can request camera access
microphone Access to the microphone Disable entirely: microphone=() Unnoticed eavesdropping via compromised code
geolocation Determining the user's location self only, if a store locator exists Location data leaked to embedded third parties
payment Access to the Payment Request API self only when actively used, otherwise disable Manipulated payment dialogs via third party code
usb Access to WebUSB devices Disable entirely: usb=() Unauthorized access to connected USB devices

Mironsoft

Security audits, OWASP-compliant hardening, and secure architecture

Applications that actually hold up against a real attack attempt?

We review existing applications for classic OWASP vulnerabilities, insecure authentication, and missing input validation, then build an architecture that structurally reduces attack surface instead of just patching individual symptoms.

Security Audit

Systematically checking OWASP Top 10, auth flows, and input validation for vulnerabilities.

Secure Architecture

Building rate limiting, encryption, and access controls correctly from the ground up.

Incident Readiness

Establishing logging, monitoring, and response processes for when things go wrong.

10. Summary

Permissions-Policy Header: The Essentials at a Glance

Core Idea

The header defines which browser APIs a page and its iframes can even use.

Predecessor

Feature-Policy used a different syntax and is now considered deprecated.

Effect on Iframes

The header acts as a ceiling above any single iframe's allow attribute.

Magento Practice

Disable camera, microphone, usb and xr tracking entirely in most shops.

11. FAQ: Permissions-Policy Header: The Essentials at a Glance

1What exactly does the Permissions-Policy header do?
It defines at the HTTP level which powerful browser interfaces, such as camera, microphone or geolocation, are actually usable for a document and all embedded iframes.
2What is the difference between Permissions-Policy and Feature-Policy?
Feature-Policy was the predecessor with a different syntax, where origins were written in quotes and separated by spaces. Permissions-Policy uses the more modern structured field syntax with parentheses and is the current standard.
3What does camera=() mean in the header?
The empty parentheses mean nobody is allowed to use the camera, not even the page itself.
4Can an iframe bypass Permissions-Policy restrictions?
No. The parent document's header acts as a ceiling. Even when an iframe requests a feature through its own allow attribute, access stays denied if the policy has not granted it for that domain.
5Is Permissions-Policy a replacement for Content-Security-Policy?
No, the two complement each other. CSP controls which resources may be loaded, while Permissions-Policy controls access to browser APIs after loading.
6Which features should a typical Magento shop disable?
In most cases camera, microphone, usb, midi and xr-spatial-tracking, since these features are not needed during normal shop operation.
7How do you verify the header is delivered correctly?
The browser developer tools let you inspect the actually sent response headers, and many browsers additionally log console warnings whenever a blocked feature access is attempted.
8What happens when a directive is missing from the header?
The browser specific specification default applies, and that default can be more or less permissive depending on the feature and the browser.
9Does Permissions-Policy need to be set on every response individually?
No, the header can be set centrally in the web server configuration so it applies automatically to every response without touching individual templates.
10Is Permissions-Policy supported equally across all browsers?
Not fully. Chrome and Chromium-based browsers support most directives comprehensively, while individual features in Firefox or Safari sometimes differ or are missing.