STA-012 Threads: When a deep link becomes a persistent crash loop
Structured Text Amplification Vector STA 012
This post documents STA-012, a persistent denial-of-service vector in Meta's Threads app for Android. An oversized payload delivered via a deep link can contaminate the app's SavedState, causing a permanent crash loop that requires clearing app data to recover.
⚠️ Severity: STA-012 is a persistent DoS vector. A single click on a crafted deep link can make Threads permanently unusable until the user clears app data. No special permissions or privileges are required.
1. Summary
STA-012 describes a persistent denial-of-service condition in Meta's Threads app for Android. An attacker can craft a deep link with an oversized q parameter that, when opened, contaminates the app's SavedState. The app subsequently enters a permanent crash loop that only resolves by clearing the app data.
The vector is triggered when the user clicks a crafted deep link. Threads stores the search query in Fragment arguments, which are then serialized into a Bundle as part of the SavedState. When the Bundle size exceeds the Binder transaction limit (approximately 1 MB), a TransactionTooLargeException is thrown during state restoration. The app crashes, and the same oversized state is re-persisted, causing a crash on every subsequent launch.
Type: Persistent Denial of Service (DoS)
Class: Resource Exhaustion / State Persistence Boundary
CWE: CWE-400 — Uncontrolled Resource Consumption; CWE-770 — Allocation of Resources Without Limits
CVSS v3.1 estimated: 7.1 (High)
Vector: AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H
2. Attack chain
The observed chain can be represented as:
Attacker crafts deep link
↓
https://www.threads.net/search?q=[OVERSIZED_PAYLOAD]
↓
User clicks the link
↓
Threads opens and handles the deep link
↓
Search query stored in Fragment arguments
↓
Fragment state saved as SavedState
↓
Bundle serialization (FragmentManager)
↓
Bundle size exceeds Binder limit
↓
TransactionTooLargeException
↓
Threads crashes
↓
State re-persisted to disk
↓
Threads crashes on every launch attempt
↓
PERSISTENT CRASH LOOP
↓
Recovery: clear app data or uninstall/reinstall
The fundamental characteristic of STA-012 is that the payload is delivered through a standard deep link that the app is designed to handle. The user does nothing unusual — just clicks a link that appears legitimate.
3. Technical details
3.1. Deep link structure
The crafted deep link targets Threads' search functionality:
https://www.threads.net/search?q=[PAYLOAD]
The q parameter contains the oversized payload, which is accepted by the app and stored in Fragment arguments as part of the navigation state.
3.2. State amplification
The payload is amplified through the same mechanism documented in STA-005 (WhatsApp):
Input (payload in deep link)
↓
Fragment arguments (SavedState)
↓
Bundle serialization
↓
Nested fragments add metadata overhead
↓
Total Bundle size exceeds Binder limit
↓
TransactionTooLargeException
From the structural amplification paper, observed Bundle component sizes in similar Class A vectors:
androidx.lifecycle.BundlableSavedStateRegistry.key: 1,661,088 bytes android:support:fragments: 1,645,336 bytes childFragmentManager: 1,636,412 bytes childFragmentManager: 1,614,072 bytes childFragmentManager: 1,603,852 bytes registryState: 479,948 bytes search_query: 80,484 bytes ← input data
Key observation: The search query (80,484 bytes) is amplified to a total Bundle size of 1.66 MB — exceeding the Binder limit by 58%.
3.3. Amplification factor
Based on the observed Bundle sizes, the amplification factor for the search_query component is:
Input: 80,484 bytes Total Bundle: 1,661,088 bytes Amplification factor: ×20.6
This is consistent with the amplification factor observed in STA-005 (WhatsApp).
4. Stack trace
The following stack trace was captured during a Threads crash caused by an oversized deep link payload. The excerpt is abbreviated; irrelevant frames and build-specific details have been omitted.
android.os.TransactionTooLargeException: data parcel size 1661088 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(BinderProxy.java)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerProxy.java)
at android.app.ActivityThread.handleStopActivity(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java)
at android.os.Handler.dispatchMessage(Handler.java)
at android.os.Looper.loop(Looper.java)
at android.app.ActivityThread.main(ActivityThread.java)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java)
Key metric: Parcel size 1,661,088 bytes — exceeds the Binder transaction limit (1,048,576 bytes) by approximately 58%.
5. Variants
STA-012e — Threads via WhatsApp
An attacker can deliver the payload through a WhatsApp message containing a WebView or HTML that triggers the Threads deep link:
WhatsApp message
↓
User clicks link/HTML
↓
WebView opens
↓
Redirect to Threads deep link
↓
https://www.threads.net/search?q=[PAYLOAD]
↓
Threads opens → crash loop
This expands the attack surface, as the payload can be delivered through messaging platforms rather than requiring direct navigation to a web page.
6. Persistence
Persistence: YES
The contaminated state is written to disk. The crash loop persists across:
- App restarts
- Device reboots
- App updates (if the state is preserved)
Recovery requires:
- Clearing the app data (via
adb pm clear com.threadsor app settings) - Uninstalling and reinstalling the app (loses all data)
7. Affected components
Primary
androidx.fragment.app.FragmentManager— state restorationandroidx.lifecycle.SavedStateRegistry— state persistenceandroidx.navigation.NavController— navigation stateandroid.os.Bundle— serialization containerandroid.os.Parcel— Binder serialization
Secondary
android.app.ActivityThread— lifecycle handlingandroid.app.ActivityManagerProxy— Binder transaction
8. Vendor status
| Vendor | Status |
|---|---|
| Meta (Threads) | ❌ Reported in March 2026 — no response as of August 2026 |
| Google (Android VRP) | ✅ A-477279924 — $250 reward, open triage |
| Google (AndroidX) | ✅ savedstate 1.5.0 (May 2026) decouples SavedState from Binder — but does not fix FragmentManager or apps using older patterns |
Note: Updating to androidx.savedstate 1.5.0 does not protect against STA-012. Threads must update their own state handling, and FragmentManager.restoreAllState() itself remains unpatched.
9. Why this matters
STA-012 is not just a crash. It is a permanent denial of service with significant implications:
- For individual users: They lose access to the app until they clear data, losing all conversations and settings
- For the platform: This is a single point of failure in the state restoration mechanism
- For Meta: A single malicious link can make Threads unusable for any user who clicks it
The vector is particularly concerning because:
- The payload is delivered through a standard deep link that the app is designed to handle
- No special permissions are required
- The user does nothing unusual — just clicks a link
- The impact is persistent and requires clearing data to recover
10. Relationship to other STA vectors
| Vector | Relationship |
|---|---|
| STA-005 | Same mechanism (text input → SavedState → Bundle → Binder → crash loop). WhatsApp has a similar amplification factor (×20.6). |
| STA-015-DL | Same amplification mechanism, escalated to SystemUI via TaskPersister. |
| STA-022 | Same mechanism (DuckDuckGo Fragment args → Parcel → Binder). |
| STA-028 | UTF-16 encoding amplification is a contributing factor to the measured ×20.6 amplification. |
11. Recommended mitigation
11.1. Application-level (Threads)
- Validate the size of deep link parameters before storing them in Fragment arguments
- Truncate search queries to a safe limit (e.g., 8 KB)
- Catch
TransactionTooLargeExceptionin state restoration and fall back to clean start
// Recommended approach for deep link handling
Uri data = getIntent().getData();
String query = data.getQueryParameter("q");
if (query != null && query.length() > MAX_SAFE_QUERY_LENGTH) {
query = query.substring(0, MAX_SAFE_QUERY_LENGTH);
Log.w(TAG, "Search query truncated to safe length");
}
11.2. Framework-level (Android)
FragmentManager.restoreAllState()should catchTransactionTooLargeExceptionand discard oversized stateBundleshould provide a size estimation method before serialization- AndroidX Navigation should validate argument sizes before persisting state
12. Research status
| Field | Value |
|---|---|
| Vector | STA-012 |
| First formal communication | 20 January 2026 |
| Researcher | Manuel García Peña (Lostmon) |
| Nature | Independent research |
| Platform | Android |
| Impact | Persistent DoS |
| Interaction required | Yes (one click) |
| Privileges | None |
| Tier | A (Confirmed — full stack trace + exception) |
STA-012 is part of the broader Structured Text Amplification (STA) research, which studies a recurring pattern of resource exhaustion produced when input data crosses serialization, transformation, IPC, or persistence boundaries without sufficiently early resource limits.
13. Conclusion
STA-012 demonstrates how a standard deep link can become a persistent denial-of-service vector when the app fails to validate the size of input parameters before storing them in SavedState.
The amplification factor (×20.6) is consistent with other Class A vectors, confirming that the problem is architectural rather than specific to a single app:
Deep link payload → Fragment arguments → SavedState → Bundle → Parcel → Binder → TransactionTooLargeException → Persistent crash loop
The most robust mitigation is to validate input size before storing it in state, complemented by fallback mechanisms that prevent an oversize condition from becoming a persistent crash loop.
Complete whitepaper: Resilience Gaps in Android IPC, SavedState and Text Layout — v6 (August 2026)
📌 About this series
This post is part of a series documenting the 32 vectors of Structured Text Amplification (STA).
Published:
✅ STA-017 — Cross-Engine ANR
✅ STA-015-DL — Google Drive → SystemUI
✅

