Skip to content

Editorial: define read-back-allowed rendering - #12554

Open
foolip wants to merge 15 commits into
mainfrom
foolip/privacy-preserving-rendering
Open

foolip wants to merge 15 commits into
mainfrom
foolip/privacy-preserving-rendering

Conversation

@foolip

@foolip foolip commented Jun 9, 2026 •

Copy link
Copy Markdown
Member

This is for #11588, but because the concept is unused we can consider it editorial.


/index.html ( diff )
/infrastructure.html ( diff )
/rendering.html ( diff )

Comment thread source Outdated
Comment thread source Outdated
Comment thread source Outdated
@nigelmegitt

nigelmegitt commented Jun 9, 2026 •

Copy link
Copy Markdown

What's the motivation behind privacy-preserving rendering of subtitles and captions not taking into account user preferences? As I understand it, WebVTT rendering done by the UA or OS is already supposed to be privacy-preserving, and the current design choice is that there are no Web APIs for querying user preferences or for extracting styling choices from the rendered captions.

It seems odd that privacy-preservation should have a negative impact on accessibility settings that aren't exposed to pages.

(aside: I actually don't think the argument for prohibiting Web APIs for accessing user settings holds up any more, but that's a whole different discussion)

@annevk

annevk commented Jun 9, 2026

Copy link
Copy Markdown
Member

This is a rendering mode that allows for arbitrary read back. Maybe instead of calling it privacy-preserving we should call it "read-back rendering mode".

@nigelmegitt

Copy link
Copy Markdown

That would be a lot clearer, yes, seems like I got a whole different impression from the name alone.

