From b199482a4641a153dec7fb079ba2656399e97350 Mon Sep 17 00:00:00 2001 From: "Emmanuel Romero Ruiz (from Dev Box)" Date: Wed, 18 Jun 2025 14:59:13 -0700 Subject: [PATCH 1/6] feat: Add conditional marker exposure based on cross-origin isolation --- README.md | 4 ++- index.html | 10 ++++-- markers.md | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 99 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index fce843f..5b99903 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,9 @@ window.addEventListener('load', collectAndSendTrace); ## Markers Extensions -See [markers](markers.md) for detailed description of the proposal. +The API supports optional markers that identify browser activity during sampling. Markers are conditionally exposed based on security context - all markers are available in cross-origin isolated contexts, while only safe markers (`style`, `layout`) are available in regular contexts. + +See [markers](markers.md) for detailed description of the proposal and [Conditional Markers Exposure](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/ConditionalMarkersExposure/explainer.md) for technical implementation details. ## Privacy and Security diff --git a/index.html b/index.html index 8c82897..8ea30bd 100644 --- a/index.html +++ b/index.html @@ -303,17 +303,23 @@

The ProfilerTrace Dictionary

Inspired by the V8 trace event format and Gecko profile format, this representation is designed to be easily and efficiently serializable. -

-
+

The ProfilerSample Dictionary

+        enum ProfilerMarker { "script", "gc", "style", "layout", "paint", "other" };
+
         dictionary ProfilerSample {
           required DOMHighResTimeStamp timestamp;
           unsigned long long stackId;
+          ProfilerMarker? marker;
         };
         

timestamp MUST return the value it was initialized to.

stackId MUST return the value it was initialized to.

+

marker MUST return the value it was initialized to, if present. The availability of markers depends on the context's cross-origin isolation status.

+

+ In cross-origin isolated contexts, all marker types are available. In non-isolated contexts, only style and layout markers are exposed for security reasons. +

The ProfilerStack Dictionary

