Automates the OWASP MASWE-0024 check: sensitive data accessible after session termination.

Data-residue testing for mobile apps

Prove your app forgets — no token survives logout.

Capture your app before and after logout. WatchMemory shows which tokens and personal data survived — in storage, caches, files and memory — names the store and key that hold them, and gives you a PASS, FAIL or INCOMPLETE verdict you can run in CI.

Download & run your first residue check

Free: one residue check a day. No account, no upload.

Download WatchMemory

iOS Simulator: Swift, React Native, Flutter and KMP debug builds. Android (beta): debuggable builds, disk only, CLI on Linux or macOS. Runs locally; nothing is uploaded.

Residue check · com.acme.appExample

iOS Simulator · React Native (Hermes) · debug build

Coverage

0 %

Secrets before logout

0

Survived

0

Refresh token · High

disk · SDK:redux-persist › persist:root › auth › refreshToken

SURVIVED

Access token (JWT) · High

disk · URLCache Cache.db + JS heap

SURVIVED

Session ID · High

memory only · JS heap, pending GC

REPORT-ONLY

E-mail · Medium

disk · SDK:redux-persist › persist:root › user › email

released

FAIL · 3 secrets survived logout in 4 places (2 blocking)

Logout rarely cleans up everything

A refresh token in UserDefaults or AsyncStorage, a JWT in the URL cache, a session in shared_preferences or DataStore: logout bugs are invisible in the UI and show up later in pentest reports. OWASP lists the weakness as MASWE-0024 (sensitive data accessible after session termination), but no MASTG test automates it.

WatchMemory turns logout into a test

Capture before, log out, capture after. Each secret is matched by a keyed hash, even if it moved to another file or address, and reported once: every place it survived, the store and key that hold it, and a fix. A capture that read too little is INCOMPLETE, never a silent PASS.

How it works

Step 1

Log in to your app in the Simulator or emulator

Step 2

Capture: storage, caches, files and memory

Step 3

Log out the way a user would

Step 4

Capture again: PASS, FAIL or INCOMPLETE, per secret

Built for one job: proving logout cleans up

Results per secret

“3 secrets survived logout in 7 places.” One group per secret (the same token in memory and on disk is one result), with survived, appeared and released matched by keyed hash.

The store and key, not just a pattern

Key-aware extraction from plists, SQLite, JSON, XML preferences, MMKV and DataStore names the exact key, e.g. SDK:redux-persist › persist:root › auth › refreshToken. Values seen before logout are looked up again after it, so opaque tokens no regex matches are found too (as written, not re-encoded).

Verdicts you can trust

PASS, FAIL or INCOMPLETE. Below 90 % coverage it's INCOMPLETE. Memory-only survivors fail the gate only where that's reliable (native code with MallocScribble on); in React Native and Flutter heaps they're reported, not failed.

iOS Simulator and Android (beta)

Swift, React Native, Flutter and KMP debug builds on the iOS Simulator. Android debuggable builds over adb run-as (no root), from the CLI on Linux or macOS.

Mapped to OWASP MAS v2

Survivors map to MASWE-0024 (MASVS-AUTH-3); data on disk to MASVS-STORAGE-1 and MASTG-TEST-0302 (iOS) or MASTG-TEST-0207 (Android). Evidence for your review, not a certificate.

Validated detectors

JWTs, bearer headers, AWS/GitHub/Slack/Google/Stripe keys, private keys, Luhn- and issuer-checked cards, IBAN (mod-97), T.C. Kimlik No (checksum), e-mail and phone, plus refresh, access and session tokens recognised by their key.

Example residue check

Access token (JWT)

Expected after logout: gone

Actual: still in Library/Caches/…/Cache.db (URLCache) and in memory

High · fails the gate (disk) · MASWE-0024

The token survived logout in the URLSession cache. Use an ephemeral session (or Cache-Control: no-store) for authenticated calls and clear URLCache on logout. The memory copy is reported too; on its own it would not fail the gate unless MallocScribble is on.

From capture to verdict

1

Capture

Before and after logout: storage, caches and files, plus memory on iOS. Every capture states its coverage.

