Skip to content

Commit 3d8c973

Browse files
committed
feat: native module substitution
1 parent dd45ab0 commit 3d8c973

30 files changed

+2893
-946
lines changed

README.md

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ Full examples:
147147
- [`apps/recursive`](./apps/recursive/README.md): An example application with few nested sandbox instances.
148148
- [`apps/p2p-chat`](./apps/p2p-counter/README.md): Direct sandbox-to-sandbox chat demo.
149149
- [`apps/p2p-counter`](./apps/p2p-counter/README.md): Direct sandbox-to-sandbox communication demo.
150+
- [`apps/fs-experiment`](./apps/fs-experiment/README.md): File system & storage isolation with TurboModule substitutions.
150151
151152
## 📚 API Reference
152153
@@ -168,9 +169,15 @@ We're actively working on expanding the capabilities of `react-native-sandbox`.
168169
- Resource usage limits and monitoring
169170
- Sandbox capability restrictions
170171
- Unresponsiveness detection
171-
- [ ] **Storage Isolation** - Secure data partitioning
172-
- Per-sandbox AsyncStorage isolation
173-
- Secure file system access controls
172+
- [x] **TurboModule Substitutions** - Replace native module implementations per sandbox
173+
- Configurable via `turboModuleSubstitutions` prop (JS/TS only)
174+
- Sandbox-aware modules receive origin context for per-instance scoping
175+
- Supports both TurboModules (new arch) and legacy bridge modules
176+
- [x] **Storage & File System Isolation** - Secure data partitioning
177+
- Per-sandbox AsyncStorage isolation via scoped storage directories
178+
- Sandboxed file system access (react-native-fs, react-native-file-access) with path jailing
179+
- All directory constants overridden to sandbox-scoped paths
180+
- Network/system operations blocked in sandboxed FS modules
174181
- [ ] **Developer Tools** - Enhanced debugging and development experience
175182
176183
Contributions and feedback on these roadmap items are welcome! Please check our [issues](https://github.com/callstackincubator/react-native-sandbox/issues) for detailed discussions on each feature.
@@ -185,17 +192,36 @@ A primary security concern when running multiple React Native instances is the p
185192
- **Data Leakage:** One sandbox could use a shared TurboModule to store data, which could then be read by another sandbox or the host. This breaks the isolation model.
186193
- **Unintended Side-Effects:** A sandbox could call a method on a shared module that changes its state, affecting the behavior of the host or other sandboxes in unpredictable ways.
187194
188-
To address this, `react-native-sandbox` allows you to provide a **whitelist of allowed TurboModules** for each sandbox instance via the `allowedTurboModules` prop. Only the modules specified in this list will be accessible from within the sandbox, significantly reducing the attack surface. It is critical to only whitelist modules that are stateless or are explicitly designed to be shared safely.
195+
To address this, `react-native-sandbox` provides two mechanisms:
189196
190-
**Default Whitelist:** By default, only `NativeMicrotasksCxx` is whitelisted. Modules like `NativePerformanceCxx`, `PlatformConstants`, `DevSettings`, `LogBox`, and other third-party modules are *not* whitelisted.
197+
- **TurboModule Allowlisting** — Use the `allowedTurboModules` prop to control which native modules the sandbox can access. Only modules in this list are resolved; all others return a stub that rejects with a clear error.
198+
199+
- **TurboModule Substitutions** — Use the `turboModuleSubstitutions` prop to transparently replace a module with a sandbox-aware alternative. For example, when sandbox JS requests `RNCAsyncStorage`, the host can resolve different implementation like `SandboxedAsyncStorage` instead — an implementation that scopes storage to the sandbox's origin. Substituted modules that conform to `RCTSandboxAwareModule` (ObjC) or `ISandboxAwareModule` (C++) receive the sandbox context (origin, requested name, resolved name) after instantiation.
200+
201+
```tsx
202+
<SandboxReactNativeView
203+
allowedTurboModules={['RNFSManager', 'FileAccess', 'RNCAsyncStorage']}
204+
turboModuleSubstitutions={{
205+
RNFSManager: 'SandboxedRNFSManager',
206+
FileAccess: 'SandboxedFileAccess',
207+
RNCAsyncStorage: 'SandboxedAsyncStorage',
208+
}}
209+
/>
210+
```
211+
212+
**Default Allowlist:** A baseline set of essential React Native modules is allowed by default (e.g., `EventDispatcher`, `AppState`, `Appearance`, `Networking`, `DeviceInfo`, `KeyboardObserver`, and others required for basic rendering and dev tooling). See the [full list in source](https://github.com/callstackincubator/react-native-sandbox/blob/main/packages/react-native-sandbox/src/index.tsx). Third-party modules and storage/FS modules are *not* included — they must be explicitly added via `allowedTurboModules` or provided through `turboModuleSubstitutions`.
191213
192214
### Performance
193215
194216
- **Resource Exhaustion (Denial of Service):** A sandboxed instance could intentionally or unintentionally consume excessive CPU or memory, potentially leading to a denial-of-service attack that slows down or crashes the entire application. The host should be prepared to monitor and terminate misbehaving instances.
195217
196218
### File System & Storage
197219
198-
- **Persistent Storage Conflicts:** Standard APIs like `AsyncStorage` may not be instance-aware, potentially allowing a sandbox to read or overwrite data stored by the host or other sandboxes. Any storage mechanism must be properly partitioned to ensure data isolation.
220+
- **Persistent Storage Conflicts:** Standard APIs like `AsyncStorage` are not instance-aware by default, potentially allowing a sandbox to read or overwrite data stored by the host or other sandboxes. Use `turboModuleSubstitutions` to replace these modules with sandbox-aware implementations that scope data per origin.
221+
- **File System Path Jailing:** Sandboxed file system modules (`SandboxedRNFSManager`, `SandboxedFileAccess`) override directory constants and validate all path arguments, ensuring file operations are confined to a per-origin sandbox directory. Paths outside the sandbox root are rejected with `EPERM`.
222+
- **Network Operations Blocked:** Sandboxed FS modules block download/upload/fetch operations to prevent data exfiltration.
223+
224+
See the [`apps/fs-experiment`](./apps/fs-experiment/) example for a working demonstration.
199225
200226
### Platform-Specific Considerations
201227

0 commit comments

Comments
 (0)