diff --git a/markers.md b/markers.md index 6cf2751..1216c02 100644 --- a/markers.md +++ b/markers.md @@ -73,10 +73,25 @@ enum ProfilerMarker { "script", "gc", "style", "layout", "paint", "other" }; dictionary ProfilerSample { required DOMHighResTimeStamp timestamp; unsigned long long stackId; - [CrossOriginIsolated] ProfilerMarker? marker; + ProfilerMarker? marker; }; ``` +## Conditional Marker Exposure + +Markers are conditionally exposed based on the security context to balance developer utility with privacy protection: + +**Cross-Origin Isolated contexts** (with `Cross-Origin-Embedder-Policy: require-corp` and `Cross-Origin-Opener-Policy: same-origin` headers): +- All marker types are available: `script`, `gc`, `style`, `layout`, `paint`, `other` + +**Non-isolated contexts** (regular browsing contexts): +- Only safe markers are available: `style`, `layout` +- Sensitive markers (`gc`, `paint`, `script`) are filtered out for security reasons + +This graduated approach allows developers to access layout and style timing information (already available through DOM APIs and CSSOM) in regular contexts, while requiring explicit Cross-Origin Isolation for more sensitive timing data. + +For detailed technical specification, see the [Conditional Markers Exposure explainer](https://github.com/MSEdgeExplainers/ConditionalMarkersExposure). + ## Key scenarios ### Browser activity @@ -240,14 +255,84 @@ Trace with markers: "marker": "script" }, { - "timestamp" :150 + "timestamp" :150 } +``` + +### Conditional marker availability example + +**In a Cross-Origin Isolated context** (all markers available): + +```json +{ + "samples": [ + { + "timestamp": 100, + "stackId": 2, + "marker": "script" + }, + { + "timestamp": 110, + "marker": "gc" + }, + { + "timestamp": 120, + "marker": "style" + }, + { + "timestamp": 130, + "marker": "layout" + }, + { + "timestamp": 140, + "marker": "paint" } + ] +} ``` + +**In a regular (non-isolated) context** (only safe markers available): + +```json +{ + "samples": [ + { + "timestamp": 100, + "stackId": 2 + }, + { + "timestamp": 110 + }, + { + "timestamp": 120, + "marker": "style" + }, + { + "timestamp": 130, + "marker": "layout" + }, + { + "timestamp": 140 + } + ] +} +``` + +Note how `gc`, `script`, and `paint` markers are filtered out in non-isolated contexts for security reasons. + ## Privacy and Security Careful consideration must be taken to avoid leaking top level UA work performed on a cross-origin document. UAs must only expose a marker if the responsible document for the work is same-origin with the profiler. -There is a risk to introduce a new source of side channel information through this API. Specifically, the timings of cross-origin opaque resources owned by the document that do not pass a Timing-Allow-Origin check or the timings of cross-origin documents hosted by the same process. To mitigate this risk, a Sample's marker attribute may only be accessible when the current Realm's settings objects's cross-origin isolated capability boolean is set to true. +To balance developer utility with privacy protection, markers are conditionally exposed based on security context: + +**Safe markers** (`style`, `layout`): Available in all contexts as this information is already accessible through existing web APIs (DOM APIs, CSSOM) and does not pose additional security risks. + +**Sensitive markers** (`gc`, `paint`, `script`): Only available in Cross-Origin Isolated contexts to prevent potential timing attacks and cross-origin information leakage. These markers could potentially be used for side-channel attacks or to infer information about cross-origin content. + +There is a risk to introduce a new source of side channel information through this API. The conditional exposure model mitigates this risk by: +- Requiring Cross-Origin Isolation for sensitive timing information +- Only exposing safe markers that reveal information already available through other APIs in regular contexts +- Ensuring all markers are only exposed when the responsible document is same-origin with the profiler Additional checks may also be required by user agents to implement this feature. ## Considered alternatives From 254e5891dc2f9bb283b1cb679d2d2cbe75b1edbe Mon Sep 17 00:00:00 2001 From: Monica Chintala Date: Mon, 20 Jul 2026 14:54:27 -0700 Subject: [PATCH 2/6] Fix bugs and add normative filter algorithm for conditional markers --- index.html | 24 +++++++++++++++++++++--- markers.md | 5 +++-- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index 8ea30bd..e83f119 100644 --- a/index.html +++ b/index.html @@ -156,9 +156,26 @@