2

Compare

Each secret is matched by keyed hash across captures and grouped, with the store, the key and the blocking reason.

3

Fix and re-check

Apply the fix for that store, then run the check again until it says PASS.

What happens after you download

Open WatchMemory and run the System check (Xcode, Simulator, developer mode)

Log in to your app in the Simulator and start a residue check

Log out when asked: get PASS, FAIL or INCOMPLETE, with a fix for each surviving secret

Evidence you can attach to a release

Export a self-contained HTML report (print it to PDF) for a residue check or a CI run. It states what was scanned, how much, and on which platform and build, so a PASS means something.

  • • PASS / FAIL / INCOMPLETE with coverage
  • • Per-secret groups: where it survived, store and key, blocking reason
  • • OWASP MAS v2 references: MASWE-0024, MASVS-STORAGE-1, MASTG-TEST-0302 / 0207
  • • Platform, runtime and build mode on every report
  • • Masked values and keyed hashes only

A release gate, not just a dashboard

Run the same check in CI after your UI tests. With Pro or Team it fails the build when a canary or a high-risk secret survives logout. Free runs report-only with the same, truthful verdict.

  • • iOS: memory plus the Simulator container (UserDefaults, URLCache, SQLite/Core Data, Documents, tmp). Android (beta): app data over adb run-as on Linux runners.
  • • Canaries without false alarms: the app generates its own when launched with -WMCanaryMode 1; launch arguments that contain a canary are refused.
  • • MallocScribble recipe, so freed native memory doesn't count as a survivor.
  • • Exit codes 0 PASS, 1 FAIL, 2 INCOMPLETE or error; SARIF, JUnit, Markdown and HTML reports.
  • • Baselines and a .watchmemory.json policy: only new findings fail the build (canaries always do).
  • • Versioned CLI with a published SHA-256 checksum.
# the app generates its own canary; freed native memory is scribbled
SIMCTL_CHILD_WM_CANARY_MODE=1 SIMCTL_CHILD_MallocScribble=1 \
SIMCTL_CHILD_MallocNanoZone=0 xcrun simctl launch booted com.acme.app
# …log in and out with your UI test, then:
watchmemory ci --process MyApp --bundle-id com.acme.app \
  --scan-profile full --baseline .watchmemory-baseline.json \
  --sarif wm.sarif --junit wm.xml

Download CLI 0.3.0 (.tar.gz, Python 3.9+) · SHA-256 · Docs

Works with your AI coding agent

An agent can write a logout fix but can't see whether the token is really gone. WatchMemory's MCP server lets Claude Code, Cursor and other agents check the running Simulator app.

  • • check_environment, scan_memory, scan_disk, compare_residue_captures and assert_no_residue tools
  • • Raw secret values are never sent to the model: masked previews and hashes only
  • • Runs locally over stdio; scan data never leaves your Mac

Pricing

Free

$0

  • • 1 logout residue check per day, with the full verdict and the first 5 surviving secrets in detail
  • • Quick scans, plus 1 Full scan per day
  • • CLI, Android beta and CI in report-only mode: truthful verdict, build not failed
  • • MCP scan tools within the daily quota

Pro

$12 / month · or $99 / year

  • • For 1 developer: unlimited residue checks and scans, every finding
  • • Evidence report export (HTML, print-ready)
  • • CI enforcement for 1 app: fail the build when a secret survives logout
  • • Mac app, CLI (including Android beta) and MCP server

Team

$1,500 / app / year

Founding price: $990 for the first 20 apps

  • • Per app: the iOS bundle ID and Android package of the same app count as 1 app; extra apps −30 %
  • • Unlimited developers and CI runners
  • • Offline licence and invoice
  • • Shared baselines and policy; account-switch and delete-account scenarios with v0.4

Founding price: $990/yr for the first 20 apps, first app per organisation, locked for 24 months, in exchange for a named reference or case study and a quarterly feedback call. Manual pre-sale: contact us.

Enterprise

From $6,000 / year

  • • 5 apps included, +$900 per extra app
  • • Signed evidence, compliance crosswalk and accepted-risk register
  • • Vendor security pack and air-gapped use

