{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreicw7snpo7uknk3tqsqaregtqwnzalfczkpcwrghvt45y2ld6qasce",
"uri": "at://did:plc:4n6wgsqsqm6q2hjncgwmreey/app.bsky.feed.post/3ml5qten2nph2"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreiec6boe234tj3kj2oqxhcrhktntgqg46tsbcpmrngbfmexhdabexm"
},
"mimeType": "image/png",
"size": 41272
},
"path": "/post/49905276",
"publishedAt": "2026-05-05T15:51:15.000Z",
"site": "https://programming.dev",
"tags": [
"Privacy",
"InternetCitizen2",
"5 comments",
"https://thereallo.dev/blog/decompiling-the-white-house-app",
"www.ice.gov/webform/ice-tip-form",
"androidheadlines.com/…/a-security-researcher-deco…"
],
"textContent": "submitted by InternetCitizen2 to privacy\n13 points | 5 comments\nhttps://thereallo.dev/blog/decompiling-the-white-house-app\n\nEdit: Updated as I found the researchers blog.\n\n* * *\n\nThe White House released an app on the App Store and Google Play. They posted a blog about it. “Unparalleled access to the Trump Administration.”\n\nIt took a few minutes to pull the APKs with ADB, and threw them into JADX.\n\nHere is everything I found.\n\nIt’s a React Native app built with Expo (SDK 54), running on the Hermes JavaScript engine. The backend is WordPress with a custom REST API. The app was built by an entity called “forty-five-press” according to the Expo config.\n\nThe actual app logic is compiled into a 5.5 MB Hermes bytecode bundle. The native Java side is just a thin wrapper.\n\nVersion 47.0.1. Build 20. Hermes enabled. New Architecture enabled. Nothing weird here. Let’s keep going.\n\nTwo things stand out here. First, there’s a plugin called withNoLocation. Second, there’s a plugin called withStripPermissions. Remember these. They become relevant very soon.\n\nOTA updates are disabled. The Expo update infrastructure is compiled in but dormant.\n\nI extracted every string from the Hermes bytecode bundle and filtered for URLs and API endpoints. The app’s content comes from a WordPress REST API at whitehouse.gov with a custom whitehouse/v1 namespace.\n\nHere are the endpoints: Endpoint What It Serves /wp-json/whitehouse/v1/home Home screen /wp-json/whitehouse/v1/news/articles News articles /wp-json/whitehouse/v1/wire “The Wire” news feed /wp-json/whitehouse/v1/live Live streams /wp-json/whitehouse/v1/galleries Photo galleries /wp-json/whitehouse/v1/issues Policy issues /wp-json/whitehouse/v1/priorities Priorities /wp-json/whitehouse/v1/achievements Achievements /wp-json/whitehouse/v1/affordability Drug pricing /wp-json/whitehouse/v1/media-bias “Media Bias” section /wp-json/whitehouse/v1/social/x X/Twitter feed proxy\n\nOther hardcoded strings from the bundle: “THE TRUMP EFFECT”, “Greatest President Ever!” (lol), “Text President Trump”, “Send a text message to President Trump at 45470”, “Visit TrumpRx.gov”, “Visit TrumpAccounts.gov”.\n\nThere’s also a direct link to www.ice.gov/webform/ice-tip-form. The ICE tip reporting form. In a news app.\n\nIt’s a content portal. News, live streams, galleries, policy pages, social media embeds, and promotional material for administration initiatives. All powered by WordPress.\n\nNow let’s look at what else it does.\n\nThe app has a WebView for opening external links. Every time a page loads in this WebView, the app injects a JavaScript snippet. I found it in the Hermes bytecode string table:\n\nRead that carefully. It hides:\n\n\n Cookie banners\n GDPR consent dialogs\n OneTrust popups\n Privacy banners\n Login walls\n Signup walls\n Upsell prompts\n Paywall elements\n CMP (Consent Management Platform) boxes\n\n\nIt forces body { overflow: auto !important } to re-enable scrolling on pages where consent dialogs lock the scroll. Then it sets up a MutationObserver to continuously nuke any consent elements that get dynamically added.\n\nAn official United States government app is injecting CSS and JavaScript into third-party websites to strip away their cookie consent dialogs, GDPR banners, login gates, and paywalls.\n\nThe native side confirms this is the injectedJavaScript prop on the React Native WebView:\n\nEvery page load in the in-app browser triggers this. It wraps the injection in an IIFE and runs it via Android’s evaluateJavascript().\n\nRemember withNoLocation from the Expo config? The plugin that’s supposed to strip location? Yeah. The OneSignal SDK’s native location tracking code is fully compiled into the APK.\n\n270,000 milliseconds is 4.5 minutes. 570,000 is 9.5 minutes.\n\nTo be clear about what activates this: the tracking doesn’t start silently. There are three gates. The LocationManager checks all of them before the fused location API ever fires.\n\nFirst, the _isShared flag. It’s read from SharedPreferences on init and defaults to false. The JavaScript layer can flip it on with setLocationShared(true). The Hermes string table confirms both setLocationShared and isLocationShared are referenced in the app’s JS bundle, so the app has the ability to toggle this.\n\nSecond, the user has to grant the Android runtime location permission. The location permissions aren’t declared in the AndroidManifest but requested at runtime. The Google Play Store listing confirms the app asks for “access precise location only in the foreground” and “access approximate location only in the foreground.”\n\nThird, the start() method only proceeds if the device actually has a location provider (GMS or HMS).\n\nIf all three gates pass, here’s what runs. The fused location API requests GPS at the intervals defined above:\n\nThis gets called on both onFocus() and onUnfocused(), dynamically switching between the 4.5-minute foreground interval and the 9.5-minute background interval.\n\nWhen a location update comes in, it feeds into the LocationCapturer:\n\nLatitude, longitude, accuracy, timestamp, whether the app was in the foreground or background, and whether it was fine (GPS) or coarse (network). All of it gets written into OneSignal’s PropertiesModel, which syncs to their backend.\n\nThe data goes here:\n\nThere’s also a background service that keeps capturing location even when the app isn’t active:\n\nSo the tracking isn’t unconditionally active. But the entire pipeline including permission strings, interval constants, fused location requests, capture logic, background scheduling, and the sync to OneSignal’s API, all of them are fully compiled in and one setLocationShared(true) call away from activating. The withNoLocation Expo plugin clearly did not strip any of this. Whether the JS layer currently calls setLocationShared(true) is something I can’t determine from the native side alone, since the Hermes bytecode is compiled and the actual call site is buried in the 5.5 MB bundle. What I can say is that the infrastructure is there, ready to go, and the JS API to enable it is referenced in the bundle.\n\nOneSignal is doing a lot more than push notifications in this app. From the Hermes string table:\n\n\n addTag - tag users for segmentation\n addSms - associate phone numbers with user profiles\n addAliases - cross-device user identification\n addOutcomeWithValue / addUniqueOutcome - track user actions and conversions\n OneSignal-notificationClicked - notification tap tracking\n OneSignal-inAppMessageClicked / WillDisplay / DidDisplay / WillDismiss / DidDismiss - full in-app message lifecycle tracking\n OneSignal-permissionChanged / subscriptionChanged / userStateChanged - state change tracking\n setLocationShared / isLocationShared - location toggle\n setPrivacyConsentRequired / setPrivacyConsentGiven - consent gating\n\n\nThe local database tracks every notification received and whether it was opened or dismissed:\n\nYour location, your notification interactions, your in-app message clicks, your phone number if you provide it, your tags, your state changes. All going to OneSignal’s servers.\n\nThe app embeds YouTube videos using the react-native-youtube-iframe library. This library loads its player HTML from:\n\nThat’s a personal GitHub Pages site. If the lonelycpp GitHub account gets compromised, whoever controls it can serve arbitrary HTML and JavaScript to every user of this app, executing inside the WebView context.\n\nThis is a government app loading code from a random person’s GitHub Pages.\n\nThe app loads third-party JavaScript from Elfsight to embed social media feeds:\n\nElfsight is a commercial SaaS widget company. Their JavaScript runs inside the app’s WebView with no sandboxing. Whatever tracking Elfsight does, it does it here too. Their code can change at any time. The Elfsight widget ID 4a00611b-befa-466e-bab2-6e824a0a98a9 is hardcoded in an HTML embed.\n\n\n Mailchimp at whitehouse.us10.list-manage.com/subscribe/post-json handles email signups. User emails go to Mailchimp's infrastructure.\n Uploadcare at ucarecdn.com hosts content images via six hardcoded UUIDs.\n Truth Social has a hardcoded HTML embed with Trump's profile, avatar image URL from static-assets-1.truthsocial.com, and a \"Follow on Truth Social\" button.\n Facebook page plugin is loaded in an iframe via facebook.com/plugins/page.php.\n\n\nNone of these are government-controlled infrastructure.\n\nThe app uses standard Android TrustManager for SSL with no custom certificate pinning. If you’re on a network with a compromised CA (corporate proxies, public wifi with MITM, etc.), traffic between the app and its backends can be intercepted and read.\n\nThe build has some sloppy leftovers.\n\nA localhost URL made it into the production Hermes bundle:\n\nThat’s the React Native Metro bundler dev server.\n\nA developer’s local IP is hardcoded in the string resources:\n\nThe Expo development client (expo-dev-client, expo-devlauncher, expo-devmenu) is compiled into the release build. There’s a dev_menu_fab_icon.png in the drawable resources. The Compose PreviewActivity is exported in the manifest, which is a development-only component that should not be in a production APK.\n\nThe AndroidManifest itself is pretty standard for a notification-heavy app:\n\nPlus about 16 badge permissions for Samsung, HTC, Sony, Huawei, OPPO, and other launchers. These just let the app show notification badge counts. Not interesting.\n\nThe interesting permissions are the ones that aren’t in the manifest but are hardcoded as runtime request strings in the OneSignal SDK, as covered above. Fine location. Coarse location. Background location.\n\nThe Google Play listing also mentions: “modify or delete the contents of your shared storage”, “run foreground service”, “this app can appear on top of other apps”, “run at startup”, “use fingerprint hardware”, “use biometric hardware.”\n\nThe file provider config is also worth mentioning:\n\nThat exposes the entire external storage root. It’s used by the WebView for file access.\n\n68+ libraries are compiled into this thing. The highlights: Category Libraries Framework React Native, Expo SDK 54, Hermes JS engine Push/Engagement OneSignal, Firebase Cloud Messaging, Firebase Installations Analytics/Telemetry Firebase Analytics, Google Data Transport, OpenTelemetry Networking OkHttp 3, Apollo GraphQL, Okio Images Fresco, Glide, Coil 3, Uploadcare CDN Video ExoPlayer (Media3), Expo Video ML Google ML Kit Vision (barcode scanning), Barhopper model Crypto Bouncy Castle Storage Expo Secure Store, React Native Async Storage WebView React Native WebView (with the injection script) DI Koin Serialization GSON, Wire (Protocol Buffers) License PairIP license check (Google Play verification)\n\n25 native .so libraries in the arm64 split. The full Hermes engine, React Native core, Reanimated, gesture handler, SVG renderer, image pipeline, barcode scanner, and more.\n\nThe official White House Android app:\n\n\n Injects JavaScript into every website you open through its in-app browser to hide cookie consent dialogs, GDPR banners, login walls, signup walls, upsell prompts, and paywalls.\n\n Has a full GPS tracking pipeline compiled in that polls every 4.5 minutes in the foreground and 9.5 minutes in the background, syncing lat/lng/accuracy/timestamp to OneSignal's servers.\n\n Loads JavaScript from a random person's GitHub Pages site (lonelycpp.github.io) for YouTube embeds. If that account is compromised, arbitrary code runs in the app's WebView.\n\n Loads third-party JavaScript from Elfsight (elfsightcdn.com/platform.js) for social media widgets, with no sandboxing.\n\n Sends email addresses to Mailchimp, images are served from Uploadcare, and a Truth Social embed is hardcoded with static CDN URLs. None of this is government infrastructure.\n\n Has no certificate pinning. Standard Android trust management.\n\n\nShips with dev artifacts in production. A localhost URL, a developer IP (10.4.4.109), the Expo dev client, and an exported Compose PreviewActivity.\n\n\n Profiles users extensively through OneSignal - tags, SMS numbers, cross-device aliases, outcome tracking, notification interaction logging, in-app message click tracking, and full user state observation.\n\n\nIs any of this illegal? Probably not. Is it what you’d expect from an official government app? Probably not either.\n\n* * *\n\n## Normie TLDR\n\nandroidheadlines.com/…/a-security-researcher-deco…\n\nRecently, The White House launched its own official app on iOS and Android, claiming that it gives users “unparalleled access to the Trump Administration”. After it launched, many tore it apart for the permissions it was asking for. Now, a security researcher pulled the APK and tore it apart to see what’s really going on.\n\nThe app is a React Native build using Expo SDK 54, with WordPress powering the backend through a custom REST API. That’s pretty normal, as nearly 42% of all websites on the internet are powered by WordPress.\n\nBut that’s just the start; now the nightmare begins. To start, the app has a full GPS tracking pipeline compiled in. Essentially, it’s set to poll your location every 4.5 minutes in the foreground, and 9.5 minutes in the background. It’s syncing latitude, longitude, accuracy, and timestamp data to OneSignal’s servers. These location permissions aren’t declared in the AndroidManifest, but they are hardcoded as runtime requests in the OneSignal SDK. Some have noted that the tracking only kicks in if the developer enables it server-side and the user grants permission, but it is there, ready to go. The app is loading from a random person’s GitHub page\n\nAnd it gets even stranger. Apparently, the app is loading JavaScript from a random person’s GitHub site for YouTube embeds. Yes, you read that right, it’s just loading JavaScript from a random GitHub site. So if that account ever gets compromised, arbitrary code could run inside the app’s WebView.\n\nThere’s also no SSL certificate pinning, meaning that traffic can potentially be intercepted on compromised networks like sketchy public WiFi or corporate proxies.\n\nThe app also injects JavaScript and CSS into every page you visit in the in-app browser. This strips away cookie consent dialogs, GDPR banners, login walls, and paywalls. There’s also leftover dev artifacts in the production build, including a localhost URL to the Metro bundler.\n\nTo put it plainly, this app is a security nightmare, and no one should have installed it, no matter what your political beliefs are.",
"title": "A Security Researcher Decompiled The White House App"
}