Draft
Conversation
9c465f2 to
3d8c973
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TurboModule Substitution for Sandboxed Native Modules
Summary
Adds a TurboModule substitution mechanism that allows host apps to transparently replace native modules inside sandboxes with scoped, security-hardened implementations. When a sandboxed JS bundle requests a module like
RNFSManager, the sandbox delegate intercepts the resolution and provides aSandboxedRNFSManagerinstead — one that jails all file paths to a per-origin directory.Motivation
Previously, sandboxed React Native instances shared the same native module instances as the host app. A sandboxed bundle using
react-native-fsorAsyncStoragecould read/write the host's data, defeating the purpose of isolation. This PR closes that gap by allowing the host to declare substitution mappings:How it works
New prop
turboModuleSubstitutions— aRecord<string, string>mapping requested module names to replacement module names. Substituted modules are implicitly allowed (no need to also list them inallowedTurboModules).RCTSandboxAwareModule/ISandboxAwareModuleprotocols — ObjC and C++ interfaces that substituted modules can adopt to receive sandbox context (origin, requested name, resolved name) at configuration time.Delegate-level interception via
getTurboModule:jsInvoker:— the sandbox delegate constructs substituted ObjC modules directly in the C++ TurboModule resolution path, bypassingRCTTurboModuleManager's internal instance creation chain (which uses weak delegate references that can lose track of configured instances). Each module is created once, configured with sandbox context, and wrapped inObjCInteropTurboModule.Unified sandbox root — all sandboxed file/storage modules share a single directory tree per origin:
<AppSupport>/<bundleId>/Sandboxes/<origin>/, with subdirectories forDocuments,Caches,tmp,Library, andAsyncStorage.Security hardening:
configureSandboxWithOrigin:— no default-origin backdoor.Documentsdirectory. Traversal attempts (e.g.,../../) are rejected.What's included
packages/react-native-sandbox: NewturboModuleSubstitutionsprop,RCTSandboxAwareModule/ISandboxAwareModuleprotocols, delegate substitution logic withSandboxNativeMethodCallInvokerfor proper method queue dispatch.apps/fs-experiment: Three reference sandboxed module implementations:SandboxedRNFSManager— wrapsreact-native-fswith per-origin file jailingSandboxedFileAccess— wrapsreact-native-file-accesswith per-origin file jailingSandboxedRNCAsyncStorage— wraps@react-native-async-storagewith per-origin storage isolationDemo
fs-experimentapp with substitution toggle off — sandbox uses real modules, can read/write host dataSandboxes/<origin>/directory../../Library/...) are rejectedAsyncStoragekeys are isolated between host and sandbox