Una URL de 70.000 caracteres puede congelar cualquier teléfono Android durante 10–16 segundos. No es corrupción de memoria. Es un ataque algorítmico que explota la complejidad O(n²) del motor de diseño de texto nativo de Android. Y lo peor: cualquier aplicación con un TextView es vulnerable.
He documentado 31 vectores en 9 empresas, incluyendo Google, Meta, Microsoft, Mozilla, Opera, DuckDuckGo, Brave, Tor Project y Xiaomi. El fallo reside en libminikin.so, el motor de diseño de texto de Android, y afecta a todos los dispositivos con Android 9 a 16.
1. El problema: Algoritmos que se vuelven en tu contra
libminikin.so implementa el algoritmo de salto de línea óptimo (Knuth-Plass) en la función LineBreakOptimizer::computeBreaks. Este algoritmo tiene complejidad O(n²) en el peor caso: si duplicas la longitud del texto, el tiempo de procesamiento se multiplica por cuatro.
Para un texto normal de 200 caracteres, el tiempo es imperceptible. Pero para una URL de 70.000 caracteres con la estructura adecuada, el algoritmo ejecuta millones de operaciones y bloquea el hilo de la interfaz durante más de 10 segundos.
#, /, % y € multiplica el número de "candidatos a salto de línea", y el algoritmo se dispara.
2. La estructura del ataque: Caracteres que multiplican el caos
| Carácter | Función en la URL | Efecto en libminikin |
|---|---|---|
# |
Fragmento (separador lógico) | Duplica las decisiones de salto de línea |
/ |
Separador de rutas | Cada barra es un punto de ruptura → O(n²) con el número de barras |
% |
Codificación porcentual | Expansión UTF-8 → UTF-16, fragmenta la cadena |
€ |
Carácter multibyte | Propiedades de salto de línea ambiguas → el algoritmo explora ambas opciones |
El patrón óptimo repite miles de veces. Cada 9 bytes generan múltiples puntos de decisión y el algoritmo explota.
3. Prueba de concepto mínima (20 líneas)
Esta aplicación de prueba no contiene código de navegador. Solo un TextView con el payload malicioso. El resultado es idéntico al de los navegadores:
Resultado: La UI se congela durante 10–16 segundos. El stack trace nativo confirma que libminikin es el único responsable.
4. Vectores de ataque: Más allá de los navegadores
El fallo no se limita a los navegadores. Cualquier aplicación que muestre texto en un TextView sin truncar es un vector de ataque:
| Componente / Aplicación | ¿Muestra URL larga? | Vulnerabilidad observada |
|---|---|---|
| Chrome (menú contextual) | Sí | ✅ ANR de 5+ segundos |
| Firefox (diálogo externo) | Sí | ✅ ANR de 16 segundos (enlace real de Gmail) |
| Opera / Opera Mini | Sí | ✅ Crash con TransactionTooLargeException |
| DuckDuckGo | Sí (historial) | ✅ Bucle de cierre permanente |
| Gmail (vista previa de enlace) | Sí | ⚠️ Potencial |
| WhatsApp (vista previa de enlace) | Sí | ⚠️ Potencial |
| Cualquier app con TextView | Sí | ✅ Confirmado con PoC de 20 líneas |
5. El vector crítico: STA-015-DL (SystemUI crash loop)
La cadena de ataque STA-015-DL demuestra que el problema trasciende las aplicaciones y afecta a SystemUI, la interfaz del sistema:
- La víctima hace clic en un archivo HTML alojado en Google Drive.
- Google Drive lanza un
Intent.ACTION_VIEWcon una URL malformada. - La URL bypasea todas las validaciones del navegador porque llega a través de
callingPackage=com.google.android.apps.docs(certificado por Android). - La URL corrompe el estado de
TaskPersisteren disco. - SystemUI intenta leer el estado →
DeadObjectException→ bucle de cierre. - Recuperación: reinicio forzado del dispositivo.
Evidencia de campo: Un dispositivo en producción (Xiaomi Redmi Note 14 5G, Android 16) registró 85 SystemUI crashes en 4 días, con un tiempo mínimo de supervivencia de 374ms.
6. Stack traces nativos (evidencia forense)
Chrome – Menú contextual (24 de mayo de 2026)
Firefox – Diálogo de aplicación externa (10 de junio de 2026)
7. Mitigación
7.1 A nivel de framework (Google/AOSP)
Google debería implementar un límite de entrada antes de ejecutar el algoritmo O(n²):
7.2 A nivel de aplicación (inmediato)
Los desarrolladores pueden truncar el texto antes de mostrarlo en un TextView:
8. Conclusión
La complejidad O(n²) en libminikin convierte una URL de 70 KB en un arma de denegación de servicio que congela cualquier Android que la muestre en un TextView sin truncar. No es corrupción de memoria, es explotación algorítmica — usar la propia complejidad del sistema en su contra.
Google ha empezado a moverse (LargePayloadSupport, savedstate 1.5.0), pero no hay parche público para libminikin a fecha de junio de 2026. La comunidad y los desarrolladores pueden aplicar mitigaciones inmediatas truncando el texto antes de mostrarlo.
El 30 de julio de 2026 publicaré el whitepaper completo con los 31 vectores documentados y la evidencia forense completa. Si tu aplicación usa TextView, ya estás avisado.
Investigador independiente · lostmon@gmail.com
Blog: lostmon.blogspot.com