Skip to content

fix(security): restrict iframe allow policy to low-risk features - #25

Merged
herewithme merged 5 commits into
developfrom
fix/iframe-allow-policy
Nov 11, 2026
Merged

herewithme merged 5 commits into
developfrom
fix/iframe-allow-policy

Conversation

@herewithme

@herewithme herewithme commented Nov 5, 2026 •

Copy link
Copy Markdown
Member

Fixes #24

What

  • allow values are filtered against a Permissions Policy feature allowlist: accelerometer, autoplay, clipboard-write, encrypted-media, fullscreen, gyroscope, picture-in-picture, web-share.
    • Unknown or sensitive directives (camera, microphone, geolocation, display-capture, payment…) are dropped.
    • Origin lists are removed, so each kept feature defaults to the iframe src origin.
    • If nothing remains, the attribute is omitted.
  • New filter blockparty_iframe_allowed_features to extend the list.
  • The obsolete allowpaymentrequest is removed from the allowlists.
  • The editor preview uses ServerSideRender, so it goes through BlockRenderer like the front end (suggestion on #24). Filtering lives in PHP only, and the filter applies to the preview too. The JS ALLOWED_FEATURES, sanitizeAllowValue() and convertAttributesToProps() are removed; parseIframeCode() and isSafeIframeUrl() only help with input.
    • The preview sends the form state, so "View" before "Add iframe" shows what was typed (Bugbot finding).
    • align and style are not sent to the preview: the editor wrapper already applies them, and skipBlockSupportAttributes keeps style.dimensions.
    • Adds the @wordpress/server-side-render dependency (6.20.0, default import for WordPress 6.7–6.8 compatibility).
  • aria-* / data-* attributes are checked with str_starts_with() / startsWith() instead of a regex (review suggestion).
  • The deprecated save stays unfiltered on purpose. It must reproduce the old markup for block validation and is never mounted.

Tests

No automated test suite exists in the repo. Checks run locally: npm run lint:js src, phpcs, npm run build.

Manual test in the block editor (WordPress 7.1.4, wp-env, admin account):

  • Saved block with allow="camera *; fullscreen; microphone https://evil.test; autoplay", onload and data-test → preview and front end both render allow="fullscreen; autoplay" and data-test, no onload.
  • Preview size matches the block wrapper: 16/9 (645×363), default square (645×645), aspect ratio changed to 4/3 in the editor (645×484).
  • New block, pasted <iframe … allow="geolocation *; picture-in-picture" onload="…">, "View" without "Add iframe" → preview shows the typed iframe with allow="picture-in-picture" only.

Not tested: contributor account, blockparty_iframe_allowed_features in the preview.

Review notes

  • Behaviour change: existing blocks with allow="camera; microphone" (for example, some video-call embeds) lose those permissions. Sites that need them can extend the list with the filter.
  • Preview rendering now needs a request to the block-renderer REST endpoint (debounced while typing).

🤖 Generated with Claude Code


Note

Medium Risk
Security-sensitive iframe attribute handling changes behavior for existing embeds that relied on broad allow values; editor preview now depends on server render.

Overview
Tightens iframe Permissions Policy delegation so contributors without unfiltered_html cannot pass sensitive allow features (camera, microphone, geolocation, payment, etc.). Only a fixed low-risk feature set is kept, origin lists in directives are stripped, empty values drop the attribute, and obsolete allowpaymentrequest is no longer output.

Editor preview now uses server-side rendering via ServerSideRender, so the same BlockRenderer path filters attributes for both front end and preview. Client-side preview attribute conversion (convertAttributesToProps) is removed; paste parsing still uses a convenience allowlist in JS.

Adds blockparty_iframe_allowed_features to extend the PHP feature list, @wordpress/server-side-render as a dependency, and editor SCSS so the nested preview fills block dimensions.

Reviewed by Cursor Bugbot for commit e9d9e51. Bugbot is set up for automated code reviews on this repo. Configure here.

asadowski10 and others added 2 commits November 5, 2026 18:59
Users without unfiltered_html could set an arbitrary `allow` value and
delegate camera, microphone, geolocation or display-capture to any
embedded origin.

- Filter `allow` directives against an allowlist (filterable on the
  front end with `blockparty_iframe_allowed_features`) and drop origin
  lists, in PHP and in the editor preview.
- Stop rendering the obsolete `allowpaymentrequest` attribute.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@herewithme
herewithme requested a review from Rahe November 5, 2026 22:04

Rahe commented Nov 6, 2026

Copy link
Copy Markdown
Member

is_allowed_iframe_attribute(): the aria-* / data-* regex can be replaced with str_starts_with() (PHP 8.0+, plugin requires 8.1). The first regex already validates the name syntax, so only the prefix check is needed:

return in_array( $attribute_name, self::ALLOWED_ATTRIBUTES, true )
	|| str_starts_with( $attribute_name, 'aria-' )
	|| str_starts_with( $attribute_name, 'data-' );

Same in utils.js with name.startsWith().


Generated by Claude Code

@Rahe Rahe mentioned this pull request Nov 6, 2026
Render the editor preview through BlockRenderer so iframe attribute
filtering lives in PHP only, and the
`blockparty_iframe_allowed_features` filter applies to the preview too.

- Use ServerSideRender (default import, WordPress 6.7 compatible) with
  skipBlockSupportAttributes; drop convertAttributesToProps(),
  sanitizeAllowValue() and the JS ALLOWED_FEATURES list.
- Make the nested preview markup fill the block wrapper in the editor.
- Check aria-*/data-* attribute prefixes with str_starts_with() and
  startsWith() instead of a regex.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@herewithme

Copy link
Copy Markdown
Member Author

Thanks, applied in 123e26a, following this suggestion: is_allowed_iframe_attribute() now uses str_starts_with() for aria- / data-, and isAllowedIframeAttribute() in utils.js uses name.startsWith(). The name syntax regex stays as the first check.

Side effect: a bare aria- or data- name now passes, where the old regex required at least one character after the prefix. Such attributes have no effect in the browser, so I left it.


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 123e26a. Configure here.

Comment thread src/blockparty-iframe/edit.js Resolved
herewithme and others added 2 commits November 11, 2026 17:14
The server-side preview used the saved block attributes, while "View"
shows the form before "Add iframe" saves it. A new block or a
"Replace" edit then previewed an empty or stale iframe. Merge the form
state into the attributes sent to ServerSideRender, as the former JS
preview did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
skipBlockSupportAttributes keeps `style.dimensions`, so the server-side
preview markup got the aspect ratio again inside the block wrapper and
overflowed it. Drop `align` and `style` from the preview attributes:
the editor wrapper already applies them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@herewithme
herewithme merged commit e068a79 into develop Nov 11, 2026
2 checks passed
@herewithme
herewithme deleted the fix/iframe-allow-policy branch November 11, 2026 16:21
@herewithme
herewithme restored the fix/iframe-allow-policy branch November 11, 2026 16:23
@herewithme
herewithme deleted the fix/iframe-allow-policy branch November 11, 2026 16:24
This was referenced Nov 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security: iframe allow attribute lets contributors delegate sensitive browser permissions

3 participants