Not sure if this PR is the right place for the discussion (please point me to the right place: there's no linked issue), but since I'm here: Is this related to test drivers/engines? I'd expect test engines, when inspecting rendering results, to be able to choose whether to use this "read-back rendering mode" or to be able to read back the result rendered with a provided context of specific user settings.

@foolip foolip mentioned this pull request Jun 11, 2026
6 tasks
@foolip foolip changed the title Define privacy-preserving rendering Define read-back-allowed rendering Jun 16, 2026
@foolip

foolip commented Jun 16, 2026

Copy link
Copy Markdown
Member Author

After discussion with @annevk on chat I'll rename it "read-back-allowed rendering" since read back might not actually happen.

@annevk annevk added topic: canvas security/privacy There are security or privacy implications labels Jun 16, 2026
@schenney-chromium

Copy link
Copy Markdown
Contributor

That would be a lot clearer, yes, seems like I got a whole different impression from the name alone.

Not sure if this PR is the right place for the discussion (please point me to the right place: there's no linked issue), but since I'm here: Is this related to test drivers/engines? I'd expect test engines, when inspecting rendering results, to be able to choose whether to use this "read-back rendering mode" or to be able to read back the result rendered with a provided context of specific user settings.

The test drivers/engines is an interesting point we had not considered. We have thought to refer to read-back-allowed in the SVG spec, where there are issues with SVG-as-Image used as an image source in a canvas and the related tainting behavior.

Comment thread source Outdated
Comment thread source Outdated
data</span> is <span>CORS-cross-origin</span> must not be rendered.</p>

<p>During <span>read-back-allowed rendering</span>, controls, subtitles and captions must not be
rendered.</p>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

And same here obvs. Note that, while CORS-violating images still leak sizing info, so observing the geometry via other layout effects doesn't leak any further info, this isn't necessarily true for these elements. Dunno if you can use anchorpos to observe their geometry indirectly, but if we assume that someday you can, this would be an info leak. We probably do mean "as if display:none" here, at least for subs/captions, then? They float on the video so there's no layout side-effects from making them not render boxes.

Probably also useful to clarify that this applies to these elements even on non-CORS-cross-origin videos, just to contrast it with the preceding bullet point.

Comment thread source Outdated
Comment thread source Outdated
Comment thread source
@tabatkins

Copy link
Copy Markdown
Contributor

Ah here we go, the term we want to lean on for "not rendered" is instead "invisible", from Display 4. Not painted, not hit-tested, etc.

@foolip foolip changed the title Define read-back-allowed rendering Editorial: define read-back-allowed rendering Sep 30, 2026
Comment thread source

<p>During <span>read-back-allowed rendering</span>, any <span data-x="CSS box">CSS boxes</span>
generated by controls, subtitles, and captions must be <span data-x="invisible
box">invisible</span>.</p>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This should also apply to audio elements. At least the controls, not sure if audio elements can have captions.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Audio elements can't have captions, but it seems just as well to just make this about all media elements and letting the captions part be a no-op for audio elements.

Comment thread source
<p class="note">This also applies to <code>video</code> elements whose <span>media data</span> is
<span>CORS-same-origin</span>.</p>

<p class="warning">This affects the accessibility of <code>video</code> elements. Authors are

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This seems like the wrong explanation. We are not rendering controls or subtitles because we cannot adhere to accessibility settings without letting the user be fingerprinted.

Comment thread source
<p>During <span>read-back-allowed rendering</span>, any <span data-x="CSS box">CSS boxes</span>
generated by <code>img</code> and <code>input</code> elements whose <span>current request</span>'s
<span data-x="img-req-data">image data</span> is <span>CORS-cross-origin</span> must be <span
data-x="invisible box">invisible</span>.</p>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For img elements we should have an equivalent requirement for controls I think as they can now have controls as well.

Comment thread source
</ul>

<p>During <span>read-back-allowed rendering</span>, <span data-x="widget">widgets</span> must not
use <span>native appearance</span>.</p>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we add an XXX here that we want this to be base appearance?

Comment thread source
the <code data-x="selector-link">:link</code> and <code data-x="selector-visited">:visited</code>
<span data-x="pseudo-class">pseudo-classes</span>. This specification does not specify how to
preserve user privacy, but user agents must align with what they do in other contexts, like
style recalculation and selector matching.</p>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Only a single newline before <h4>? Seems okay if that's consistent, but not sure.

Comment thread source

<p>During <span>read-back-allowed rendering</span>, any <span data-x="CSS box">CSS boxes</span>
generated by <span>CORS-cross-origin</span> content must be <span data-x="invisible
box">invisible</span>. This includes features defined by other specifications, including but not

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure this works because CSS backgrounds are not boxes. I think we have to define for each property how it should behave. E.g., for background it could behave as none.

@annevk

annevk commented Oct 2, 2026

Copy link
Copy Markdown
Member

AI found further leaks:

  • It seems that frames (iframe, frame, embed, object) are not protected as their responses are always seen as CORS-same-origin. I think it's correct they need a special case.
  • Cross-origin poster frames leak.
  • The input element doesn't have a current request so might need its own condition.
  • It suggests that the :visited wording is wrong as the existing protections are at the getComputedStyle() level whereas we need them at the painting level here.
  • Some wording is ambiguous, such as the antialiasing ban, it suggests something like "text must not be rendered with subpixel antialiasing; grayscale antialiasing can be used instead".

That's the most important.

Full AI review
  Blockers
  
  1. source:153661 (+ 153599): Cross-origin frames aren't covered.
     - The dl says iframe/frame need nothing special because "CORS-same-origin frames are not sensitive". CORS-same-origin is defined on responses, and Fetch gives every navigate-mode request "basic" tainting. So by HTML's definition every frame is CORS-same-origin,
       cross-origin ones included.
     - object/embed also fetch with mode "navigate" (source:36716). So <object data="https://other.example/secret.png"> paints a cross-origin image the general rule never catches.
     - The explainer explicitly doesn't paint cross-origin iframes.
     - Fix: add a normative rule under Embedded content. Boxes of iframe/frame/embed/object whose content navigable's active document isn't same origin with the reference document (see S1) are invisible, and so is an object showing an image from a cross-origin URL.
       Same-origin navigables are rendered the same way, recursively. Replace the dl entry.
  2. source:151616: Cross-origin poster frames leak.
     - The poster is fetched no-cors (no mode is set, and crossorigin doesn't apply), but the rule only checks the media data.
     - <video poster="https://other.example/x.png"> with no media, or same-origin media, paints the cross-origin poster.
     - Fix: also cover video elements whose poster frame came from a CORS-cross-origin response.
  3. source:153599–153609: The general rule doesn't fit its own examples.
     - 'background-image' and 'border-image-source' don't generate boxes; they're painted inside the box of the element that uses them.
     - pattern and feImage generate no boxes at all, and SVG elements generate SVG layout boxes, not CSS boxes (source:149882).
     - So for these cases the rule either does nothing or, read loosely, hides the whole element.
     - Fix: phrase it in terms of image data: image data from a CORS-cross-origin response must not be painted (as if fully transparent), e.g. via CSS <image> values or SVG image/use/pattern/feImage.
  4. source:151733: input has no "current request".
     - Only img has one (source:32754), and the rule isn't limited to the Image Button state.
     - Fix: give input its own condition: in the Image Button state, with an image from a CORS-cross-origin response. Its fetch is no-cors (source:54575), so any cross-origin src qualifies.
  5. source:149857: It's unclear whether these "must"s bind anyone.
     - The Rendering intro says "must" isn't used in this section, and that "expected" only binds UAs that claim to support the suggested default rendering. It also says "User agents are not required to present HTML documents in any particular way".
     - The PR adds about a dozen "must"s without changing that intro. These are security requirements, so they have to bind every UA that does read-back-allowed rendering.
     - Fix: carve read-back-allowed rendering out in the intro, or move its requirements out of Rendering.
  6. source:153590: The new section is outside <div w-nodev>.
     - That div closes at source:153586, and everything else in Rendering is inside one. In the full build, the developer edition gets a stray "14.1 Read-back-allowed rendering" under "14 The XML syntax", with a dead #rendering link.
     - Meanwhile the author warning (source:151627) is inside w-nodev, so it's missing from the developer edition, which is the one authors read.
     - Fix: wrap the section in <div w-nodev>, and move the warning to the video element section or next to drawElementImage() in #11588.
  7. source:153349: The :visited wording is ambiguous on the one point that matters.
     - UAs do paint visited styles on screen; the privacy measures live in getComputedStyle() and the selector APIs. "Align with … style recalculation" can be read as "paint as usual", which is exactly the leak.
     - The earlier "act as if :visited does not match" was testable.
     - Fix: something like "the rendering must not depend on whether links have been visited, beyond what is otherwise observable to author code (e.g., getComputedStyle(), matches())". That still allows partitioned history.
  8. source:153614: "Subpixel text rendering and antialiasing must be disabled" literally bans all antialiasing.
     - The explainer only means subpixel (LCD) text antialiasing.
     - Fix: "text must not be rendered with subpixel antialiasing; grayscale antialiasing can be used instead".

  Suggestions

  1. source:153592–153597: The definition doesn't say what the concept is.
     - Define it positively: rendering whose output may be exposed to author code.
     - Say whose author code: the document the rendering is done for. Blocker 1 needs this.
     - Say that nested same-origin navigables are rendered this way too.
     - Make the general principle a normative catch-all, since every list is "including but not limited to".
     - Drop "The detailed requirements are in the relevant sections above", which the next paragraph repeats. Fix the agreement: "information … is omitted".
  2. source:151943, 153651: "Widgets must not use native appearance" doesn't say what they use instead.
     - Primitive appearance "can cause some widgets to disappear completely" (CSS UI 4), and base appearance isn't ready.
     - Native vs. devolved appearance also changes layout, so switching only at paint time is underspecified.
     - The table's "default appearance" isn't a defined term.
     - The explainer still calls form-control and scrollbar appearance non-sensitive. If that has changed, scrollbars and outline-style: auto focus rings (which use the accent color) presumably need the same treatment. Reconcile the two.
  3. source:153617: "Default colors, themes, and preferences must be used" has no limits. Read literally, it covers things already observable and baked into layout, like font-size preferences, prefers-color-scheme and forced-colors. Scope it to what isn't otherwise observable
     (e.g. system/accent colors in widgets, focus rings and selection) and give examples.
  4. source:153620, 153658:
     - Say whether author ::selection/::search-text styles still apply.
     - The dl says find-in-page needs nothing special, right after a find-in-page requirement; reword it as "highlights are painted, with default styles".
     - ::target-text isn't covered at all. The explainer calls it non-sensitive, but the text directive is deliberately hidden from script, so make the call explicit.
  5. source:151198: "Pending autofill suggestions" isn't defined and doesn't generate boxes. Tie it to autofill: values the UA shows that aren't yet exposed to author code (previews, or filled values not yet exposed through value) must not be painted.
  6. source:151620–151625: "Controls, subtitles, and captions" doesn't say of which element.
     - Use "expose a user interface to the user" for media elements. That also covers audio, as the table's "Media elements" row implies.
     - The note reads oddly after a rule with no condition; try "This applies regardless of whether the media data is CORS-same-origin."
  7. source:151627: The warning effectively tells authors not to provide captions. A better message: don't rely on this rendering for video that needs controls or captions; if you must, draw captions yourself from the track's active cues (mode "hidden").
  8. source:151582, 151616, 151732: The img/video/canvas conditions restate canvas's existing "is not origin-clean" check (source:73662) case by case. Referencing it keeps the two in sync and covers SVG image for free. The poster and input cases still need their own wording.
  9. Coverage gaps:
     - IME composition styling is on the explainer's sensitive list but isn't covered.
     - EME and isolated MediaStreams aren't CORS-cross-origin but mustn't be readable either. At least add a note that other specs are expected to hook into this concept; SVG already plans to.
  10. PR hygiene: "Editorial:" is defensible because nothing uses the concept yet. But the PR adds dormant normative UA requirements and an exported term SVG intends to use. Consider landing it with #11588, or at least write a commit message body that explains the label and
      links the explainer's "Read-back-allowed rendering" section.

  Nits

  1. source:151198: missing comma after "During read-back-allowed rendering"; every other instance has one.
  2. source:153600: "This includes … including but not limited to" → "This includes, but is not limited to:".
  3. source:153605–153608: the <li>s are indented 4 spaces; house style is 3.
  4. source:153659/153663: only one of the two <dd>s is closed with </dd>, and "Matching text from find-in-page" lacks a period.
  5. source:153351: "This specification does not specify" → "does not define".
  6. source:153353, 153621: the :link paragraph cuts the blank lines before <h4>The title attribute</h4> from 4 to 1. Keep at least 2 there and before <h4>Summary</h4>.
  7. source:153590, 153623: the h3 takes #read-back-allowed-rendering, so the exported definition ends up at #read-back-allowed-rendering-2 (I checked the build). <h4>Summary</h4> also claims the spec-wide #summary. Consider explicit ids.
  8. source:4214: the <url> definition anchor is #url-value; #urls is the section. The existing <length> entry does the same thing, so this is optional.
  9. source:153607, 153611: add SVG image to the examples. "Markers must be disabled" → "must not be painted", since "disabled" sounds like turning spellcheck off.
  10. source:153634: "Expected" is a defined term in this section; consider "Effect" as the column header.

@foolip

foolip commented Oct 2, 2026

Copy link
Copy Markdown
Member Author

It suggests that the :visited wording is wrong as the existing protections are at the getComputedStyle() level whereas we need them at the painting level here.

This is right, the mitigation isn't the same. The wording I used was:

This specification does not specify how to preserve user privacy, but user agents must align with what they do in other contexts, like style recalculation and selector matching.

By "align with" I mean that a script that uses getComputedStyle() or elm.matches(':visited') should observe the same state as a script that reads pixel colors after drawElementImage(). In other words, there shouldn't be a different used value observable via paint.

In the spirit of CSS spec's flexibility here, I think I'll just say "must preserve user privacy" and have a note pointing out that the mitigations already applied for CSS might not be enough.

@foolip

foolip commented Oct 2, 2026

Copy link
Copy Markdown
Member Author

It seems that frames (iframe, frame, embed, object) are not protected as their responses are always seen as CORS-same-origin. I think it's correct they need a special case.

This is surprising, do you mean that when foo.example embeds <iframe src="/?url=https%3A%2F%2Fbar.example">, the response for that initial navigation request is seen as CORS-same-origin?

@annevk

annevk commented Oct 2, 2026

Copy link
Copy Markdown
Member

Yeah, I think navigations always end up with a non-opaque response. With navigations it's also more tricky as you have the source (document with the link that navigates the target), the ancestor chain (if the target is in a frame), and the target. And you have redirects of course that should probably taint as well. Might well be the same problem/solution as that other PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

security/privacy There are security or privacy implications topic: canvas

Development

Successfully merging this pull request may close these issues.

5 participants