Replies: 2 comments 1 reply
-
|
Hiya! You have the threat model correct here and your analysis is correct, but it's missing a step that we take (which is perhaps entirely omitted from the public docs/repo? I need to check): In practise, we don't apply patches from the untrusted realm (S-B) to the trusted DOM directly. They pass through an intermediary layer - either (p)react bindings or a library we use (not yet moved into the remote-dom repository) called Tree Receiver, which acts as a double-buffer and security boundary (patches are applied to an in-memory plain object representation of the untrusted realm's tree, which then trigger internal patching of the DOM. The key here is that the intermediary layer (the (p)react bindings and/or Tree Receiver) don't forward properties by default - they act as both an allowlist and reprojection mechanism. In the remote-dom repository, the examples are intentionally simplified to omit this step, so they lack any security whatsoever. Here are some diagrams: 📈 SequencesequenceDiagram
participant AJS as Arbitrary JS
participant RDMT as Remote DOM Tree
participant TRec as Tree Receiver
participant PR as Preact Reprojection
participant RDT as Real DOM Tree
Note over AJS, RDT: Initial Setup & Synchronization
AJS->>RDMT: Create/modify elements
RDMT->>TRec: Send mutations
TRec->>TRec: Apply filtering & security rules
TRec->>PR: Forward validated tree deltas
PR->>RDT: Apply DOM patches
RDT-->>PR: Confirm changes
PR-->>TRec: Send events confirmation
Note over AJS, RDT: User Interaction Flow
RDT->>PR: User interaction (click, input, etc.)
PR->>TRec: Forward events
TRec->>TRec: Apply props allowlist filtering
TRec->>RDMT: Send filtered events + properties
RDMT->>AJS: Trigger event handlers
Note over AJS, RDT: State Update Cycle
AJS->>RDMT: Update state/properties
RDMT->>TRec: Property changes
TRec->>TRec: Validate against allowlist
TRec->>PR: Send validated properties
PR->>PR: Re-render components
PR->>RDT: Apply new DOM patches
Note over AJS, RDT: Error Handling
AJS->>RDMT: Invalid operation
RDMT->>TRec: Potentially unsafe mutation
TRec->>TRec: Security check fails
TRec--xAJS: Reject operation
Note over AJS, RDT: Cleanup
AJS->>RDMT: Remove elements
RDMT->>TRec: Deletion mutations
TRec->>PR: Tree deltas (removals)
PR->>RDT: Remove DOM elements
📈 Block%%{ init: { 'flowchart': { 'curve': 'step' } } }%%
flowchart TD
subgraph TR["🔒 Trusted Realm"]
RDT["Real DOM Tree"]
PR["Preact Reprojection"]
TRec["Tree Receiver"]
end
subgraph UR["🔓 Untrusted Realm"]
RDMT["Remote DOM Tree"]
AJS["Arbitrary JS"]
end
RDT ---|DOM patches| PR
PR ---|events| RDT
PR ---|tree deltas| TRec
TRec ---|events| PR
TRec ---|mutations| RDMT
RDMT ---|events + properties| TRec
RDMT ---|bidirectional sync| AJS
%% Add side annotations
%% PR -.-|props allowlist| TRec
%% TRec -.-|filtering and set rules| PR
classDef trusted fill:#e1f5fe,stroke:#01579b,stroke-width:2px
classDef untrusted fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef realm fill:#f5f5f5,stroke:#666,stroke-width:1px
class RDT,PR,TRec trusted
class RDMT,AJS untrusted
class TR,UR realm
|
Beta Was this translation helpful? Give feedback.
-
|
Thanks for the clarification, that makes sense! And that does seem to work properly and make sense from a security perspective. Given that, I guess the only feedback I have is that I didn't find this to be clear from the docs (READM.md). It seems to me the docs paint RemoteDOM as a sandboxing security tool, and almost only covers So what I fell for, and I can see others fall for too, is into thinking that Please refer me to any proof showing otherwise if I'm missing anything! |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Been learning about https://github.com/idosal/mcp-ui/ and therefore about remote-dom by proxy, to study both their security resilience.
Looking at remote-dom, I feel like I don't get it.
The general notion AFAIU, is to have some remote realm (say "S-B") in which you can dynamically generate sub-DOMs and then draw them to a protected realm (say "P-R") of your choice.
So, this should mean that remote-dom does not trust the provider of the code that generates the DOM, and therefore takes their untrusted code and runs it in a confined environment such as S-B.
To be more specific, remote-dom's job is to make sure provided untrusted code runs within S-B so that the DOM it generates is reflected to P-R without exposing P-R to any malicious code the provider might attempt to sneak in.
If I'm wrong here, I would love to be corrected on what I might be missing.
If I'm not, this does not sit well with the fact remote-dom does nothing AFAIU to prevent malicious code coming from the provider to end up in P-R.
Playing around with the
getting-startedexample, it seems to be very straight forward for the code running within S-B to ask P-R to embed XSSable elements such as<iframe src="javascript:alert(window.origin)">, which would execute in the origin of P-R.remote-dom takes just about any attribute of any element and introduces it the P-R's DOM.
This is so straight forward that I'm pretty sure I'm just missing the whole point, but I could really use the clarification. Am I wrong to think the provider of the untrusted code is an entity we don't trust? And if so, what entity do we not trust then? Or in other words, what's the threat model here?
Thanks!
Beta Was this translation helpful? Give feedback.
All reactions