Add security audit report
Static source review of commit 358144ee61 covering malware, backdoors, information leaks, obfuscated code, and remote code-download behaviour. Verdict: clean - 0 critical/high/medium/low findings, 3 informational observations.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
358144ee61
commit
672a3f7938
1 changed files with 473 additions and 0 deletions
473
AUDIT.md
Normal file
473
AUDIT.md
Normal file
|
|
@ -0,0 +1,473 @@
|
|||
# Security Audit Report
|
||||
|
||||
## Tangem Android Wallet — Source Code Review
|
||||
|
||||
---
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Subject** | `tangem-app-android` — Tangem cryptocurrency wallet for Android |
|
||||
| **Upstream** | `https://github.com/tangem/tangem-app-android` |
|
||||
| **Commit reviewed** | `358144ee61a` (branch `master`) |
|
||||
| **Report date** | 17 August 2026 |
|
||||
| **Review type** | Static source code review (manual, targeted) |
|
||||
| **Codebase size** | ~292 Gradle modules · 7,719 Kotlin files · 641 XML · 5 Java |
|
||||
| **Objective** | Detect malware, backdoors, information leaks, obfuscated code, and remote code-download behaviour |
|
||||
|
||||
---
|
||||
|
||||
## 1. Executive Summary
|
||||
|
||||
**The reviewed source code is clean.** No malicious code, backdoor, data-exfiltration channel,
|
||||
obfuscated logic, or remote code-download ("dropper") capability was identified.
|
||||
|
||||
Beyond the absence of malicious code, the codebase demonstrates **deliberate, consistent defensive
|
||||
engineering** of a standard appropriate to software that custodies private keys. Several controls
|
||||
found here are ones that trojanised or negligent applications characteristically lack: JavaScript
|
||||
is disabled in WebViews with no JavaScript bridge present at all, certificate validation is left
|
||||
entirely intact, analytics identifiers are cryptographically hashed rather than transmitted raw,
|
||||
and the application manifest actively *removes* location and microphone permissions that bundled
|
||||
third-party SDKs attempt to introduce.
|
||||
|
||||
Ten categories of malicious or leak-prone behaviour were examined. All ten returned negative.
|
||||
Three informational observations are recorded in §5 — none is a vulnerability, and none affects
|
||||
the verdict.
|
||||
|
||||
### Findings Summary
|
||||
|
||||
| Severity | Count | Detail |
|
||||
|---|---|---|
|
||||
| **Critical** | **0** | — |
|
||||
| **High** | **0** | — |
|
||||
| **Medium** | **0** | — |
|
||||
| **Low** | **0** | — |
|
||||
| Informational | 3 | Operational notes for downstream forks (§5) |
|
||||
|
||||
### Verdict
|
||||
|
||||
> **CLEAN.** Nothing in the reviewed first-party source behaves maliciously or leaks sensitive
|
||||
> data. The security posture is materially better than typical for the category.
|
||||
|
||||
Readers should note the scope boundaries in §6 — most importantly that Tangem's own SDKs are
|
||||
consumed as **pre-built binary artifacts** and were therefore outside the reach of this source
|
||||
review.
|
||||
|
||||
---
|
||||
|
||||
## 2. Methodology
|
||||
|
||||
The review targeted the behaviours that distinguish malicious software from ordinary application
|
||||
code, rather than attempting an exhaustive line-by-line reading of 7,719 files. Each question
|
||||
below was resolved by exhaustive pattern analysis across the full tree, followed by manual reading
|
||||
of every candidate hit in context.
|
||||
|
||||
| # | Question put to the code | Result |
|
||||
|---|---|---|
|
||||
| 1 | Can it load or execute code obtained at runtime? | **No** |
|
||||
| 2 | Can it execute shell commands or spawn processes? | **No** |
|
||||
| 3 | Does it ship native binaries or opaque blobs? | **No** |
|
||||
| 4 | Does key material reach logs, storage, or the network? | **No** |
|
||||
| 5 | Does it contact hidden or hostile endpoints? | **No** |
|
||||
| 6 | Are live credentials committed to the repository? | **No** |
|
||||
| 7 | Can the build system pull hostile artifacts? | **No** |
|
||||
| 8 | Does telemetry leak personally identifying data? | **No** — pseudonymised |
|
||||
| 9 | Is transport security weakened anywhere? | **No** — hardened |
|
||||
| 10 | Are permissions over-broad or components exposed? | **No** — minimised |
|
||||
|
||||
A finding was only cleared once the underlying code was read and understood in context. Two
|
||||
pattern classes produce **misleading automated results** and are documented explicitly in §4 so
|
||||
that any repeat or automated review does not raise a false alarm.
|
||||
|
||||
---
|
||||
|
||||
## 3. Detailed Findings
|
||||
|
||||
### 3.1 Runtime Code Loading and Dropper Behaviour — CLEAN
|
||||
|
||||
No occurrence of `DexClassLoader`, `PathClassLoader`, `BaseDexClassLoader`,
|
||||
`InMemoryDexClassLoader`, or any `dalvik.system` API exists in the repository. The application
|
||||
cannot load code it did not ship with.
|
||||
|
||||
**Process execution.** Exactly one match tree-wide:
|
||||
|
||||
```kotlin
|
||||
// app/src/main/java/com/tangem/tap/common/finisher/AndroidAppFinisher.kt:25
|
||||
Runtime.getRuntime().exit(0)
|
||||
```
|
||||
|
||||
This terminates the application's own process. It executes nothing.
|
||||
|
||||
**Native code.** No `.so` libraries, no JNI, no NDK build inputs. Only two `.jar` files exist in
|
||||
the tree:
|
||||
|
||||
| File | Size | Assessment |
|
||||
|---|---|---|
|
||||
| `gradle/wrapper/gradle-wrapper.jar` | 55.6 KB | Standard Gradle 8.14.1 wrapper |
|
||||
| `app/libs/dexprotector-annotations.jar` | 3.5 KB | Compile-time annotations only (§3.9) |
|
||||
|
||||
**Reflection.** Searches for `Class.forName`, `getDeclaredMethod`, `getDeclaredField`, and
|
||||
`setAccessible` returned **zero** genuine results. There is no reflective dispatch to hide
|
||||
behaviour behind.
|
||||
|
||||
### 3.2 Obfuscation and Encoded Payloads — CLEAN
|
||||
|
||||
A scan for long opaque literals (≥200 characters of Base64-like text) returned three hits, all in
|
||||
`libs/visa/`:
|
||||
|
||||
- `TangemPaymentAccountRegistry.java`
|
||||
- `TangemBridgeProcessor.java`
|
||||
- `TangemPaymentAccount.java`
|
||||
|
||||
Each declares `public static final String BINARY = "6080604052…"`. The `6080604052` prefix is the
|
||||
standard **EVM (Solidity) contract constructor prologue**. These are Web3j-generated smart-contract
|
||||
wrappers carrying on-chain deployment bytecode — an expected artifact of the Visa payment-account
|
||||
integration, not concealed program logic.
|
||||
|
||||
All eight `Base64.decode` call sites serve declared cryptographic purposes — AES/RSA key and IV
|
||||
decoding in `RainCryptoUtil`, `DefaultAuthNonceDecryptor`, and `SetVisaPinCodeUseCase`, plus swap
|
||||
transaction decoding. None reconstructs an executable payload.
|
||||
|
||||
### 3.3 Private Key and Seed Phrase Handling — CLEAN
|
||||
|
||||
This is the highest-consequence area for a wallet. It is handled correctly.
|
||||
|
||||
**Key material never reaches logs.** Every logging call (`Log.*`, `Timber.*`, `println`) was
|
||||
cross-referenced against *mnemonic, seed, privateKey, passphrase, secret, accessCode, passcode*.
|
||||
**No true positives.** The only matches were UI-state fields on onboarding screens
|
||||
(`dialog.dismissButtonText`, `dialog.dismissWarningColor`) — incidental matches on the substring
|
||||
"dismiss", carrying no secret data.
|
||||
|
||||
**Key material never reaches the network.** The sole endpoint whose name suggests otherwise is
|
||||
`v1/seedphrase-notification/{wallet_id}`. Its complete payload is:
|
||||
|
||||
```kotlin
|
||||
data class SeedPhraseNotificationDTO(val status: Status)
|
||||
|
||||
enum class Status { NOT_NEEDED, NOTIFIED, DECLINED, CONFIRMED, REJECTED, ACCEPTED }
|
||||
```
|
||||
|
||||
A single enum recording whether the user was reminded to back up their phrase. No phrase material
|
||||
is transmitted.
|
||||
|
||||
**Export is authentication-gated.** `ExportSeedPhraseUseCase` delegates to
|
||||
`DefaultHotWalletAccessor.exportSeedPhrase()`, which routes through `hotSdkRequest()` — a path
|
||||
requiring password or biometric unlock (`HotAuth.Password` / `HotAuth.Biometry`) before the SDK
|
||||
releases the mnemonic. Wrong-password retry and biometric lockout are handled explicitly.
|
||||
|
||||
**Exported phrases have exactly two consumers**, both user-initiated display flows:
|
||||
|
||||
- `features/hot-wallet/impl/…/viewphrase/model/ViewPhraseModel.kt` — user views their own backup
|
||||
- `features/onboarding-v2/impl/…/upgradewallet/model/MultiWalletUpgradeWalletModel.kt`
|
||||
|
||||
Neither transmits, persists, nor logs the value.
|
||||
|
||||
**Supporting controls.** `clearContextualUnlock()` and `clearAllContextualUnlock()` purge unlocked
|
||||
wallet handles from memory; `LockUserWalletsTimer` auto-locks wallets on a timer via WorkManager.
|
||||
|
||||
### 3.4 Network Endpoints — CLEAN
|
||||
|
||||
Every hardcoded host in the tree was enumerated and classified. All fall into legitimate
|
||||
categories:
|
||||
|
||||
| Category | Examples |
|
||||
|---|---|
|
||||
| Public blockchain RPC | Ankr, publicnode, dRPC, thirdweb, Infura, QuikNode, GetBlock, Arbitrum, Base, Solana, Tron, Kaspa, Polkadot |
|
||||
| Tangem infrastructure | `api.tangem.com`, `express.tangem.com`, `buy.tangem.com` |
|
||||
| Payment / staking partners | MoonPay, Mercuryo, P2P.org, StakeKit, Paera |
|
||||
| Documentation / schema | `schemas.android.com`, `developer.android.com`, EIP references |
|
||||
|
||||
No unexplained endpoint, dead-drop host, dynamic-DNS domain, or hardcoded IP address was found.
|
||||
|
||||
### 3.5 Transport Security — HARDENED
|
||||
|
||||
`app/src/main/res/xml/network_security_config.xml`:
|
||||
|
||||
```xml
|
||||
<network-security-config>
|
||||
<base-config cleartextTrafficPermitted="false">
|
||||
<trust-anchors>
|
||||
<certificates src="system" />
|
||||
</trust-anchors>
|
||||
</base-config>
|
||||
</network-security-config>
|
||||
```
|
||||
|
||||
- Cleartext HTTP disabled application-wide.
|
||||
- **System trust anchors only** — user-installed CAs are excluded, resisting casual interception
|
||||
proxies.
|
||||
- No `debug-overrides` block.
|
||||
|
||||
Searches for `X509TrustManager`, `checkServerTrusted`, `HostnameVerifier`, `ALLOW_ALL`, and
|
||||
`SSLContext` returned **zero** results. No certificate-validation bypass exists anywhere in the
|
||||
repository — a common weakness that is simply absent here.
|
||||
|
||||
**WebView.** `core/ui/…/webview/WebViewExt.kt` sets `javaScriptEnabled = false`. There is no
|
||||
`addJavascriptInterface` or `@JavascriptInterface` anywhere in the tree. The JavaScript-bridge
|
||||
attack surface does not exist by construction.
|
||||
|
||||
### 3.6 Permissions and Exported Components — MINIMISED
|
||||
|
||||
Complete permission set across all manifests:
|
||||
|
||||
`INTERNET` · `ACCESS_NETWORK_STATE` · `CAMERA` (QR scanning) · `NFC` (card scanning) ·
|
||||
`USE_BIOMETRIC` · `VIBRATE` · `WAKE_LOCK` · `HIDE_OVERLAY_WINDOWS` · `AD_ID`
|
||||
|
||||
**Absent:** SMS, contacts, call log, location, microphone, external storage, accessibility
|
||||
services, `SYSTEM_ALERT_WINDOW`, `REQUEST_INSTALL_PACKAGES`, `RECEIVE_BOOT_COMPLETED`. The set
|
||||
contains nothing a wallet does not require.
|
||||
|
||||
Two measures are worth drawing out, as both are affirmative hardening rather than mere restraint:
|
||||
|
||||
**1. Overlay defence.** `HIDE_OVERLAY_WINDOWS` is requested to defeat tapjacking — a known vector
|
||||
for hijacking wallet transaction-confirmation dialogs.
|
||||
|
||||
**2. Permission stripping.** The manifest actively removes permissions that bundled third-party
|
||||
SDKs would otherwise introduce through manifest merging:
|
||||
|
||||
```xml
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" tools:node="remove" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" tools:node="remove" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" tools:node="remove" />
|
||||
```
|
||||
|
||||
Denying location and microphone access to advertising and analytics SDKs is a privacy measure that
|
||||
argues directly against hostile intent.
|
||||
|
||||
**Exported components.** Exactly one: `MainActivity`, necessarily exported as the launcher. Its
|
||||
intent filters are tightly scoped — the `LAUNCHER` category, NFC NDEF discovery restricted to
|
||||
`tangem.com` / `www.tangem.com` / `app.tangem.com` under `/ndef` path prefixes, and the `wc:` and
|
||||
`tangem://wc` WalletConnect schemes.
|
||||
|
||||
The single declared service, `TangemPushNotificationService` (Firebase Cloud Messaging), is
|
||||
`exported="false"`. There are **no broadcast receivers, no boot receivers, and no content
|
||||
providers**. The only `WorkManager` job in the application is `LockUserWalletsTimer` — which
|
||||
*locks* wallets.
|
||||
|
||||
### 3.7 Telemetry and Personal Data — CLEAN (pseudonymised)
|
||||
|
||||
Analytics and marketing SDKs present: Firebase Analytics/Crashlytics, Amplitude, AppsFlyer,
|
||||
CustomerIO, SurveySparrow. This is conventional commercial telemetry, declared openly in the build
|
||||
configuration.
|
||||
|
||||
The user identifier transmitted to these services is **hashed, never raw**
|
||||
(`app/…/analytics/DefaultTrackingContextProxy.kt`):
|
||||
|
||||
```kotlin
|
||||
private fun calculateUserIdHash(userWalletId: UserWalletId?): String? {
|
||||
return userWalletId?.value
|
||||
?.calculateSha256()
|
||||
?.toHexString()
|
||||
}
|
||||
```
|
||||
|
||||
Every `setUserProperties` call site — cold wallet, hot wallet, and scan response — routes through
|
||||
this function. Accompanying properties are non-identifying product facts (`batchId`, `productType`,
|
||||
`firmwareVersion`).
|
||||
|
||||
No device-identifier harvesting was found in any analytics path: no `Settings.Secure.ANDROID_ID`,
|
||||
no IMEI, no MAC address, no subscriber ID.
|
||||
|
||||
### 3.8 Local Diagnostic Logging — CLEAN
|
||||
|
||||
`NetworkLogsSaveInterceptor` records HTTP traffic to a local `AppLogsStore`, supporting the in-app
|
||||
"contact support with logs" feature. The implementation shows care:
|
||||
|
||||
- URLs pass through `SensitiveUrlMasker`, replacing configured secrets with `******`. The masker
|
||||
sorts candidates by **descending length**, so a shorter value that is a prefix of a longer one
|
||||
cannot mask first and leave a partial secret exposed — a considered detail.
|
||||
- Sensitive endpoints are excluded from body logging entirely, via `restrictedForLogURLs`
|
||||
(`api.stakek.it/v1/yields/enabled`) and `restrictedForLogHosts` (`us.paera.com`).
|
||||
- Response bodies beyond ~2 MB are skipped; binary bodies are omitted.
|
||||
|
||||
**Egress is user-initiated only.** `DefaultFeedbackRepository` exposes `getLogFile()` /
|
||||
`getZipLogFile()` and passes the file to `EmailSender` as an attachment, opening the platform email
|
||||
intent. Logs are **never** uploaded automatically or silently. See Observation **O-1**.
|
||||
|
||||
### 3.9 Build System and Supply Chain — CLEAN
|
||||
|
||||
**Repositories** — all official, no typosquats or unexpected mirrors:
|
||||
|
||||
`gradlePluginPortal()` · `google()` (content-filtered to `androidx` / `com.android` / `com.google`)
|
||||
· `mavenCentral()` · `developer.huawei.com/repo` (official, for the Huawei flavour) ·
|
||||
`maven.pkg.github.com/tangem/*` (first-party)
|
||||
|
||||
`settings.gradle.kts` enforces:
|
||||
|
||||
```kotlin
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
```
|
||||
|
||||
This **prevents any individual module from silently introducing its own repository** — a
|
||||
meaningful supply-chain control, and one many projects omit.
|
||||
|
||||
**No build-time code execution or fetching.** All `*.gradle.kts` and `*.gradle` files were searched
|
||||
for `exec {`, `URL(`, `download`, `curl`, `wget`, and `HttpURLConnection`. **Zero results.** The
|
||||
build does not download or run anything beyond declared Maven dependencies.
|
||||
|
||||
**Gradle wrapper** — `distributionUrl` resolves to the official
|
||||
`https://services.gradle.org/distributions/gradle-8.14.1-bin.zip`.
|
||||
|
||||
```
|
||||
gradle-wrapper.jar SHA-256: 3dc39ad650d40f6c029bd8ff605c6d95865d657dbfdeacdb079db0ddfffedf9f
|
||||
Size: 55,616 bytes
|
||||
```
|
||||
|
||||
Verify this against the official Gradle 8.14.1 wrapper when reproducing the build.
|
||||
|
||||
**DexProtector.** The `com.dexprotector.rtc.RtcStatus` reference in
|
||||
`DefaultDeviceSecurityInfoProvider` is Licel's commercial application-hardening product, integrated
|
||||
for **runtime root, emulator, and tamper detection**. Its presence is a defensive control, not
|
||||
concealment: the mock build flavour transparently substitutes
|
||||
`MockAwareDeviceSecurityInfoProvider`, which reports a clean device.
|
||||
|
||||
### 3.10 Committed Credentials — CLEAN
|
||||
|
||||
`app/src/main/assets/tangem-app-config/config_prod.json` and `config_dev.json` declare the full key
|
||||
schema — Amplitude, AppsFlyer, Blockchair, BlockCypher, Infura, QuikNode, GetBlock, MoonPay,
|
||||
Mercuryo, NowNodes, TonCenter and others — with **every value set to the literal string
|
||||
`PLACEHOLDER`**. No live credentials are committed.
|
||||
|
||||
The only committed keystore is a dummy debug keystore:
|
||||
|
||||
```properties
|
||||
store_password=android
|
||||
key_alias=dummy
|
||||
key_password=android
|
||||
```
|
||||
|
||||
These are the well-known Android debug defaults. The keystore cannot sign a release build. See
|
||||
Observation **O-3**.
|
||||
|
||||
---
|
||||
|
||||
## 4. Expected False Positives
|
||||
|
||||
Two pattern classes in this repository will alarm automated scanners and reviewers working from
|
||||
grep output alone. Both are benign. They are documented here so that any subsequent review reaches
|
||||
the same conclusion without re-investigating.
|
||||
|
||||
### FP-1 — `loadDex*` is *Decentralised Exchange*, not Android DEX
|
||||
|
||||
A search for `loadDex` returns numerous hits across `features/swap/`:
|
||||
|
||||
```
|
||||
loadDexSwapData · loadDexSwapDataNoFee · loadDexSwapFee · DexSwapFeeCalculator · ResolvedFlow.DexLike
|
||||
```
|
||||
|
||||
**DEX** here means **D**ecentralised **EX**change — token-swap business logic. These functions load
|
||||
swap quotes and fee data from exchange providers. They have no relationship to Android DEX
|
||||
bytecode or class loading. Confirmed by reading `SwapInteractorImpl.kt` and the surrounding swap
|
||||
domain.
|
||||
|
||||
### FP-2 — Hostile hostnames are security *test fixtures*
|
||||
|
||||
The following appear as string literals in the tree:
|
||||
|
||||
```
|
||||
faketangem.com · fake.tangem.com · tangem.com.attacker.com
|
||||
buy.tangem.com.attacker.com · evil-spoofed.example · fake.surveysparrow.com
|
||||
```
|
||||
|
||||
Every one is a **negative test case** asserting `expected = false`, located in:
|
||||
|
||||
- `common/src/testDebug/…/uri/ExternalUrlValidatorTest.kt`
|
||||
- `data/wallet-connect/src/test/…/DefaultWcPairUseCaseTest.kt`
|
||||
|
||||
Their presence is **evidence of a deliberate anti-spoofing URL validator** and a WalletConnect
|
||||
proposal-spoofing defence, verified against realistic attack strings. These are security controls
|
||||
under test, not indicators of compromise.
|
||||
|
||||
---
|
||||
|
||||
## 5. Observations
|
||||
|
||||
Operational notes for anyone forking or deploying this application. **None is a vulnerability**,
|
||||
and none affects the verdict in §1.
|
||||
|
||||
### O-1 — Support logs are financially sensitive
|
||||
|
||||
When diagnostic logging is active, full JSON request and response bodies are written to local
|
||||
application storage. URLs are masked and specific hosts excluded (§3.8), but bodies may still
|
||||
contain wallet addresses, balances, and transaction details. The data never leaves the device
|
||||
unless the user deliberately emails it to support.
|
||||
|
||||
**Recommendation:** treat a user-submitted support-log attachment as sensitive financial data in
|
||||
your support process — restrict access, and set a retention limit.
|
||||
|
||||
### O-2 — Third-party telemetry ships enabled by default
|
||||
|
||||
Five analytics and marketing SDKs (Firebase, Amplitude, AppsFlyer, CustomerIO, SurveySparrow) and
|
||||
the `AD_ID` permission are present in the Google flavour. This is disclosed and the user identifier
|
||||
is pseudonymised (§3.7).
|
||||
|
||||
**Recommendation:** a privacy-focused fork may wish to remove Amplitude, AppsFlyer, CustomerIO, and
|
||||
SurveySparrow, and drop the `AD_ID` permission. The Huawei flavour already differs in SDK
|
||||
composition.
|
||||
|
||||
### O-3 — A clean checkout builds but does not fully function
|
||||
|
||||
Because all configuration values are `PLACEHOLDER` (§3.10) and only a dummy debug keystore is
|
||||
committed, a build from a clean checkout compiles but its third-party integrations — price quotes,
|
||||
buy/sell providers, and some RPC endpoints — will not operate until real API keys are supplied.
|
||||
Release signing requires a keystore that is deliberately not in the repository.
|
||||
|
||||
This is correct and expected practice for a public source release, not a defect.
|
||||
|
||||
---
|
||||
|
||||
## 6. Scope and Limitations
|
||||
|
||||
These boundaries are stated plainly so that no broader assurance is inferred than was actually
|
||||
obtained.
|
||||
|
||||
1. **First-party source only.** Tangem's own SDKs — `com.tangem:blockchain` (Blockchain SDK),
|
||||
`tangem-sdk-kotlin` (Card SDK), `tangem-hot-sdk-kotlin` (Hot Wallet SDK), `wallet-core`, `vico`,
|
||||
and `web3j` — are resolved as **pre-built binary artifacts** from GitHub Packages at build time
|
||||
and were **not** reviewed. This is a material limitation: the hot-wallet SDK performs the actual
|
||||
mnemonic encryption and at-rest storage. Assurance over those components requires a separate
|
||||
review of their own repositories.
|
||||
|
||||
2. **Third-party Maven dependencies were not individually reviewed**, although the repository set
|
||||
from which they are drawn is constrained and official (§3.9).
|
||||
|
||||
3. **No dynamic analysis was performed.** This is a static review. No APK was executed,
|
||||
instrumented, decompiled, or observed on a network. Runtime behaviour was inferred from source.
|
||||
|
||||
4. **No cryptographic correctness review.** This review establishes that key material is not
|
||||
*leaked*. It does not assess whether the encryption schemes protecting that material at rest are
|
||||
correctly chosen or parameterised.
|
||||
|
||||
5. **Commit provenance could not be verified.** The reviewed checkout carries squashed commit
|
||||
messages (`Updated on 2026-08-14`), so upstream authorship and per-change history were not
|
||||
available for inspection.
|
||||
|
||||
6. **Point-in-time.** Findings apply to commit `358144ee61a` only.
|
||||
|
||||
---
|
||||
|
||||
## 7. Conclusion
|
||||
|
||||
The reviewed source is **clean**. No malware, backdoor, dropper, exfiltration channel, or
|
||||
intentionally obfuscated logic was identified across ten categories of examination.
|
||||
|
||||
The codebase further exhibits positive security engineering that would be unusual in a trojanised
|
||||
or negligent application:
|
||||
|
||||
- JavaScript disabled in WebViews, with no JavaScript bridge present at all
|
||||
- Certificate validation fully intact; cleartext traffic disabled; user-installed CAs excluded
|
||||
- Location and microphone permissions actively stripped from third-party SDK manifests
|
||||
- Analytics identifiers SHA-256 hashed rather than transmitted raw
|
||||
- A dedicated external-URL anti-spoofing validator, tested against realistic attack strings
|
||||
- Tapjacking/overlay protection via `HIDE_OVERLAY_WINDOWS`
|
||||
- Seed-phrase export gated behind biometric or password authentication
|
||||
- Automatic wallet locking on an inactivity timer
|
||||
- `FAIL_ON_PROJECT_REPOS` constraining the build supply chain
|
||||
- Commercial runtime tamper and root detection
|
||||
|
||||
Subject to the scope boundaries in §6 — in particular the unreviewed binary SDKs — the application
|
||||
is assessed as safe to build and distribute from this source.
|
||||
|
||||
---
|
||||
|
||||
*Static source review of commit `358144ee61a`. Findings reflect that commit only; re-audit after
|
||||
merging upstream changes.*
|
||||
Loading…
Add table
Add a link
Reference in a new issue