Low Security Header

Permissions-Policy

Discover how Permissions-Policy controls browser features and API access for enhanced security.

SiteSecurityScore Team·10 min read·Updated Feb 20, 2026

Permissions-Policy (formerly Feature-Policy) is a HTTP header that allows you to control which browser features and APIs can be used by your website and any embedded content. This helps reduce your attack surface and protects user privacy.

Why Control Browser Features?#

Modern browsers expose powerful APIs including camera, microphone, geolocation, payment processing, USB access, and more. While these APIs enable rich user experiences, they also create attack surface. If your website does not use the camera, there is no reason for third-party scripts or iframes on your page to have access to it. Permissions-Policy lets you explicitly disable features you do not need.

  • Third-party scripts embedded via ads or analytics could access sensitive browser APIs
  • Malicious iframes can request permissions that appear to come from your domain
  • Disabling unused features reduces your attack surface and protects user privacy
  • The header replaces the older Feature-Policy header with an improved syntax
Formerly Feature-Policy

Permissions-Policy was previously called Feature-Policy. The new header uses a different syntax (structured headers format). Most browsers now support Permissions-Policy, though some older versions only recognize Feature-Policy.

How Permissions-Policy Works#

The header uses a structured syntax where each directive controls a specific browser feature. For each feature, you specify an allowlist of origins that can use it. Empty parentheses () mean no origin is allowed, (self) means only your own origin, and you can list specific trusted domains.

  • Each feature is controlled independently with its own allowlist
  • Empty parentheses () disable the feature for all origins including your own
  • (self) allows the feature only for your own origin
  • You can list specific external origins that should have access
  • The * wildcard allows all origins (defeats the purpose for most features)
Configuration
# Syntax breakdown Permissions-Policy: feature-name=(allowlist) # Examples camera=() # Disabled for everyone camera=(self) # Only your origin camera=(self "https://meet.example.com") # Your origin + specific domain camera=* # All origins (not recommended)

Common Features to Control#

There are dozens of features you can control with Permissions-Policy. Here are the most commonly configured ones and when you should enable or disable them.

  • camera, microphone: Disable unless your app uses video/audio features
  • geolocation: Disable unless your app needs location services
  • payment: Disable unless you use the Payment Request API
  • usb, bluetooth, serial: Disable unless you have specific hardware integration needs
  • autoplay: Control whether media can auto-play on your pages
  • fullscreen: Usually safe to allow for self, restrict for third-party iframes
  • interest-cohort: Disable to opt out of Google's Federated Learning of Cohorts (FLoC)

Implementation Guide#

Start by disabling all features your site does not use, then selectively enable what you need. This deny-by-default approach provides the strongest security posture.

Configuration
# Apache (.htaccess) Header always set Permissions-Policy "\ camera=(), microphone=(), geolocation=(), \ payment=(), usb=(), interest-cohort=()" # Nginx add_header Permissions-Policy \ "camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()" always; # Node.js / Express app.use((req, res, next) => { res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=(), ' + 'payment=(), usb=(), interest-cohort=()'); next(); });

Permissions-Policy and Iframes#

One of the most valuable uses of Permissions-Policy is controlling what embedded iframes can do. Even if a third-party iframe requests camera or microphone access, Permissions-Policy can block it at the document level. You can also use the iframe allow attribute for per-element control.

Layered Control

The HTTP header sets the outermost boundary. The iframe allow attribute can further restrict (but not expand) what the header allows. This layered approach gives you both site-wide defaults and per-element granularity.

Configuration
<!-- Allow camera only for a specific iframe --> <iframe src="https://meet.example.com" allow="camera; microphone" sandbox="allow-scripts allow-same-origin"> </iframe> <!-- The header-level policy still applies as an outer boundary --> <!-- If the header says camera=(), the iframe allow attribute cannot override it -->

Best Practices#

Follow these guidelines for an effective Permissions-Policy configuration that balances security with functionality.

  • Start with all sensitive features disabled and only enable what your application needs
  • Use (self) rather than * for features your site uses to prevent third-party access
  • Audit third-party scripts and iframes to understand what permissions they require
  • Test your policy in a staging environment before deploying to production
  • Review and update your policy when adding new third-party integrations
  • Use the Permissions Policy Generator tool to build your policy visually

Implementation Examples#

Block All Features

Permissions-Policy: camera=(), microphone=(), geolocation=()

Disables camera, microphone, and geolocation for all origins

Explanation: Empty parentheses () mean no origins are allowed to use these features, providing maximum privacy.

Allow for Self Only

Permissions-Policy: camera=(self), microphone=(self)

Allows features only for your own origin

Explanation: The 'self' keyword refers to your own domain. Third-party embedded content cannot access these features.

Allow Specific Domains

Permissions-Policy: camera=(self "https://trusted-video.com")

Allows features for your site and specific trusted domains

Explanation: You can specify multiple origins that are allowed to use sensitive browser features.

Key Directives#

camera

Controls access to camera API

camera=()

microphone

Controls access to microphone API

microphone=()

geolocation

Controls access to geolocation API

geolocation=()

payment

Controls access to payment request API

payment=(self)

References#

Was this helpful?
Share

Test Your Permissions-Policy Configuration

Scan your site to check if Permissions-Policy is properly configured.