# DSHA Security Model — what it can reach on your phone You installed a 370 MB APK that lets an AI run shell commands on your device, and you may have handed it ADB access on top of that. This document states **where the boundaries are**: what the agent can reach, what it cannot, what needs your explicit approval, and what each permission actually exposes once granted. If a line doesn't make sense to you, treat it as dangerous. You can run DSHA in its most restricted configuration — no ADB, no file permission, no LAN access — and dsh still works fine. > 中文版:[security-model.md](security-model.md) --- ## In one sentence **By default the agent can only touch DSHA's own private directory.** Every step beyond that is opt-in, granted explicitly by you, and individually revocable. --- ## What the agent reaches by default Fresh install, no permissions granted: | Scope | Reachable | Notes | |---|---|---| | The Ubuntu container | ✅ Fully | This is its workspace. `apt install`, compiling, running services — all here | | DSHA's private directory | ✅ Read/write | The rootfs lives here (`/data/data/com.dsh.client/`); Android's app sandbox keeps everyone else out | | Shared storage (`/sdcard`) | ✅ Read/write | `/sdcard` inside the container maps to shared storage. **This is on by default** — photos, downloads, documents are all readable | | Other apps' data | ❌ No | Android app sandbox isolation; `/data/data/` is unreachable | | System partition | ❌ Not writable | Without root, `/system` cannot be modified | | Dialer, SMS, contacts, location, camera, microphone | ❌ No | DSHA never requests these permissions — verify it yourself in system settings | > ⚠️ **`/sdcard` is reachable by default** and this is the easiest one to overlook. If you don't > want the agent seeing your gallery and downloads, right now your options are convention > (tell it so in `AGENTS.md`) or not keeping sensitive files on this phone. > Mount points live in `ContainerRuntime.BINDS` if you build it yourself. --- ## Capabilities that need your approval Each one is **off by default**, toggled in-app, revocable at any time. ### Wireless ADB (Workspace page) **What granting it means**: the agent gets `shell` user privileges (uid 2000). It can tap, swipe, take screenshots, install and uninstall apps, read system logs, list installed packages, and change some system settings. **This is the second most powerful thing this project can hand out**, behind only root. - The pairing code is used once; a keypair maintains the connection afterwards. DSHA never stores your pairing code - To revoke: turn off Wireless debugging in system settings, or revoke all debugging authorizations - What ADB cannot do: read other apps' private data, or obtain root ### Root shell (Config page, off by default) **What granting it means**: everything. With root there are no boundaries left to discuss. - Requires a rooted device (KernelSU / Magisk). DSHA neither provides nor requests root - The flag is `allow_root_shell`, default false - Don't enable it unless you know exactly why you are ### "All files access" (prompted on first launch) **What granting it means**: DSHA can read and write all of shared storage. It uses this to move conversation data into `Documents/dshdata`, which is what makes **data survive uninstall**. - If you decline: data stays in the private directory and **dies with uninstall** (the self-check tells you which state you're in) - It grants the agent no new reach — `/sdcard` was already available ### Overlay window (the streaming floating bar, off by default) **What granting it means**: DSHA can draw on top of other apps. - It's used only to display model output and the approval buttons for dangerous commands. It does not read or capture the screen - Content appears on your screen — **anyone nearby can read it**, which is why it ships disabled ### LAN access (off by default) **What enabling it means**: devices on the same Wi-Fi can reach the dsh Web UI on your phone. - Token authentication is **fail-closed**: a missing or wrong token is always rejected; there is no "empty token means allow" path - On first successful hit the token becomes a `SameSite=Strict` cookie and disappears from the URL — so it can't leak through outbound links - Don't enable it on public Wi-Fi. The token is strong, but you're exposing a port on the network --- ## What happens when the agent tries something dangerous `dsh-guard.sh` intercepts these and hands the decision to you: - Overwriting or deleting critical paths (`/`, `/root`, `/etc`, `/data`, …) - Recursive deletion (`rm -rf`) - Writing directly to block devices, modifying partitions - Uninstalling apps or factory-reset-class operations over ADB Once intercepted, approve through **any of three channels**: the notification, the in-app dialog, or the button on the floating bar. All three share one decision — first tap wins — and 60 seconds of silence counts as a refusal. > ⚠️ **The gate is not a sandbox.** It's a denylist over command text, and it isn't hard to > get around — it defends against an AI slipping, not against someone deliberately writing a > command that evades it. Android has no bubblewrap, so dsh runs with `danger-full-access`. > There is exactly one real isolation boundary: **the Android app sandbox**. --- ## Where your keys and data live | Item | Location | Protection | |---|---|---| | DeepSeek API key | App SharedPreferences | Android Keystore encryption (AES/CBC). **The key never leaves the Keystore**; other apps cannot read it | | API key inside backups | `.dsh/.dsha-apikey` in the archive | Same Keystore key. **Undecryptable after a device change** — by design, not a bug. You can turn off "include key in backup" in Config | | Conversations | `Documents/dshdata` (public) or private dir | ⚠️ In the public location, **any app with storage permission can read them**. That's the price of surviving uninstall | | Backup archives | `Download/DSHA/` | ⚠️ Public directory, and they contain **all** your conversations. Think before sharing one | | dsh's own credentials | `.dsh/.credentials.yaml` | Deliberately kept private, never migrated to the public area — but it **does go into backups** | | Bridge token (:3090) | `.dsh/.bridge_token` | Private directory, mode 600. **Excluded from backups** — it belongs to this machine | **We collect nothing.** No telemetry, no analytics, no crash reporting. The only outbound requests are: GitHub API when you tap check-for-updates, raw.githubusercontent.com when scripts hot-update, and whichever mirror you picked during installation. API calls go from dsh straight to DeepSeek and never pass through anything of ours. --- ## Verifying the APK you installed Sideloading an APK from GitHub makes provenance the thing most worth checking: ```bash # 1. Hash — proves the file wasn't altered sha256sum -c deepseekharness-arm64-vX.Y.Z.apk.sha256 # 2. Build provenance — proves it came from this repo's CI at that tag, # not from someone else's repackage gh attestation verify deepseekharness-arm64-vX.Y.Z.apk --repo qiannianhuanxiang/DSHA ``` The signing certificate fingerprint is verified on every release run, and a mismatch **aborts the release** — a wrongly signed package can't even be installed over an existing one (Android only allows same-signature upgrades), so shipping it would be worse than failing the build. --- ## Known weaknesses Not hidden: | Weakness | Status | |---|---| | `danger-full-access` | Android sepolicy blocks bubblewrap, so dsh has no sandbox. The agent has full control inside the container | | The gate is bypassable | A denylist over command text: guards against slips, not deliberate evasion | | Backups sit in a public directory | Every conversation, in plaintext, under `Download/DSHA/`, readable by any app with storage permission | | `.credentials.yaml` goes into backups | dsh's credential file rides along into the public directory; whether to add an exclusion toggle is undecided | | `/sdcard` reachable by default | The agent can read your gallery and downloads out of the box; there's no toggle yet | | Signing key needs rotation | Releases are signed with a debug keystore for historical reasons — replacing it would break upgrades for every existing user. Rotation via APK Signature Scheme v3 is scheduled separately | Found something else? Open an issue, or bring it to QQ group 975836806. Security reports go first.