PWA / TWA (Progressive Web Apps / Trusted Web Activities)¶
Progressive Web Apps (PWAs) wrapped as Trusted Web Activities (TWAs) are web applications packaged inside a minimal Android APK shell. The APK contains almost no native code -- it exists solely to launch Chrome Custom Tabs pointed at a web origin. All application logic, UI, and data handling live on a remote web server, not inside the APK. This makes the reverse engineering target the web application itself rather than the Android package. TWAs use Android's Digital Asset Links protocol to verify that the APK publisher controls the target web domain.
Architecture¶
PWA Fundamentals¶
A Progressive Web App is a web application that uses modern browser APIs to provide app-like capabilities:
| Component | Role |
|---|---|
| Service Worker | JavaScript proxy between the app and network -- handles caching, offline support, push notifications |
| Web App Manifest | JSON file (manifest.json) defining app name, icons, start URL, display mode |
| HTTPS Origin | All PWA features require a secure origin |
| Application Shell | Cached HTML/CSS/JS skeleton that loads instantly, then hydrates with dynamic content |
TWA Wrapper¶
A Trusted Web Activity is an Android activity that launches a Chrome Custom Tab in full-screen mode (no browser chrome) to display a PWA. On launch, the APK's LauncherActivity delegates to Chrome Custom Tabs, which verifies the Digital Asset Links relationship between the APK and the target domain. If verification passes, Chrome renders the PWA full-screen with no browser UI. If verification fails, Chrome shows the URL bar as a fallback.
Key Distinction from WebView Apps¶
TWAs are fundamentally different from WebView-based frameworks (Cordova, Capacitor, uni-app):
| Aspect | TWA | WebView Framework |
|---|---|---|
| Rendering engine | System Chrome (always up to date) | Embedded WebView (varies by OS version) |
| Code location | Remote server | Bundled in APK (assets/www/) |
| Offline capability | Service Worker cache (optional) | Full offline by default |
| Native bridge | None -- browser sandbox only | JavaScript bridge to native APIs |
| APK size | Tiny (< 1 MB typically) | Larger (includes web assets + native plugins) |
Identification¶
| Indicator | Location |
|---|---|
| Very small APK size (< 2 MB) | Overall package |
com.google.androidbrowserhelper |
DEX classes -- Google's TWA support library |
LauncherActivity or TWALauncherActivity |
Main activity in manifest |
androidx.browser.trusted.* |
Trusted Web Activity classes |
asset_statements string resource |
Digital Asset Links declaration |
No assets/www/ or bundled web code |
Absence of local web content |
org.chromium.chrome.browser.browserservices |
Chrome TWA service references |
META-INF/services/ with Chrome entries |
Service provider configuration |
Quick check:
unzip -l target.apk | wc -l
aapt dump xmltree target.apk AndroidManifest.xml | grep -iE "(launcher|twa|browser|customtab)"
A TWA APK typically has fewer than 100 files. Compare this to a Cordova app which may have thousands.
Bubblewrap Detection¶
Most TWAs are built using Bubblewrap, Google's CLI tool for generating TWA wrapper APKs. Bubblewrap-generated APKs have a predictable structure:
Code Location¶
What Is in the APK¶
The APK contains only:
AndroidManifest.xml-- activity declarations, Digital Asset Links references- Thin Java/Kotlin launcher code (delegate to Chrome)
- App icons and splash screen resources
res/values/strings.xml-- may contain the target URL- Digital Asset Links configuration
Extracting the Target URL¶
All application logic (HTML, JavaScript, CSS, Service Workers) resides on the remote server. The only useful artifact in the APK is the target URL.
The target web origin is the critical piece of information in the APK:
From decompiled Java (jadx):
The URL is typically stored in res/values/strings.xml or hardcoded in LauncherActivity.
Digital Asset Links¶
The APK references a /.well-known/assetlinks.json file hosted on the target domain. This JSON file proves the domain owner authorized the APK:
The response contains the APK's package name and signing certificate fingerprint:
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.twa",
"sha256_cert_fingerprints": ["AB:CD:EF:..."]
}
}]
Analysis Approach¶
Web-Focused Analysis¶
Since the code lives on the server, standard web application analysis techniques apply:
| Technique | Tool | Purpose |
|---|---|---|
| Browser DevTools | Chrome/Firefox | Inspect DOM, network requests, service worker, local storage |
| Proxy interception | mitmproxy, Burp Suite | Capture and modify HTTP/S traffic |
| Service Worker analysis | Chrome DevTools (Application tab) | Examine caching strategy, push notification handlers |
| JavaScript analysis | Browser DevTools Sources | Read, debug, and breakpoint application code |
| API enumeration | Burp Suite, Postman | Map backend endpoints discovered through traffic analysis |
Proxy Setup for TWA¶
Intercept TWA traffic by configuring a system-wide proxy on the Android device and installing the proxy CA certificate:
Service Worker and Cache Extraction¶
Service Workers are cached by Chrome on the device. Access them through Chrome DevTools remote debugging:
Then navigate to chrome://inspect on the desktop browser. On a rooted device, Chrome's cache directories under /data/data/com.android.chrome/app_chrome/Default/Service Worker/CacheStorage/ contain cached responses and service worker scripts.
Security Implications¶
Origin Verification Bypass¶
The TWA trust model depends on Digital Asset Links verification. If an attacker can:
- Register a domain and host
assetlinks.jsonpointing to their APK - Build a TWA targeting that domain
- Later modify the web content to be malicious
The APK signature verification only proves the APK publisher owns the domain -- it says nothing about the safety of the web content. The web application can change at any time without updating the APK.
No Native Bridge¶
TWAs run inside Chrome's sandbox with no JavaScript bridge to native Android APIs. The PWA is limited to browser-granted capabilities: camera/microphone (via permissions prompt), GPS (Geolocation API), push notifications (Push API), local storage (IndexedDB), and same-origin network requests. No access to contacts, SMS, call logs, or file system beyond browser sandbox.
Phishing Surface¶
TWAs are effective phishing vectors because the thin APK passes static analysis (no malicious native code), web content can change after app store review, full-screen mode hides the URL bar making origin verification impossible for the user, and the app icon/splash screen mimic legitimate applications.
Hooking Strategy¶
Limited Native Hooks¶
The TWA APK contains minimal code, so Frida hook surface is small:
Java.perform(function() {
var Builder = Java.use("androidx.browser.customtabs.CustomTabsIntent$Builder");
Builder.build.implementation = function() {
console.log("[TWA] CustomTabsIntent built");
return this.build();
};
});
Network-Level Interception¶
Proxy-based interception is the most effective approach. Use mitmproxy or Burp Suite with iptables on a rooted device to force traffic through the proxy:
adb shell iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to-destination 192.168.1.100:8080
adb shell iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination 192.168.1.100:8080
SSL Pinning¶
TWAs inherit Chrome's certificate handling. Chrome does not support user-installed CA certificates for HTTPS interception by default on Android 7+. Options:
| Method | Requirement |
|---|---|
| System CA installation | Root access to place cert in /system/etc/security/cacerts/ |
| Magisk module | MagiskTrustUserCerts moves user certs to system store |
| Patched Chrome | Use a Chromium build with certificate verification disabled |
| Network Security Config | Not applicable -- TWA uses Chrome, not a WebView you control |
Malware Context¶
TWAs are used in phishing and scam campaigns where the threat actor wants:
| Use Case | Details |
|---|---|
| Phishing | Full-screen app mimicking banking/payment sites, no visible URL bar to alert the user |
| Scam storefronts | Fake e-commerce sites wrapped as apps, content changes post-review |
| Credential harvesting | Login forms that POST to attacker-controlled servers |
| Dynamic payload | APK passes store review with benign content, switches to malicious web content later |
The thin APK passes most static analysis tools because there is no malicious code in the package. All malicious behavior exists on the remote server and can be toggled at will.
RE Difficulty Assessment¶
| Aspect | Assessment |
|---|---|
| APK analysis | Trivial -- minimal code, extract target URL |
| Web code access | Depends on server -- visible via DevTools and proxy |
| String extraction | N/A -- no code in APK to extract strings from |
| Dynamic analysis | Standard web security testing |
| Patching | Not applicable -- code is server-side |
| Overall difficulty | Easy for APK, Variable for web application (rank 4/28) |
The APK is trivial to analyze -- extract the target URL and shift to standard web application penetration testing (OWASP Testing Guide). The difficulty depends entirely on the server-side web application.