Processing Model

  • Set the ProfilerSample.timestamp property of sample to the current high resolution time relative to the profiling session's time origin.
  • Let stack be the execution context stack associated with the profiling session's agent.
  • Set the ProfilerSample.stackId property of sample to the result of the get a stack ID algorithm on stack.
  • +
  • + Let candidateMarker be the ProfilerMarker value that best describes the top-level work the user agent was performing when the sample was taken, or null if none applies. +
  • +
  • + If candidateMarker is not null, set the ProfilerSample.marker property of sample to the result of running filter a marker given candidateMarker and the profiling session's associated environment settings object. +
  • Add sample to the ProfilerTrace.samples associated with the session's ProfilerTrace.
  • + To filter a marker given a ProfilerMarker marker and an environment settings object settings, perform the following steps: +

    +
      +
    1. If settings' cross-origin isolated capability is true, return marker.
    2. +
    3. If marker is "style" or "layout", return marker.
    4. +
    5. Return null.
    6. +
    +

    + The filter a marker algorithm produces the observable behavior that in non-cross-origin-isolated contexts, only the style and layout markers appear on ProfilerSample; the script, gc, paint, and other markers are suppressed. User agents MAY offer opt-in mechanisms (for example, an origin-trial token or a document policy) that widen the set returned by filter a marker for a specific environment settings object; such opt-ins MUST NOT expose markers cross-origin. +

    +

    To get a stack ID given an execution context stack bound to stack, perform the following steps:

    1. If stack is empty, return undefined.
    2. @@ -303,7 +320,8 @@

      The ProfilerTrace Dictionary

      Inspired by the V8 trace event format and Gecko profile format, this representation is designed to be easily and efficiently serializable. -

      +

      +

      The ProfilerSample Dictionary

               enum ProfilerMarker { "script", "gc", "style", "layout", "paint", "other" };
      @@ -316,9 +334,9 @@ 

      The ProfilerSample Dictionary

      timestamp MUST return the value it was initialized to.

      stackId MUST return the value it was initialized to.

      -

      marker MUST return the value it was initialized to, if present. The availability of markers depends on the context's cross-origin isolation status.

      +

      marker MUST return the value it was initialized to by the take a sample algorithm, or be absent if no marker was set. The set of marker values that may be exposed is governed by the filter a marker algorithm.

      - In cross-origin isolated contexts, all marker types are available. In non-isolated contexts, only style and layout markers are exposed for security reasons. + In cross-origin isolated contexts the filter a marker algorithm returns every value in the ProfilerMarker enumeration. In non-isolated contexts it returns only style and layout, so any other marker is suppressed (the marker attribute is absent on the corresponding ProfilerSample).

      diff --git a/markers.md b/markers.md index 1216c02..1c4c020 100644 --- a/markers.md +++ b/markers.md @@ -90,7 +90,7 @@ Markers are conditionally exposed based on the security context to balance devel This graduated approach allows developers to access layout and style timing information (already available through DOM APIs and CSSOM) in regular contexts, while requiring explicit Cross-Origin Isolation for more sensitive timing data. -For detailed technical specification, see the [Conditional Markers Exposure explainer](https://github.com/MSEdgeExplainers/ConditionalMarkersExposure). +For detailed technical specification, see the [Conditional Markers Exposure explainer](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/ConditionalMarkersExposure/explainer.md). ## Key scenarios @@ -255,7 +255,8 @@ Trace with markers: "marker": "script" }, { - "timestamp" :150 } + "timestamp": 150 + } ``` ### Conditional marker availability example From 532b1252fc29e62f6298e8278ceb497ca02f13b7 Mon Sep 17 00:00:00 2001 From: Monica Chintala Date: Wed, 5 Aug 2026 12:22:23 -0700 Subject: [PATCH 3/6] Address review: extract capture-a-marker algorithm and document conditional marker exposure --- index.html | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/index.html b/index.html index e83f119..172454b 100644 --- a/index.html +++ b/index.html @@ -156,15 +156,22 @@

      Processing Model

    3. Set the ProfilerSample.timestamp property of sample to the current high resolution time relative to the profiling session's time origin.
    4. Let stack be the execution context stack associated with the profiling session's agent.
    5. Set the ProfilerSample.stackId property of sample to the result of the get a stack ID algorithm on stack.
    6. -
    7. - Let candidateMarker be the ProfilerMarker value that best describes the top-level work the user agent was performing when the sample was taken, or null if none applies. -
    8. -
    9. - If candidateMarker is not null, set the ProfilerSample.marker property of sample to the result of running filter a marker given candidateMarker and the profiling session's associated environment settings object. -
    10. +
    11. Let marker be the result of running the capture a marker algorithm given the profiling session's associated environment settings object.
    12. +
    13. If marker is not null, set the ProfilerSample.marker property of sample to marker.
    14. Add sample to the ProfilerTrace.samples associated with the session's ProfilerTrace.

    + To capture a marker given an environment settings object settings, perform the following steps: +

    +
      +
    1. Let candidateMarker be the ProfilerMarker value that best describes the top-level work the user agent was performing when the sample was taken, or null if none applies.
    2. +
    3. If candidateMarker is null, return null.
    4. +
    5. Return the result of running filter a marker given candidateMarker and settings.
    6. +
    +

    + The mapping from a user agent's internal activity to a ProfilerMarker value is intentionally implementation-defined, as engine architectures differ. As non-normative guidance, a user agent is expected to report script while executing author script, gc during garbage collection, style while recalculating computed style, layout while computing box geometry (i.e. reflow), and paint while rasterizing or compositing document content. The other marker is used for user-agent work that does not fall into one of the preceding categories. When no category applies (for example, when the agent is idle), the capture a marker algorithm returns null and the marker attribute is left absent on the resulting ProfilerSample. +

    +

    To filter a marker given a ProfilerMarker marker and an environment settings object settings, perform the following steps:

      @@ -173,7 +180,7 @@

      Processing Model

    1. Return null.

    - The filter a marker algorithm produces the observable behavior that in non-cross-origin-isolated contexts, only the style and layout markers appear on ProfilerSample; the script, gc, paint, and other markers are suppressed. User agents MAY offer opt-in mechanisms (for example, an origin-trial token or a document policy) that widen the set returned by filter a marker for a specific environment settings object; such opt-ins MUST NOT expose markers cross-origin. + The filter a marker algorithm produces the observable behavior that in non-cross-origin-isolated contexts, only the style and layout markers appear on ProfilerSample; the script, gc, paint, and other markers are suppressed. See Conditional marker exposure for the rationale behind this behavior. User agents MAY offer opt-in mechanisms (for example, an origin-trial token or a document policy) that widen the set returned by filter a marker for a specific environment settings object; such opt-ins MUST NOT expose markers cross-origin.

    To get a stack ID given an execution context stack bound to stack, perform the following steps: @@ -447,7 +454,7 @@

    Cross-origin script contents

    As a result, the API does not expose any new insight into the contents or execution characteristics of cross-origin script, beyond what is already possible through manual instrumentation. UAs are encouraged to verify this holds if they choose to support extremely low sample interval values (e.g. less than one millisecond).

    -
    +

    Cross-origin execution

    Cross-origin execution contexts should not be observable by the API through the realm check in the take a sample algorithm. Cross-origin iframes and other execution contexts that share an agent with a profiler will therefore not have their execution observable through this API. @@ -461,6 +468,15 @@

    Timing attacks

    See [[?HR-Time]]'s discussion on clock resolution.

    +
    +

    Conditional marker exposure

    +

    + The filter a marker algorithm exposes the script, gc, paint, and other markers only when the profiler's environment settings object has its cross-origin isolated capability set to true. These markers can reflect engine work that is not necessarily attributable to a single origin — for example, garbage collection and script compilation are typically process-wide, and painting may composite content from cross-origin frames. Exposing their timing without isolation could therefore contribute to a cross-origin side channel of the kind that cross-origin isolation is designed to mitigate. Gating them behind cross-origin isolation ensures the surrounding context is already separated from cross-origin data before this timing becomes observable. +

    +

    + The style and layout markers are exposed without cross-origin isolation because the timing they reveal is already same-origin observable. A document can already synchronously trigger, and time, its own style and layout work using existing APIs that force a reflow, such as getBoundingClientRect() or getComputedStyle(). These markers therefore expose no timing information that a same-origin document could not already obtain, and — like every sample — they remain subject to the restrictions in Cross-origin execution, so they never attribute work to a cross-origin execution context. +

    +
    From 372319766ed0280b1f552b4428c49a0901da9ef2 Mon Sep 17 00:00:00 2001 From: Monica Chintala Date: Wed, 5 Aug 2026 13:09:04 -0700 Subject: [PATCH 4/6] Fix ReSpec xref: qualify marker autolink in capture-a-marker note --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 172454b..f29a140 100644 --- a/index.html +++ b/index.html @@ -169,7 +169,7 @@

    Processing Model

  • Return the result of running filter a marker given candidateMarker and settings.
  • - The mapping from a user agent's internal activity to a ProfilerMarker value is intentionally implementation-defined, as engine architectures differ. As non-normative guidance, a user agent is expected to report script while executing author script, gc during garbage collection, style while recalculating computed style, layout while computing box geometry (i.e. reflow), and paint while rasterizing or compositing document content. The other marker is used for user-agent work that does not fall into one of the preceding categories. When no category applies (for example, when the agent is idle), the capture a marker algorithm returns null and the marker attribute is left absent on the resulting ProfilerSample. + The mapping from a user agent's internal activity to a ProfilerMarker value is intentionally implementation-defined, as engine architectures differ. As non-normative guidance, a user agent is expected to report script while executing author script, gc during garbage collection, style while recalculating computed style, layout while computing box geometry (i.e. reflow), and paint while rasterizing or compositing document content. The other marker is used for user-agent work that does not fall into one of the preceding categories. When no category applies (for example, when the agent is idle), the capture a marker algorithm returns null and the ProfilerSample.marker attribute is left absent on the resulting ProfilerSample.

    To filter a marker given a ProfilerMarker marker and an environment settings object settings, perform the following steps: From e6a39fb44b0f1c0418d163676901f2bb6fc203fc Mon Sep 17 00:00:00 2001 From: Monica Chintala Date: Wed, 5 Aug 2026 13:17:17 -0700 Subject: [PATCH 5/6] Tighten conditional-marker rationale after review --- index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index f29a140..1a2f09d 100644 --- a/index.html +++ b/index.html @@ -164,7 +164,7 @@

    Processing Model

    To capture a marker given an environment settings object settings, perform the following steps:

      -
    1. Let candidateMarker be the ProfilerMarker value that best describes the top-level work the user agent was performing when the sample was taken, or null if none applies.
    2. +
    3. Let candidateMarker be the ProfilerMarker value that best describes the top-level work the user agent was performing on the profiling session's agent when the sample was taken, or null if none applies.
    4. If candidateMarker is null, return null.
    5. Return the result of running filter a marker given candidateMarker and settings.
    @@ -454,7 +454,7 @@

    Cross-origin script contents

    As a result, the API does not expose any new insight into the contents or execution characteristics of cross-origin script, beyond what is already possible through manual instrumentation. UAs are encouraged to verify this holds if they choose to support extremely low sample interval values (e.g. less than one millisecond).

    -
    +

    Cross-origin execution

    Cross-origin execution contexts should not be observable by the API through the realm check in the take a sample algorithm. Cross-origin iframes and other execution contexts that share an agent with a profiler will therefore not have their execution observable through this API. @@ -471,10 +471,10 @@

    Timing attacks

    Conditional marker exposure

    - The filter a marker algorithm exposes the script, gc, paint, and other markers only when the profiler's environment settings object has its cross-origin isolated capability set to true. These markers can reflect engine work that is not necessarily attributable to a single origin — for example, garbage collection and script compilation are typically process-wide, and painting may composite content from cross-origin frames. Exposing their timing without isolation could therefore contribute to a cross-origin side channel of the kind that cross-origin isolation is designed to mitigate. Gating them behind cross-origin isolation ensures the surrounding context is already separated from cross-origin data before this timing becomes observable. + By default, the filter a marker algorithm exposes the script, gc, paint, and other markers only when the profiler's environment settings object has its cross-origin isolated capability set to true. These markers can reflect engine work that cannot reliably be attributed to a single origin — for example, garbage collection and other cross-context engine activity can correlate work across contexts, and painting may composite content from other frames. Exposing the timing of such work without isolation could therefore contribute to a cross-origin side channel of the kind that cross-origin isolation is designed to mitigate, so it is gated behind it. A user agent MAY widen the exposed set through an explicit opt-in (as described in the filter a marker note above), but such opt-ins MUST NOT expose markers cross-origin.

    - The style and layout markers are exposed without cross-origin isolation because the timing they reveal is already same-origin observable. A document can already synchronously trigger, and time, its own style and layout work using existing APIs that force a reflow, such as getBoundingClientRect() or getComputedStyle(). These markers therefore expose no timing information that a same-origin document could not already obtain, and — like every sample — they remain subject to the restrictions in Cross-origin execution, so they never attribute work to a cross-origin execution context. + The style and layout markers are exposed without cross-origin isolation because the timing they reveal is already same-origin observable. A document can already synchronously flush, and time, its own style and layout using existing APIs — for example, getBoundingClientRect() forces layout, and getComputedStyle() flushes style (and layout where required). To preserve this property, a user agent attributes the style and layout markers only to work performed for a document that is same origin with the profiler; work that cannot be attributed to a same-origin document is not reported through these markers. As a result, they expose no timing information that a same-origin document could not already obtain for itself.

    From 0b7a4cbbbc2dad9a4e2f8eaff039b5d5f2575893 Mon Sep 17 00:00:00 2001 From: Monica Chintala Date: Wed, 5 Aug 2026 14:06:22 -0700 Subject: [PATCH 6/6] Make same-origin marker attribution normative in capture a marker --- index.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 1a2f09d..e5a31f4 100644 --- a/index.html +++ b/index.html @@ -166,11 +166,15 @@

    Processing Model

    1. Let candidateMarker be the ProfilerMarker value that best describes the top-level work the user agent was performing on the profiling session's agent when the sample was taken, or null if none applies.
    2. If candidateMarker is null, return null.
    3. +
    4. If the work described by candidateMarker was performed for a specific document that is not [= same origin =] with the origin of settings, return null.
    5. Return the result of running filter a marker given candidateMarker and settings.

    The mapping from a user agent's internal activity to a ProfilerMarker value is intentionally implementation-defined, as engine architectures differ. As non-normative guidance, a user agent is expected to report script while executing author script, gc during garbage collection, style while recalculating computed style, layout while computing box geometry (i.e. reflow), and paint while rasterizing or compositing document content. The other marker is used for user-agent work that does not fall into one of the preceding categories. When no category applies (for example, when the agent is idle), the capture a marker algorithm returns null and the ProfilerSample.marker attribute is left absent on the resulting ProfilerSample.

    +

    + The same-origin check ensures a marker only describes work performed for a document that is [= same origin =] with the profiler, consistent with the requirement that the API not reveal cross-origin activity. Work that is not attributable to a single document — for example, engine-wide garbage collection — is not constrained by that check; such work is instead exposed only when the profiler is cross-origin isolated, as enforced by filter a marker. +

    To filter a marker given a ProfilerMarker marker and an environment settings object settings, perform the following steps:

    @@ -474,7 +478,7 @@

    Conditional marker exposure

    By default, the filter a marker algorithm exposes the script, gc, paint, and other markers only when the profiler's environment settings object has its cross-origin isolated capability set to true. These markers can reflect engine work that cannot reliably be attributed to a single origin — for example, garbage collection and other cross-context engine activity can correlate work across contexts, and painting may composite content from other frames. Exposing the timing of such work without isolation could therefore contribute to a cross-origin side channel of the kind that cross-origin isolation is designed to mitigate, so it is gated behind it. A user agent MAY widen the exposed set through an explicit opt-in (as described in the filter a marker note above), but such opt-ins MUST NOT expose markers cross-origin.

    - The style and layout markers are exposed without cross-origin isolation because the timing they reveal is already same-origin observable. A document can already synchronously flush, and time, its own style and layout using existing APIs — for example, getBoundingClientRect() forces layout, and getComputedStyle() flushes style (and layout where required). To preserve this property, a user agent attributes the style and layout markers only to work performed for a document that is same origin with the profiler; work that cannot be attributed to a same-origin document is not reported through these markers. As a result, they expose no timing information that a same-origin document could not already obtain for itself. + The style and layout markers are exposed without cross-origin isolation because the timing they reveal is already same-origin observable. A document can already synchronously flush, and time, its own style and layout using existing APIs — for example, getBoundingClientRect() forces layout, and getComputedStyle() flushes style (and layout where required). To preserve this property, the capture a marker algorithm reports a marker only for work performed for a document that is same origin with the profiler; work that cannot be attributed to a same-origin document is not reported through these markers. As a result, they expose no timing information that a same-origin document could not already obtain for itself.