The Permissions-Policy HTTP response header is the W3C-spec mechanism for controlling which powerful browser features the page and its embedded iframes are allowed to use. Each feature has an "allowlist" of origins that may invoke it; setting feature=() (empty allowlist) disables the feature entirely for the page and all iframe descendants.
Syntax:
Permissions-Policy: camera=(), microphone=(), geolocation=(self), payment=(self "https://checkout.example.com")
Allowlist syntax:
(): empty -- no origin can use the feature (deny-all)(self): only the page's own origin(self "https://other.com"): page's origin + a specific other origin*: any origin- Multiple features comma-separated:
camera=(), microphone=()
Why explicit policies matter:
The default for most features is self (allow on the same origin). This means a third-party iframe injected via XSS, a misconfigured embed, or a compromised CDN script can request access to powerful APIs the page never intended to expose. Explicitly setting camera=() closes the capability for the page AND for every iframe nested inside it -- the policy inherits and tightens, but child policies cannot loosen the parent's deny.
High-risk features (the BeaverCheck Permissions-Policy granularity analyzer treats coverage of these as the score):
- camera / microphone -- eavesdropping risk
- geolocation -- privacy / location tracking
- payment -- financial fraud potential via Payment Request API
- usb / serial -- direct hardware access
- midi -- low-level audio/MIDI protocol
- accelerometer / gyroscope / magnetometer -- motion / orientation sensors (fingerprinting risk)
Lower-risk but still controllable features include fullscreen, picture-in-picture, autoplay, encrypted-media, publickey-credentials-get (WebAuthn), and many more -- the full list is in the W3C registry.
Legacy Feature-Policy header:
The previous incarnation (pre-2020) used Feature-Policy with a different syntax (space-separated allowlists, no parentheses). Browsers support both during the transition period, but new code should use Permissions-Policy. The BeaverCheck analyzer accepts either header name (Permissions-Policy taking precedence when both are present).
The granularity analyzer measures coverage of high-risk features rather than just header presence. A page with Permissions-Policy: fullscreen=() technically has the header set but provides almost no security benefit -- the high-risk-feature coverage is 0/10. The score reflects the actual protection delivered, not the formal compliance.