# Security model

> The six failures every mini program ecosystem has had, and what Sollar does about each one.

Source: https://miniapp.sollar.com/platform/security-model/

---

## Start from what has already gone wrong

The reference study is *A Small Leak Will Sink Many Ships: Vulnerabilities in Mini-Programs*
(arXiv 2205.15202). It tested **more than 2,580 APIs across 9 mini-program ecosystems**, and its
result is the honest starting point for anything new in this category:

> **Every one of the nine ecosystems examined had at least one vulnerability.**

There is no secure implementation here to copy. There is a catalogue of how everyone got it wrong.

> **NOTE**
A correction for anyone citing the paper: the seven million figure is the size of the ecosystem
("as of June 2021, the number of mini programs in the whole network exceeded 7 million"), not the
sample. The authors examined 9 host apps. "Studied seven million mini programs" is a misreading that
circulates.

Section 3.2 of the paper names six categories. They are Sollar's review checklist and the agenda for
its internal penetration testing.

## 1. Cache file reuse

One mini app reads a file cached by another, because the host stores everything in a common
directory.

**Sollar:** a synthetic origin per mini app. Cache, `localStorage`, IndexedDB and cookies are
partitioned **by the browser engine**, not by a directory convention. It is the difference between a
rule the runtime remembers to apply and one it cannot violate.

## 2. PEL-API — permission encapsulated in a leaked API

A high-level API internally invokes a privileged capability and, once exposed, hands the privilege
over for free. The paper's example: obtaining the latitude and longitude of a map's centre "without
the user's authorisation", through a map context function.

**Sollar:** the bridge is minimal by construction, and every method is audited against one question
— *what capability does this grant indirectly?* A method that accepts a broad configuration object
is suspect by default, because that is where the extra capability hides. Where a web equivalent
exists it is used instead: `navigator.geolocation` already carries the engine's own prompt and has
no side path through another API.

## 3. Silent transmission of sensitive data

Data leaves for a remote server without the user noticing. The paper cites the clipboard: *"the
copied text could be sent to a remote server without user's awareness."*

**Sollar:** a network allowlist in the signed manifest, enforced in the **native** request
interceptor. Changing a destination requires a new version and a new gate. CSP is the second layer —
a mini app can rewrite its own CSP at runtime, but it cannot reach the native interceptor.

## 4. Permission management failure

A permission granted once lasts forever, leaks between contexts, or cannot be revoked.

**Sollar:** permissions are keyed on (user, mini app, scope) and revocable at any time. Host app
permissions do **not** flow to a mini app — required by Apple's Guideline 4.7.3 and enforced on both
platforms. And the mandatory `purpose` string turns the grant into a contestable claim at review
rather than a technical checkbox.

## 5. WebView bypassing permission control

An embedded webview component loads external content that escapes the runtime's permission model.

**Sollar: there is no `<web-view>` component.** External content opens in the system browser via
`sollar.ui.openExternal()`, with a visible address bar and lock icon.

This is a deliberate amputation. WeChat's `web-view` requires a business-domain allowlist covering
nested iframes and *still* is the vector for this entire category. The feature is not worth its
attack surface.

## 6. Permission divergence across environments

The permission model behaves differently in development, trial and production — and the hole exists
in only one of them.

**Sollar: the same permission-checking code in all three environments.** What changes between
environments is data and endpoints, never the authorisation path. The
[conformance suite](/reference/baseline/) runs the same permission tests against all three.

## Platform controls

### Android

| Control | Rule |
|---|---|
| Bridge | `WebViewCompat.addWebMessageListener` with `allowedOriginRules`. **Never `addJavascriptInterface`.** |
| Serving the package | `WebViewAssetLoader` + `shouldInterceptRequest` → `https://<appid>.miniapp.localhost/` |
| File access | `setAllowFileAccessFromFileURLs(false)`, `setAllowUniversalAccessFromFileURLs(false)`, `setAllowFileAccess(false)` |
| Safe Browsing | Enabled |
| Renderer | Separate process, with `WebViewRenderProcessClient` to detect a hang |
| Priority | `setRendererPriorityPolicy` — the mini app's renderer is sacrificed before the host |

`allowedOriginRules` matches scheme, host and port; **the path is ignored**.

### iOS

| Control | Rule |
|---|---|
| Bridge | `WKScriptMessageHandlerWithReply` in a dedicated `WKContentWorld` |
| Serving the package | `WKURLSchemeHandler` — see the secure-context risk in [Architecture](/platform/architecture/) |
| Storage | `WKWebsiteDataStore(forIdentifier:)` per mini app; `nonPersistent()` for ephemeral mode |
| Domains | `WKAppBoundDomains` where applicable — **capped at 10 domains**, which makes it unusable as a per-mini-app control |
| JIT | Present in the WebContent process — an advantage, not a risk |

> **CAUTION**
**`WKContentWorld` is not a security boundary.** It isolates JavaScript variables; it does not
isolate the DOM, and DOM mutation is visible across all worlds. Apple documents it as a solution to
script and namespace conflicts. It is right for preventing a mini app from overwriting the bridge
function, and wrong for hiding data from one.

## The CSP floor

The submission validator refuses a package that does not meet:

```
default-src 'self';
script-src 'self';            ← no 'unsafe-eval', no remote host
object-src 'none';
base-uri 'none';
frame-ancestors 'none';
connect-src 'self' <manifest hosts>
```

`script-src 'self'` with no remote host is also what keeps Sollar inside Google Play's interpreter
exemption: every executable byte arrives in the verified package. A mini app pulling a script from a
CDN is, technically, downloading executable code from outside it.

A third-party resource that genuinely must be remote requires Subresource Integrity with a pinned
hash.

## Denial of service

Per instance: a ceiling on concurrent connections, on storage, and on memory — with the mini app
destroyed rather than the host running out of memory — plus a rate limit per bridge method. A mini
app cannot degrade Sollar for the user.

## What review checks

Beyond the six categories:

1. The manifest validates, and every permission has a `purpose` plausible for the declared function.
2. The network allowlist is justifiable — an unexplained host is a question to the developer.
3. The CSP meets the floor.
4. An SBOM is present, with no high-severity CVE in a shipped dependency.
5. No remote scripts, no `eval`, no obfuscation that defeats review.
6. `actions[]` describe honestly what they do; `destructive` is set where it is destructive.
7. Reporting and blocking are reachable (Guideline 4.7.1); a content rating is declared (4.7.5).

## Automated checks

The submission pipeline: validate the manifest → scan the SBOM against vulnerability data → check
the CSP → static analysis for prohibited patterns (`eval`, `Function()`, remote scripts) → **dynamic
tests for all six categories**, with a deliberately malicious mini app kept as a permanent test case.

**TaintMini** (ICSE 2023), a static taint-analysis tool for mini programs, is a candidate for the
pipeline.

## What remains open

Stated plainly, because a security page that claims completeness is not a security page.

1. **Secure context on iOS.** If a custom scheme is not a secure context, `crypto.subtle` and service
   workers are unavailable inside mini apps and the storage design changes. Verified per release.
2. **Obfuscation versus review.** WeChat ships code obfuscation as a first-party plugin with a
   reversible sourcemap. Obfuscation that review cannot undo is incompatible with real review; the
   policy must be settled before the store opens.
3. **No independent audit yet.** Nothing described here has been tested by an outside team. Before
   opening the store to unvetted third parties, penetration testing with a written scope, an isolated
   environment and synthetic data is a precondition, not a nice-to-have.
