- Introduction
- Problem Statement
- Proposed Solution
- Behavioral Changes
- Security Analysis
- API Impact
- Examples
- Compatibility
This explainer describes a proposed modification to the JavaScript Self-Profiling API that enables conditional exposure of ProfilerMarker values based on context isolation status. The change allows selective disclosure of markers based on their security sensitivity, improving developer experience while maintaining security boundaries.
The current JavaScript Self-Profiling API markers feature has some limitations:
- All-or-nothing approach: Markers are either completely available in Cross-Origin Isolated contexts or completely unavailable in non-isolated contexts
- Overly restrictive: Safe markers that don't pose security risks are unnecessarily gated behind Cross-Origin Isolation
- Limited flexibility: No mechanism for selective marker exposure based on security sensitivity
- Enable selective marker exposure based on security sensitivity
- Allow safe markers (
layout,style) in non-isolated contexts - Maintain explicit control over marker feature availability
- Preserve security boundaries while improving developer experience
- Graduated disclosure: Allow certain safe markers (
layout,style) in non-isolated contexts - Security-based filtering: Continue to restrict sensitive markers (
gc,paint,script) to Cross-Origin Isolated contexts - Transparent operation: No changes to the API surface; filtering happens internally
Layout and style state information is already exposed through other browser APIs (DOM APIs and CSSOM), making these markers safe for broader availability without introducing new security risks.
| Context Type | Feature Flag | Available Markers |
|---|---|---|
| Cross-Origin Isolated | Enabled | All markers (gc, layout, paint, script, style) |
| Cross-Origin Isolated | Disabled | None |
| Non-Isolated | Enabled | Limited (layout, style only) |
| Non-Isolated | Disabled | None |
layout: Layout state information is already available via DOM APIs such asgetBoundingClientRect(),getComputedStyle(), and layout-triggering operationsstyle: Style computation state is accessible through CSSOM APIs and style recalculation is observable via existing timing mechanisms
The following markers remain restricted to Cross-Origin Isolated contexts due to potential security implications:
gc: Garbage collection timing could leak memory patterns and cross-origin resource informationpaint: Paint timing might reveal information about cross-origin opaque resources that wouldn't pass Timing-Allow-Origin checksscript: Script execution state could expose sensitive timing information about cross-origin activities
This approach follows the principle of graduated disclosure, where:
- Information already available through other APIs can be safely exposed
- Sensitive timing information requires explicit Cross-Origin Isolation opt-in
- The overall feature remains controlled by user agent implementation
The API surface remains unchanged from a developer perspective. The conditional exposure happens transparently:
// Cross-origin isolated context
const profiler = new Profiler({sampleInterval: 10, maxBufferSize: 1000});
const trace = await profiler.stop();
// trace.samples may contain all marker types
// Non-isolated context
const profiler = new Profiler({sampleInterval: 10, maxBufferSize: 1000});
const trace = await profiler.stop();
// trace.samples may contain layout/style markers onlyNo changes to trace structure. The marker field in samples will be:
- Present with full marker data (Cross-Origin Isolated contexts)
- Present with filtered marker data (non-isolated contexts)
- Absent (feature disabled or no marker available)
// Set required headers for Cross-Origin Isolation:
// Cross-Origin-Embedder-Policy: require-corp
// Cross-Origin-Opener-Policy: same-origin
const profiler = new Profiler({sampleInterval: 5, maxBufferSize: 1000});
// Trigger various browser activities
document.body.style.color = 'red'; // Style recalculation
document.body.offsetHeight; // Layout
new Array(1000000); // Potential GC
const trace = await profiler.stop();
// Sample output may include all marker types:
console.log(trace.samples);
// [
// { timestamp: 1234.5, stackId: 2, marker: "gc" },
// { timestamp: 1235.0, stackId: 3, marker: "layout" },
// { timestamp: 1235.5, stackId: 1, marker: "style" },
// { timestamp: 1236.0, stackId: 4, marker: "paint" }
// ]// Regular context (no special headers required)
const profiler = new Profiler({sampleInterval: 5, maxBufferSize: 1000});
// Trigger various browser activities
document.body.style.color = 'blue'; // Style recalculation
document.body.offsetHeight; // Layout
new Array(1000000); // Potential GC (won't be exposed)
const trace = await profiler.stop();
// Sample output with filtered markers:
console.log(trace.samples);
// [
// { timestamp: 1234.5, stackId: 2 }, // gc marker filtered out
// { timestamp: 1235.0, stackId: 3, marker: "layout" }, // allowed
// { timestamp: 1235.5, stackId: 1, marker: "style" }, // allowed
// { timestamp: 1236.0, stackId: 4 } // paint marker filtered out
// ]const profiler = new Profiler({sampleInterval: 5, maxBufferSize: 1000});
const trace = await profiler.stop();
// No markers regardless of context isolation status:
console.log(trace.samples);
// [
// { timestamp: 1234.5, stackId: 2 },
// { timestamp: 1235.0, stackId: 3 },
// { timestamp: 1235.5, stackId: 1 }
// ]- No breaking changes: Existing code continues to work without modification
- Progressive enhancement: Non-isolated contexts gain access to layout/style markers
- Consistent behavior: Cross-Origin Isolated contexts maintain full marker access
- Extensible model: Framework ready for additional "safe" markers in the future
- Clear categorization: Established security model for evaluating new marker types
- Implementer guidance: Clear criteria for determining marker safety