A Super App with mini programs is essentially an operating system within an operating system. The host application loads and executes code from third-party developers. If that code can read data from other mini programs or the main application, the entire security architecture collapses. We offer a turnkey isolated sandbox implementation, ensuring that each mini program operates in a tightly constrained environment. This reduces the risk of financial losses from data breaches, which can reach millions of dollars. Contact us — we'll evaluate your project within 1 day.
Why Isolating Mini Programs Is a Technical Challenge
In WeChat Mini Programs, Grab SuperApp, Gojek — each has its own isolation implementation. The main problem: native code on iOS and Android cannot "isolate" arbitrary JS or Dart code without special mechanisms. WebView isolates the DOM but not memory, and it does not restrict network requests.
A typical antipattern: load the mini program's JS into WKWebView / WebView, expose addJavascriptInterface for the required APIs — and consider that a sandbox. This is not a sandbox. Any XSS in the mini program gains access to all objects registered via addJavascriptInterface, including bridges to native code. Our experience shows such leads to leaks in 9 out of 10 audits. The cost of implementing our sandbox pays for itself by preventing such incidents.
Levels of Isolation We Implement
Execution Isolation
On Android, JS mini programs are best executed in a separate process using the android:process attribute in the manifest. Each mini program gets its own process with its own heap. A crash in one program does not bring down the host. For Dart/Flutter, we use Isolate with a limited ReceivePort API.
For WebView-based mini programs: WebView with setJavaScriptEnabled(true) in a separate process plus a WebViewClient with a host allowlist:
class SandboxedWebViewClient( private val allowedHosts: Set<String> ) : WebViewClient() { override fun shouldInterceptRequest( view: WebView, request: WebResourceRequest ): WebResourceResponse? { val host = request.url.host ?: return blockRequest() if (host !in allowedHosts) { auditLogger.logBlockedRequest(miniProgramId, request.url) return blockRequest() } return null // proceed } private fun blockRequest() = WebResourceResponse( "text/plain", "UTF-8", ByteArrayInputStream("blocked".toByteArray()) ) } JavaScript Bridge with Capability Model
Instead of open addJavascriptInterface, we use a declarative bridge with an explicit permission list. The mini program requests an API; the host checks whether it is allowed in that program's manifest:
class CapabilityBridge( private val miniAppManifest: MiniAppManifest, private val userId: String ) { @JavascriptInterface fun callNative(apiName: String, params: String, callbackId: String) { val capability = Capability.fromString(apiName) ?: run { sendError(callbackId, "UNKNOWN_API") return } if (!miniAppManifest.hasPermission(capability)) { auditLogger.logUnauthorizedApiCall(miniAppId, apiName) sendError(callbackId, "PERMISSION_DENIED") return } nativeApiRouter.dispatch(capability, params, callbackId) } } The mini program manifest describes the requested APIs — analogous to uses-permission in Android, but for the mini app ecosystem.
Storage Isolation
Each mini program gets an isolated namespace in SharedPreferences and a separate directory in filesDir:
/app/mini_programs/ /{mini_app_id}/ /storage/ ← SharedPreferences namespace /files/ ← file storage /cache/ ← cleared when space is low Access to another mini program's storage requires an explicit Intent with user confirmation. Cross-program data access outside this scheme is forbidden at the ContentProvider level with callingUid verification.
Network Isolation
On Android 8 and above, we use ConnectivityManager with NetworkCapabilities to bind a specific connection to a VPN profile for the mini program. A less aggressive option is a proxy with an allowlist at the host level and HTTPS pinning to the mini program's servers through a custom X509TrustManager. We also implement request monitoring with a limit of 1000 requests per minute per mini program; when exceeded, we block and notify.
On iOS, WKContentWorld (iOS 14+) allows executing each mini program's JS in an isolated world with a separate global object. According to Apple's documentation, this ensures complete execution context isolation.
let miniAppWorld = WKContentWorld.world(withName: "mini_app_\(miniAppId)") webView.evaluateJavaScript(miniAppCode, in: nil, in: miniAppWorld) { result, error in // code executes in isolated context } Different WKContentWorld instances do not see each other's variables, even in the same WKWebView.
How Is Trusted Launch Ensured?
Before launch, we verify the bundle signature. Each bundle is signed by the developer and verified against the public key registered on the platform:
fun verifyMiniAppBundle(bundle: ByteArray, signature: ByteArray, publisherKey: PublicKey): Boolean { val sig = Signature.getInstance("SHA256withECDSA") sig.initVerify(publisherKey) sig.update(bundle) return sig.verify(signature) } Launching an unsigned or modified bundle is refused with incident logging.
Runtime Monitoring
A sandbox is not a static construct. We need runtime monitoring: CPU time per mini program, allocated memory, network request count. A mini program making 500 requests per second is either broken or mining.
On Android, we use Debug.MemoryInfo + Debug.ThreadCpuTimeNanos() for each mini program process. Thresholds are configured in the platform config (e.g., 200 ms CPU per second, 50 MB memory, 100 network requests per minute).
| Isolation Level | Technology | Effect |
|---|---|---|
| Execution | Separate process (android:process) / Isolate | Crash does not bring down host |
| JavaScript Bridge | CapabilityBridge with manifest | API access control |
| Storage | Namespace + ContentProvider | Data isolation |
| Network | WebViewClient allowlist / WKContentWorld | Request restriction |
What's Included in the Work
- Architectural documentation of the isolation scheme (processes, bridges, storage)
- Implementation of core components: SandboxedWebViewClient, CapabilityBridge, StorageManager
- Integration of bundle attestation mechanism with ECDSA signatures
- Setup of runtime monitoring with CPU/memory/network thresholds
- Security audit and penetration testing of the sandbox before launch
- Support and team training for 2 weeks post-implementation
Timeline and Cost
A basic sandbox with WebView process isolation and capability bridge takes 2–3 weeks. A full platform with network isolation, bundle attestation, runtime monitoring, and a permissions management console takes 2–3 months. Cost is calculated individually after scoping. Get a consultation — contact us for a free audit. Order the sandbox implementation for your Super App — we'll provide a detailed assessment.







