diff --git a/front_end/models/ai_assistance/agents/StylingAgent.ts b/front_end/models/ai_assistance/agents/StylingAgent.ts index 84358416ec..8142c2d0d4 100644 --- a/front_end/models/ai_assistance/agents/StylingAgent.ts +++ b/front_end/models/ai_assistance/agents/StylingAgent.ts @@ -501,6 +501,26 @@ export class StylingAgent extends AiAgent { return this.context?.getItem() ?? null; } + /** + * AI-supplied backendNodeIds resolve via the renderer-process-global + * DOMNodeIds map, so a number chosen by the LLM can land on a node inside a + * cross-origin in-process subframe. Reject nodes whose ownerDocument origin + * differs from the conversation's selected-element origin (mirrors the + * guard added to ContextSelectionAgent for network requests). + */ + #isSameOriginAsContext(node: SDK.DOMModel.DOMNode): boolean { + const allowedOrigin = this.context?.getOrigin(); + const doc = node.ownerDocument; + if (!doc || !allowedOrigin) { + return false; + } + try { + return new URL(doc.documentURL).origin === allowedOrigin; + } catch { + return false; + } + } + async #getStyles(elements: number[], properties: string[]): Promise> { const widgets: ComputedStyleAiWidget[] = []; @@ -519,6 +539,10 @@ export class StylingAgent extends AiAgent { if (!resolved) { return {error: 'Error: Could not find the element with uid=' + uid}; } + if (!this.#isSameOriginAsContext(resolved)) { + // Do not disclose existence of cross-origin nodes to the LLM. + return {error: 'Error: Could not find the element with uid=' + uid}; + } const styles = await resolved.domModel().cssModel().getComputedStyle(resolved.id); if (!styles) { return {error: 'Error: Could not get computed styles.'}; @@ -579,6 +603,9 @@ export class StylingAgent extends AiAgent { if (!node) { return {error: `Error: Could not find the element with backendNodeId=${elementId}`}; } + if (!this.#isSameOriginAsContext(node)) { + return {error: `Error: Could not find the element with backendNodeId=${elementId}`}; + } Annotations.AnnotationRepository.instance().addElementsAnnotation(annotationMessage, node);