Permissions Policy
Lock down camera, geolocation, payment, and other powerful features with Permissions-Policy headers and iframe allow.
- browser
- permissions-policy
- security
- iframes
- headers
Permissions-Policy (formerly Feature-Policy) is an HTTP response header that enables or disables browser features for your document and descendants. Use it so XSS or a third-party iframe cannot casually call camera, mic, or payment APIs you never needed.
Docs: MDN Permissions-Policy, Permissions Policy spec.
Header shape
Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=(self), interest-cohort=()
| Syntax | Meaning |
|---|---|
feature=() |
Off for everyone including self |
feature=(self) |
Only same origin |
feature=(self "https://cdn.example") |
Self + origin |
feature=* |
All origins (rare; think carefully) |
Features frontend teams actually set
| Feature | Notes |
|---|---|
camera / microphone |
Video calls only on known pages |
geolocation |
Maps flows only |
payment |
Payment Request API |
fullscreen |
Often allowed for video |
autoplay |
Media policy |
clipboard-write |
Tighter on untrusted surfaces |
usb / serial / bluetooth |
Admin tools only |
interest-cohort |
Historical FLoC disable pattern |
Directive availability evolves — check current MDN before assuming a token exists.
iframe delegation
<iframe
src="https://payments.example/checkout"
allow="payment (self); fullscreen"
sandbox="allow-scripts allow-same-origin allow-forms"
></iframe>
The effective policy is constrained by both the parent Permissions-Policy and the iframe’s allow. Sandbox is separate — Sandboxing iframes.
Debugging denials
APIs fail closed when policy blocks them. Distinguish:
- Policy block
- User permission prompt deny
- Missing HTTPS / secure context
Chrome may log policy violations in the console / Reporting API when configured.
Rollout tips
- Start with disabling features you never use site-wide.
- Open holes only on routes that need them (different HTML/document policies via edge config).
- Inventory third-party embeds before locking
autoplayorfullscreen. - Prefer Permissions-Policy over legacy Feature-Policy — legacy notes.
Interview out-loud
“Permissions-Policy allowlists powerful APIs per document. Empty list disables; self and listed origins re-enable. Combined with iframe allow and sandbox it limits what third parties and XSS can touch.”
Example hardened baseline
Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
Open holes per-route at the reverse proxy when a feature needs them. Document exceptions next to the product feature flag.
Embed negotiations
When a vendor requires camera or payment in an iframe, force them to document exact tokens for allow and the parent Permissions-Policy exceptions. Add a contract test page that asserts navigator.mediaDevices fails on pages that should not have camera access. Policy drift happens when someone pastes a vendor snippet into the root layout.
Related
- Feature Policy legacy notes
- Sandboxing iframes
- Content Security Policy
- Frontend security threat model
Further depth
Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.
Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.
Further reading
Related guides
- Feature Policy Legacy NotesFeature-Policy renamed to Permissions-Policy: migration notes, old header syntax, and what still matters.
- Content-Type and MIME SniffingWhy Content-Type matters, how MIME sniffing works, X-Content-Type-Options: nosniff, and XSS-ish pitfalls.
- CORS Explained for FrontendWhy the browser blocks cross-origin responses, what Access-Control-* headers mean, preflight, credentials, and how to fix real frontend errors.
- Cross-Origin Embedder PolicyCOEP require-corp / credentialless: cross-origin isolation, SharedArrayBuffer, and embedding requirements.
- Cross-Origin Opener PolicyCOOP same-origin and same-origin-allow-popups: sever window.opener, process isolation, and OAuth popups.