Coming with v1.0. Talk to us.

Prices in USD. Pro is sold through Lemon Squeezy (merchant of record), which calculates taxes at checkout. Team is invoiced. Scans always run locally.

Frequently asked questions

What is WatchMemory?

A local-first data-residue tester for mobile apps. It captures your app's storage, caches, files and (on iOS) memory before and after logout and tells you which tokens and personal data survived, with a PASS, FAIL or INCOMPLETE verdict.

Does it work with React Native, Flutter or Kotlin Multiplatform?

Yes, on the iOS Simulator with debug builds (Flutter runs only in debug mode on the Simulator). Findings are labelled with the store and key, such as AsyncStorage, MMKV or flutter.* preferences, and the runtime is stamped on every report. Memory-only hits in the JavaScript (Hermes) or Dart heap are reported but don't fail the gate, because freed strings there wait for garbage collection. Storage results gate as usual.

Does it support Android?

In beta. The CLI reads a debuggable build's private data over adb run-as (no root) on Linux or macOS, including CI runners. It covers disk only: SharedPreferences, DataStore, Room/SQLite, WebView data, the OkHttp cache, MMKV and files. There are no Android memory results yet.

Can it scan App Store or release builds?

No, by design. iOS and Android only let a debugger or run-as reach debug (debuggable) builds. WatchMemory checks your own debug build; release builds can't be inspected, by us or by anyone without the same access.

Does it require an SDK?

No SDK needed. Optional: the WatchMemoryDebugAgent Swift package (DEBUG builds only) lets the app generate a WMCANARY_ canary for zero-false-positive checks.

Does it inspect the Keychain?

Not yet. Keychain items live outside the app container, so a token left in the Keychain after logout isn't reported today. Delete Keychain items in your logout code; a Keychain lifecycle check is on the roadmap.

Does it work on a physical iPhone?

Not yet. iOS scans target Simulator apps on your Mac. Physical-device support is on the roadmap.

Does it make my app compliant or MASVS certified?

No tool can: OWASP doesn't certify apps or tools. WatchMemory automates the OWASP MASWE-0024 check and maps results to MASVS-STORAGE and MASVS-AUTH-3, so you have evidence for a review or a pentest.

What happens in CI on the Free plan?

The check runs and reports a truthful verdict, labelled report-only. A FAIL still exits 0, so the build isn't failed. Pro enforces for one app; Team covers every developer and runner of an app.

What does it need?

Mac app: macOS 14+ and Xcode (it brings the iOS Simulator and LLDB); the scan engine is bundled. CLI: Python 3.9+, plus Xcode for iOS or adb for Android (Linux or macOS).

Do my secrets leave my machine?

No. Scans run locally, values are masked and hashed with a per-install key in every report by default, and the MCP server never sends raw values to AI models. The only network calls are the Pro licence check and a daily update check (version number only).

Quick answers

What is WatchMemory?

A local-first data-residue tester: it proves that logout removes tokens and personal data from a mobile app's storage, caches and memory, with a PASS / FAIL / INCOMPLETE verdict.

Who is it for?

Mobile teams shipping apps with accounts, payments or health data: native iOS, React Native, Flutter and KMP on the iOS Simulator, and Android (beta) for debuggable builds.

How is it different from Xcode Instruments or LeakCanary?

Those find leaked objects and measure memory. WatchMemory searches for secret values and checks whether they are gone after logout. Use them together.

Which standard does it map to?

OWASP MAS v2: MASWE-0024 (sensitive data accessible after session termination), MASVS-STORAGE-1/2 and MASVS-AUTH-3. It automates the MASWE-0024 check; it doesn't certify compliance.

Logout and data-residue guides

Practical guides on clearing tokens and personal data on logout, for iOS, React Native, Flutter and Android.

Read all articles

Prove your app forgets before every release

Run a residue check on your next build. Free, local, no account.

Team pricing, invoices or a founding-price pilot? Email us

WatchMemory's Mac app is local-first: scans and reports stay on your machine. Web analytics on this site are privacy-friendly and only used to improve the website.