Skip to content

Chatgpt latest source code and apk review results #32

@JDub545

Description

@JDub545

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

  1. 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.

  1. 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.

  1. 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.

  1. 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

  1. 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

  1. 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."

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions