Chatgot 5.4 found security and privacy issues plus unexpected permission. At first glance this app appears to come from the actual proton organization but Im pretty sure the description is misleading in that way for a reason. Let me know if im wrong.
Gpt's findings :
"I went through both the APK and the source zip with a static review.
What I checked
I inspected the source tree, manifest, WebView code, speech-recognition code, permissions, and packaged APK manifest.
I also compared the source package to the APK:
the source zip comment is 6310d17
the APK embeds the same revision in META-INF/version-control-info.textproto
So the APK and source you uploaded appear to match. That is a nice sanity check.
Main security and privacy findings
- Trusted-domain validation is weak
This is the biggest real issue I found.
In LumoConfig.kt, trusted-domain checks use simple substring matching:
isLumoDomain(url) = url?.contains(LUMO_DOMAIN) == true
isAccountDomain(url) = url?.contains(ACCOUNT_DOMAIN) == true
In LumoWebClient.kt, those checks are then used to decide:
whether a page is treated as trusted
whether it stays inside the WebView
whether JavaScript gets injected
In WebAppInterface.kt, the app adds a global JavaScript bridge named Android to the WebView.
Why that matters:
A malicious URL like:
https://evil.com/?next=account.proton.me
https://account.proton.me.evil.tld/...
could be misclassified as trusted, because it merely contains the trusted hostname string.
That means an attacker-controlled page could potentially remain inside the WebView and gain access to the Android bridge methods such as:
startVoiceEntry()
showPayment()
retryLoad()
navigation/theme callbacks
The exposed methods are not full remote code execution, so this is not apocalypse-in-a-trench-coat, but it is still a meaningful trust-boundary bug in a privacy-focused app.
Files involved
app/src/main/java/me/proton/android/lumo/config/LumoConfig.kt:60-70
app/src/main/java/me/proton/android/lumo/webview/LumoWebClient.kt:183-213
app/src/main/java/me/proton/android/lumo/webview/WebAppInterface.kt:21-31, 61-119
What should be done
Parse the URI properly.
Compare the actual host, not contains(...).
Use exact host matching or a strict whitelist.
- WebView mixed content is explicitly allowed
In WebViewScreen.kt, the app sets:
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
That is a bad setting for a privacy/security-sensitive wrapper app. Android’s own guidance explicitly recommends avoiding MIXED_CONTENT_ALWAYS_ALLOW because it weakens app security, and Android also documents that WebView honors usesCleartextTraffic for modern target SDKs.
Why this matters:
The manifest sets android:usesCleartextTraffic="false", which is good.
But the WebView is still being configured in a way that is much looser than it should be.
If any trusted page ever loads insecure subresources or mixed content, that increases exposure to tampering.
File
app/src/main/java/me/proton/android/lumo/webview/WebViewScreen.kt:34-40
What should be done
Use MIXED_CONTENT_NEVER_ALLOW
or at worst MIXED_CONTENT_COMPATIBILITY_MODE if there is some legacy requirement
For a privacy-branded app, ALWAYS_ALLOW is the kind of foot-gun that should be locked in a drawer.
- Speech input can fall back to Google processing
This is the biggest privacy caveat.
In SpeechRecognitionManager.kt, the app chooses engines like this:
First choice: Android on-device recognition
Second choice: Vosk on-device recognition
On initialization failure, it falls back again:
OnDevice -> Vosk -> GoogleSpeechRecognizer
And the UI strings explicitly say:
Recognition processed by Google
Recognition processed by Vosk • On-device • Private
On-device • Private
So the app is telling on itself here.
Files
app/src/main/java/me/proton/android/lumo/speech/SpeechRecognitionManager.kt:48-55, 115-125
app/src/main/res/values/strings.xml:28-31
Why this matters:
If the private/on-device engines fail, microphone audio or transcripts may be handled by the device’s Google speech-recognition service instead.
For a “privacy-first” assistant, that fallback needs to be made very explicit to the user.
I would rate this as a real privacy concern, not because it is hidden malware, but because it changes the trust model.
What should be done
Add a hard user setting like:
“Never use cloud speech”
In a nogms build, I would strongly consider disabling Google fallback entirely.
- Recognized speech text is written to logs
This is not ideal.
In AndroidSpeechRecognizer.kt, the code logs:
final recognition text
partial recognition text
Examples:
Log.d(TAG, "SpeechRecognizer: onResults: $text")
Log.d(TAG, "SpeechRecognizer: onPartialResults: $text")
It also logs WebView URLs and some JS activity elsewhere.
Files
app/src/main/java/me/proton/android/lumo/speech/recognizer/android/AndroidSpeechRecognizer.kt:80-99
app/src/main/java/me/proton/android/lumo/webview/LumoWebClient.kt:32-40, 74, 156-159
app/src/main/java/me/proton/android/lumo/webview/WebAppInterface.kt:103-118
Why this matters:
On rooted devices, dev builds, adb-connected situations, or privileged log access, transcripts and navigation details may leak into logs.
That is exactly the sort of thing a privacy app should avoid in release builds.
What should be done
Strip or gate logs in release
never log recognized speech text
never log sensitive URLs or JS payloads
- Auto backup is enabled, with no real backup policy in effect
The manifest has:
android:allowBackup="true"
But I did not find the manifest wired to an actual restrictive backup policy. The source tree contains sample backup XML files, but they are just template stubs and are not referenced by the manifest.
Android’s documentation says that when backup is enabled and no explicit rules are provided, Auto Backup includes most app files by default.
Files
app/src/main/AndroidManifest.xml:23-32
app/src/main/res/xml/backup_rules.xml
app/src/main/res/xml/data_extraction_rules.xml
Why this matters:
Even if the app stores only modest local data directly, a WebView-based app may still accumulate cookies, session state, cached content, and app-private files.
Backup/transfer behavior is something a privacy-sensitive app should control explicitly, not leave to defaults.
What should be done
either disable backup
or explicitly exclude sensitive WebView/app data with proper backup rules
- The packaged APK contains unexpected extra permissions
The source manifest is very lean:
INTERNET
ACCESS_NETWORK_STATE
RECORD_AUDIO
But the APK manifest also includes:
READ_PHONE_STATE
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
I did not find corresponding runtime-request logic in the app source for those permissions.
That means one of two things is happening:
a dependency is contributing them during manifest merge, or
there is stale legacy baggage in the packaging
Why this matters:
READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE are legacy and much less meaningful on modern Android, but they still should not be there without reason.
READ_PHONE_STATE is more sensitive and stands out like a raccoon in a tuxedo.
Where I found it
extracted APK manifest lines 32, 34, and 36
I cannot prove from this static review that the app is actively using phone-state data, and I do not want to overclaim that. But I can say those permissions are unexpected and should be traced.
What should be done
inspect the merged manifest blame
remove unneeded permissions explicitly with manifest merge rules
Things that looked better
I did not find obvious Firebase, Crashlytics, ads SDKs, or Sentry in the nogms APK.
The Gradle config scopes Sentry to the GMS flavor, and I did not see Sentry artifacts in the nogms package.
WebView debugging is only enabled for debug builds.
The manifest does set usesCleartextTraffic="false".
So this does not look like an obvious tracker-stuffed spyware APK. The problems I found are more about WebView trust boundaries, privacy fallbacks, and Android hardening quality.
Bottom-line assessment
If I rank the findings by importance:
Most important security bug: weak trusted-domain matching with contains(...)
Most important privacy issue: speech can fall back to Google processing
Most important hardening issue: MIXED_CONTENT_ALWAYS_ALLOW
Most suspicious packaging issue: unexpected READ_PHONE_STATE / storage permissions in the final APK
Most avoidable privacy hygiene issue: transcript logging and enabled backups"
One more important caveat
This app is fundamentally a WebView wrapper around a remote web app. That means even if the APK itself is relatively clean, the actual behavior can still change later based on what the server delivers. So static APK review is useful, but it cannot fully guarantee privacy at runtime.
If you want the next step, the most valuable follow-up would be a runtime traffic and behavior review: certificate inspection, DNS destinations, logcat behavior, WebView storage, and whether any unexpected permissions ever get requested."
Chatgot 5.4 found security and privacy issues plus unexpected permission. At first glance this app appears to come from the actual proton organization but Im pretty sure the description is misleading in that way for a reason. Let me know if im wrong.
Gpt's findings :
"I went through both the APK and the source zip with a static review.
What I checked
I inspected the source tree, manifest, WebView code, speech-recognition code, permissions, and packaged APK manifest.
I also compared the source package to the APK:
the source zip comment is 6310d17
the APK embeds the same revision in META-INF/version-control-info.textproto
So the APK and source you uploaded appear to match. That is a nice sanity check.
Main security and privacy findings
This is the biggest real issue I found.
In LumoConfig.kt, trusted-domain checks use simple substring matching:
isLumoDomain(url) = url?.contains(LUMO_DOMAIN) == true
isAccountDomain(url) = url?.contains(ACCOUNT_DOMAIN) == true
In LumoWebClient.kt, those checks are then used to decide:
whether a page is treated as trusted
whether it stays inside the WebView
whether JavaScript gets injected
In WebAppInterface.kt, the app adds a global JavaScript bridge named Android to the WebView.
Why that matters:
A malicious URL like:
https://evil.com/?next=account.proton.me
https://account.proton.me.evil.tld/...
could be misclassified as trusted, because it merely contains the trusted hostname string.
That means an attacker-controlled page could potentially remain inside the WebView and gain access to the Android bridge methods such as:
startVoiceEntry()
showPayment()
retryLoad()
navigation/theme callbacks
The exposed methods are not full remote code execution, so this is not apocalypse-in-a-trench-coat, but it is still a meaningful trust-boundary bug in a privacy-focused app.
Files involved
app/src/main/java/me/proton/android/lumo/config/LumoConfig.kt:60-70
app/src/main/java/me/proton/android/lumo/webview/LumoWebClient.kt:183-213
app/src/main/java/me/proton/android/lumo/webview/WebAppInterface.kt:21-31, 61-119
What should be done
Parse the URI properly.
Compare the actual host, not contains(...).
Use exact host matching or a strict whitelist.
In WebViewScreen.kt, the app sets:
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
That is a bad setting for a privacy/security-sensitive wrapper app. Android’s own guidance explicitly recommends avoiding MIXED_CONTENT_ALWAYS_ALLOW because it weakens app security, and Android also documents that WebView honors usesCleartextTraffic for modern target SDKs.
Why this matters:
The manifest sets android:usesCleartextTraffic="false", which is good.
But the WebView is still being configured in a way that is much looser than it should be.
If any trusted page ever loads insecure subresources or mixed content, that increases exposure to tampering.
File
app/src/main/java/me/proton/android/lumo/webview/WebViewScreen.kt:34-40
What should be done
Use MIXED_CONTENT_NEVER_ALLOW
or at worst MIXED_CONTENT_COMPATIBILITY_MODE if there is some legacy requirement
For a privacy-branded app, ALWAYS_ALLOW is the kind of foot-gun that should be locked in a drawer.
This is the biggest privacy caveat.
In SpeechRecognitionManager.kt, the app chooses engines like this:
First choice: Android on-device recognition
Second choice: Vosk on-device recognition
On initialization failure, it falls back again:
OnDevice -> Vosk -> GoogleSpeechRecognizer
And the UI strings explicitly say:
Recognition processed by Google
Recognition processed by Vosk • On-device • Private
On-device • Private
So the app is telling on itself here.
Files
app/src/main/java/me/proton/android/lumo/speech/SpeechRecognitionManager.kt:48-55, 115-125
app/src/main/res/values/strings.xml:28-31
Why this matters:
If the private/on-device engines fail, microphone audio or transcripts may be handled by the device’s Google speech-recognition service instead.
For a “privacy-first” assistant, that fallback needs to be made very explicit to the user.
I would rate this as a real privacy concern, not because it is hidden malware, but because it changes the trust model.
What should be done
Add a hard user setting like:
“Never use cloud speech”
In a nogms build, I would strongly consider disabling Google fallback entirely.
This is not ideal.
In AndroidSpeechRecognizer.kt, the code logs:
final recognition text
partial recognition text
Examples:
Log.d(TAG, "SpeechRecognizer: onResults: $text")
Log.d(TAG, "SpeechRecognizer: onPartialResults: $text")
It also logs WebView URLs and some JS activity elsewhere.
Files
app/src/main/java/me/proton/android/lumo/speech/recognizer/android/AndroidSpeechRecognizer.kt:80-99
app/src/main/java/me/proton/android/lumo/webview/LumoWebClient.kt:32-40, 74, 156-159
app/src/main/java/me/proton/android/lumo/webview/WebAppInterface.kt:103-118
Why this matters:
On rooted devices, dev builds, adb-connected situations, or privileged log access, transcripts and navigation details may leak into logs.
That is exactly the sort of thing a privacy app should avoid in release builds.
What should be done
Strip or gate logs in release
never log recognized speech text
never log sensitive URLs or JS payloads
The manifest has:
android:allowBackup="true"
But I did not find the manifest wired to an actual restrictive backup policy. The source tree contains sample backup XML files, but they are just template stubs and are not referenced by the manifest.
Android’s documentation says that when backup is enabled and no explicit rules are provided, Auto Backup includes most app files by default.
Files
app/src/main/AndroidManifest.xml:23-32
app/src/main/res/xml/backup_rules.xml
app/src/main/res/xml/data_extraction_rules.xml
Why this matters:
Even if the app stores only modest local data directly, a WebView-based app may still accumulate cookies, session state, cached content, and app-private files.
Backup/transfer behavior is something a privacy-sensitive app should control explicitly, not leave to defaults.
What should be done
either disable backup
or explicitly exclude sensitive WebView/app data with proper backup rules
The source manifest is very lean:
INTERNET
ACCESS_NETWORK_STATE
RECORD_AUDIO
But the APK manifest also includes:
READ_PHONE_STATE
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
I did not find corresponding runtime-request logic in the app source for those permissions.
That means one of two things is happening:
a dependency is contributing them during manifest merge, or
there is stale legacy baggage in the packaging
Why this matters:
READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE are legacy and much less meaningful on modern Android, but they still should not be there without reason.
READ_PHONE_STATE is more sensitive and stands out like a raccoon in a tuxedo.
Where I found it
extracted APK manifest lines 32, 34, and 36
I cannot prove from this static review that the app is actively using phone-state data, and I do not want to overclaim that. But I can say those permissions are unexpected and should be traced.
What should be done
inspect the merged manifest blame
remove unneeded permissions explicitly with manifest merge rules
Things that looked better
I did not find obvious Firebase, Crashlytics, ads SDKs, or Sentry in the nogms APK.
The Gradle config scopes Sentry to the GMS flavor, and I did not see Sentry artifacts in the nogms package.
WebView debugging is only enabled for debug builds.
The manifest does set usesCleartextTraffic="false".
So this does not look like an obvious tracker-stuffed spyware APK. The problems I found are more about WebView trust boundaries, privacy fallbacks, and Android hardening quality.
Bottom-line assessment
If I rank the findings by importance:
Most important security bug: weak trusted-domain matching with contains(...)
Most important privacy issue: speech can fall back to Google processing
Most important hardening issue: MIXED_CONTENT_ALWAYS_ALLOW
Most suspicious packaging issue: unexpected READ_PHONE_STATE / storage permissions in the final APK
Most avoidable privacy hygiene issue: transcript logging and enabled backups"
One more important caveat
This app is fundamentally a WebView wrapper around a remote web app. That means even if the APK itself is relatively clean, the actual behavior can still change later based on what the server delivers. So static APK review is useful, but it cannot fully guarantee privacy at runtime.
If you want the next step, the most valuable follow-up would be a runtime traffic and behavior review: certificate inspection, DNS destinations, logcat behavior, WebView storage, and whether any unexpected permissions ever get requested."