89095 w a high android process death defeats recovery phrase clipboard expiry and exposes the mnemonic to later foreground apps
Submitted on Aug 17th 2026 at 06:03:52 UTC by @Ailenia for Audit Comp | Quantus
Report ID: #89095
Report Type: Websites & Apps
Report severity: High
Target: https://github.com/immunefi-team/audit-comp-quantus-apps/tree/audit-comp-ready/mobile-app
Impacts:
Improperly disclosing confidential user information, such as:
Email address
Phone number
Physical address, etc.
Description
Brief/Intro
The Quantus mobile wallet copies a 24-word recovery phrase to Android's global clipboard and promises to erase it after three minutes, but implements that guarantee with an in-process Dart Timer.
This means that if Android kills the wallet process, or the process is explicitly terminated, before the deadline, the timer disappears while the phrase remains in the system clipboard.
A separate application that becomes foreground after the promised expiry can then recover the phrase.
The clipboard entry is also not marked sensitive.
Vulnerability Details
At frozen apps commit d5fc4d6572ebc2244e95009a33f5da5048935867, mobile-app/lib/v2/components/recovery_phrase_body.dart:61 passes the joined recovery phrase to copySensitiveTextWithToaster, which calls SecureClipboardService.copyWithExpiry with its production default TTL of three minutes.
The service has an OS-backed implementation only for iOS. Since on Android, Platform.isIOS is false, the lines 45-46 write the phrase through Flutter's global clipboard API and schedule an in-process timer:
iOS instead sets UIPasteboard with .expirationDate and .localOnly, which remains effective after suspension or termination. Android has no native secure_clipboard channel handler. Terminating the Android process destroys the Dart VM and _clearTimer; reopening the wallet creates a new service instance and does not know that an old clipboard entry must be cleared.
The source comment says that after backgrounding "the clear happens when it next resumes," but no persisted deadline or resume handler exists. The Android copy also omits ClipDescription.EXTRA_IS_SENSITIVE, so Android does not conceal the mnemonic in clipboard previews.
On Android 10 and later, a clipboard reader must be the foreground application or default IME. The attack therefore requires another application already installed on the victim's device. The victim performs the wallet's intended Copy Recovery Phrase action; Android later kills the backgrounded process under ordinary lifecycle pressure, or the process is otherwise terminated. The attacker application can then be opened normally after the three-minute deadline and read the phrase. Merely backgrounding the wallet without process death is not sufficient. This does not require physical access, local-network access, a compromised Quantus service, or a malicious blockchain transaction.
Android 13 and later can provide system auto-clear, but its timeout is device-configurable and clipboard access can refresh the system's timer. On the tested Android 16 device the configured timeout was 3,600 seconds, so Quantus's promised 180-second bound was not enforced. Android's official guidance states that older versions do not provide this automatic deletion.
Impact Details
This matches the programme's High websites-and-applications impact 48, "Improperly disclosing confidential user information." A recovery phrase is the wallet's most confidential user information. The PoC proves that an independent foreground application can retrieve it after Quantus's advertised security deadline has passed.
The report does not claim that process death grants a new Android clipboard permission or that every Android user is affected automatically. It creates a temporal disclosure path: without the defect, an application first foregrounded after three minutes receives an empty clipboard; with the defect, it receives the complete phrase. Possession of a funded wallet's phrase can ultimately enable fund theft, but this report conservatively selects the demonstrated High disclosure impact rather than claiming Critical fund loss.
Remediation
Do not place recovery phrases on Android's global clipboard unless the user explicitly accepts that exposure. If copying remains supported, implement a native Android path that marks the clip with ClipDescription.EXTRA_IS_SENSITIVE, records a persistent expiry deadline, and clears a matching stale clip on lifecycle recovery or next launch. Treat the sensitive flag as preview protection rather than an expiry mechanism, and do not claim a hard three-minute bound unless an OS-backed mechanism can enforce it after process death.
References
Link to Proof of Concept
https://gist.github.com/niafreu/beddb6e36f215ece0cdb0d38e8431e69
Proof of Concept
Gist at https://gist.github.com/niafreu/beddb6e36f215ece0cdb0d38e8431e69
The attached PoC is entirely local and uses a fake BIP-39 canary which for the demo is the equivalent of a real wallet phrase. It builds a minimal Flutter victim around the SecureClipboardService and a separate native Android foreground reader.
Requirements: Linux or macOS, Flutter 3.47.0 with Dart 3.13.0, JDK 11 or later, Android SDK platform 36 and build-tools 36.1.0, and either an Android emulator or disposable Android device reachable through adb.
I used Android 16/API 36 and it shows:
Both readers ran approximately 188 seconds after the copy. The live control returned an empty value at the same boundary, isolating process termination as the cause.
The absent sensitive flag is additional exposure evidence; it does not itself affect clipboard expiry or programmatic reads.
The attached execution.log preserves the passing Android 16/API 36 run.
PoC files
run.sh
victim_main.dart
secure_clipboard_service.dart
ReaderActivity.java
AndroidManifest-reader.xml
Was this helpful?