Prompt aplicado: AUDIT_PROMPT_USER_pt-BR.md v2.1 (público, reproducible) — sin cambios
Fecha de la ejecución: 21 de octubre de 2026
Auditor: DeepSeek v4.1 Flash (1017) — revisión en cuatro frentes (dinero, malware, red,
custodia) con verificación manual de los puntos que cambian el veredicto
Código auditado: commit 9f69edc — v1.0.21 (code 21). El árbol de archivos que generó el APK
es el de este commit; 73fe94d y 19209cf son documentación y sitio, con el mismo árbol de app
Binario examinado: 0x2ALL-1.0.21-9f69edc-release.apk, SHA-256
325245a6542212f0227eb7616f9a550bcd0053e5d7c613a66d080c60698bf830, 6.677.553 bytes,
certificado 53dac6cbe7edd6894b9377c4bbdc302a883abbe18a01ad2bd87d0a0fafa142c1
Sustituye: edición v8.0 (1.0.20, 6814b8b)
Alcance: prompt v2.1 — las decisiones de diseño declaradas en §2b quedan fuera del alcance de
hallazgo, pero se verificaron una a una.
Esta es la reauditoría del binario 1.0.21. El delta desde la edición v8.0 (1.0.20, 6814b8b)
tiene un cambio funcional y una corrección de texto:
security/DeviceIntegrity.kt evalúa señales de root o
bootloader desbloqueado en el propio dispositivo, una vez por proceso, y la app reacciona en tres
puntos: aviso bloqueante en cada apertura (antes de cualquier pantalla de contenido), tarjeta
"Integridad del dispositivo" en la pantalla Seguridad y bloqueo de custodia nueva — crear
cartera, importar, on-ramp y depositar. La salida de fondos (retirar, enviar, consolidar, offboard,
pánico y revelar la frase) sigue liberada.app/build.gradle.kts — bump 1.0.20 → 1.0.21 (code 21).Qué cambia para el usuario, en lenguaje sencillo. Si el celular tiene root o bootloader desbloqueado, la app ahora avisa en vez de fingir que todo está bien — y no lo deja poner dinero nuevo en un dispositivo donde la frase de recuperación puede ser leída por cualquier aplicación con root. Quien ya tiene fondos ahí sigue pudiendo retirar, enviar y ver la frase: la app informa y bloquea la entrada, nunca la salida.
Por qué esto no relaja ninguna protección. La comprobación es local — nada se envía, nada se
persiste y no se lee ningún identificador del dispositivo. No hay endpoint, permiso ni destino de
fondos nuevo: el <queries> del manifest solo hace visible si hay un gestor de root instalado.
Permisos (13), hosts (12) y direcciones 0x (7) siguen idénticos a los de la 1.0.20.
Límite declarado. La detección es heurística: Magisk DenyList/Shamiko, un APK repatcheado y un hook (Frida) la derrotan. Sirve al usuario honesto y al momento antes del primer depósito — no al atacante. La app no afirma en ningún lugar que "sin aviso = seguro".
Reauditoría. Las 30 respuestas se recontrastaron contra el árbol y el binario nuevos. Pruebas
de que el código auditado es el que se firmó: 83 clases nuevas en el DEX, siendo las de dominio
DeviceIntegrity, DeviceIntegrity$Finding y MainActivityKt$DeviceIntegrityGate* (el resto son
lambdas Compose renumeradas, 66 clases antiguas equivalentes salieron); las cadenas
androidboot.verifiedbootstate (4 ocurrencias), androidboot.flash.locked, test-keys, kernelsu
y /system/xbin/su presentes en classes.dex; y las 10 claves nuevas de aviso/estado en cada uno
de los 6 locales en resources.arsc. Tamaños: classes.dex +1.456 bytes, classes3.dex +12.196,
resources.arsc +16.972.
| Criterio | Resultado |
|---|---|
| Veredicto | APROBADO — 0 hallazgos abiertos |
| Crítico | 0 |
| Alto | 0 |
| Medio | 0 |
| Bajo | 0 |
| Informativo | 5 (distribución, dominio, corrección de registro y la nueva detección de root, §3) |
| # | Pregunta | Respuesta | Evidencia |
|---|---|---|---|
| A1 | ¿La aplicación tiene alguna ruta que retire dinero del usuario además de la tasa de activación del 2% sobre cada depósito declarada? (tasa recurrente, participación en la ganancia, suscripción, cobro por operación, propina, "donación") | NO. El único cobro es el 2% sobre cada depósito, hecho antes del crédito en el exchange. No existe tasa por ganancia, por operación, por retiro, suscripción ni propina | PaymentManager.kt:109-111 (2%), :127-138 (cobro antes del depósito), :114-121 (orden del flujo); búsqueda de "performance fee/profit share/management fee": 0 ocurrencias en app/src/main |
| A2 | Enumera todos los destinos posibles de fondos: transferencias on-chain, retiros en el exchange, pago de la tasa. Para cada uno, di si el destino es la propia dirección del usuario, una dirección fija declarada embebida en el código, o algo calculado en tiempo de ejecución. ¿Existe algún destino que dependa de un dato recibido de la red? (No reproduzcas el valor literal de las direcciones — §1.2.) | 3 destinos. (i) tasa → dirección fija de custodia embebida en el código; (ii) depósito → contrato Bridge2 de Hyperliquid; (iii) retiro withdraw3 → siempre la propia dirección que firma. Ningún destino viene de la red |
AppConfiguration.kt:32 (constante inmutable), PaymentManager.kt:100-101; WalletManager.kt:92 (Bridge2); HyperliquidAPI.kt:1716 (destination = masterCredentials.address) y :1727 |
| A3 | ¿La tasa puede cobrarse dos veces por el mismo depósito? (reinicio de la app, reanudación del bot, reinstalación, importación de la misma cartera, dos carteras con la misma seed, fallo de red antes de la confirmación) | NO por el mismo depósito. Journal duradero con identidad <depósito>:fee; el estado indeterminado no se convierte en reversión y la operación se reanuda con la misma identidad. Los depósitos nuevos pagan 2% de nuevo — está declarado |
PaymentOperationStore.kt:24-34; PaymentManager.kt:70-76, :198 |
| A4 | ¿Existe backdoor, "modo desarrollador", feature flag, configuración remota o respuesta de servidor capaz de cambiar destino, importe o destinatario de una operación? ¿La app obedece alguna instrucción venida de la red sobre a dónde enviar dinero? | NO. La URL base es una constante de código; no existe configuración remota, feature flag, "modo dev" ni respuesta HTTP capaz de definir el destino | HyperliquidSigner.kt:38 (MAINNET_URL constante); búsqueda de remote config/flags: sin ruta que altere el destino |
| A5 | ¿La app pide aprobación (approve/allowance) de token en algún momento? Si sí, ¿cuál es el límite aprobado y puede gastarlo un tercero? | NO. No se solicita ningún approve/allowance. El contrato ERC-20 se usa solo para balanceOf y para armar la transferencia de USDC |
ERC20Contract.kt:31; búsqueda de "approve(/allowance": 0 ocurrencias |
| A6 | ¿La seed o la clave privada salen del dispositivo por cualquier ruta? (red, log, backup, portapapeles, intent, archivo externo, notificación, captura de pantalla) | NO. La seed no sale por red, log, backup, portapapeles ni intent; aparece solo en pantalla, bajo puerta de presencia | búsqueda de log de seed: 0 ocurrencias; MultiWalletManager.kt:422; MainActivity.kt:68-71 (FLAG_SECURE en toda la app); allowBackup=false |
| A7 | ¿Quien tiene el APK en la mano consigue extraer la seed? Considera: dispositivo con root, adb backup, almacenamiento externo, logcat, volcados de memoria, repackaging del APK. Relaciónalo con D2 (decisión declarada). |
Con root, sí — decisión declarada DD2: la clave del Keystore es autónoma para que el bot opere 24h. adb backup no (allowBackup=false); logcat no; el APK repackaging puede cambiar la constante de la tasa, por eso el certificado se publica y se verifica |
MultiWalletManager.kt:422; AndroidManifest.xml:55-57; ShareAppHelper.kt:33,42 |
| A8 | ¿El usuario puede perder fondos por una ruta que no autorizó explícitamente? Describe el peor caso realista y el peor caso adversarial. Relaciónalo con D4 (decisión declarada). | Realista: pérdida por la estrategia (D4 — apalancamiento 10–50x, sizing 100%). Adversarial: dispositivo comprometido → seed → todas las carteras; APK refirmado fuera de la distribución oficial | TradingBot.kt:1257,1282-1285,1338; MainActivity.kt:68-71 |
| # | Pregunta | Respuesta | Evidencia |
|---|---|---|---|
| B1 | Enumera todos los permisos declarados y por qué es necesario cada uno. ¿Existe alguno de riesgo: SMS, contactos, llamadas, ubicación, accesibilidad, administrador de dispositivo, superposición de pantalla, instalación de paquetes, lectura de almacenamiento externo? | 13 en el APK, todas funcionales. 11 declaradas en el manifest (internet, red, biometría, notificaciones, vibración, foreground service, data sync del servicio, wake lock, optimización de batería, boot, alarma exacta) + USE_FINGERPRINT (alias legado de la API de biometría) + un permiso interno de firma de AndroidX para receivers dinámicos. Ninguna de riesgo: sin SMS, contactos, ubicación, accesibilidad, admin, overlay ni instalación de paquetes |
AndroidManifest.xml:6-31; comprobado en el APK con aapt2 dump badging |
| B2 | ¿La app carga código en tiempo de ejecución? (DexClassLoader, PathClassLoader, descarga de DEX/JAR, eval, WebView con JavaScript bridge, plugins) |
NO. Cero DexClassLoader, PathClassLoader, WebView, eval o plugin; cero biblioteca nativa (.so) en el APK |
búsqueda en app/src/main: 0 ocurrencias; find de .so: 0 |
| B3 | ¿Qué componentes están exportados (exported=true)? ¿Qué puede hacer con ellos una aplicación de terceros instalada en el mismo dispositivo? |
MainActivity (solo abre la app; no lee el Intent) y BootReceiver (descarta action ≠ BOOT_COMPLETED). Los demás componentes exported=false |
AndroidManifest.xml:46-93 |
| B4 | ¿Existe alguna biblioteca de terceros que haga telemetría, analytics, anuncios, crash reporting o recogida de identificadores? Enumera todas las dependencias y qué envía cada una por la red. | NO. Sin telemetría, analytics, anuncios, crash reporting ni recolección de identificadores | búsqueda de firebase/crashlytics/analytics/sentry: 0 ocurrencias |
| B5 | ¿La app se esconde o se resiste a la desinstalación? (icono falso, desaparece de la lista de apps, impide la desinstalación, corre sin notificación visible) | NO. Icono normal, desinstalación normal, notificación del servicio siempre visible | AndroidManifest.xml; servicio en foreground |
| B6 | ¿La app hace detección de root, emulador, depurador o "fingerprint" del dispositivo? ¿Con qué finalidad y a dónde va ese dato? | SÍ, local (nuevo en la 1.0.21). Detecta root/bootloader desbloqueado para avisar al usuario y bloquear custodia nueva. No detecta emulador ni depurador, no lee identificador del dispositivo y no envía nada | DeviceIntegrity.kt (señales en §0); <queries> en AndroidManifest.xml:31-51 (sin permiso) |
| B7 | ¿La app se actualiza sola, instala APK o descarga código fuera del consentimiento explícito del usuario? | NO. No consulta la versión, no descarga APK, no instala nada; la actualización es una descarga manual en el sitio. La tarjeta nueva del sitio oficial solo abre el navegador del usuario cuando él la toca — la app no descarga ningún byte del APK | búsqueda de UpdateChecker/UPDATE_CHECK_URL: 0 ocurrencias; SecurityScreen.kt:191-226 (solo ACTION_VIEW); DEX sin descarga nativa |
| B8 | ¿Existe algún servicio en segundo plano que siga actuando después de que el usuario pare el bot, cierre la app o revoque un permiso? | El servicio en foreground solo actúa mientras el bot está activo y se detiene cuando el usuario lo para; la notificación es permanente y no se puede quitar sin detener el servicio | TradingBotService (foreground, canal visible) |
| # | Pregunta | Respuesta | Evidencia |
|---|---|---|---|
| C1 | Enumera exhaustivamente los dominios e IPs que la app puede contactar. ¿Todo destino es necesario (exchange, RPC de la red, sitio oficial)? ¿Existe algún dominio no declarado, analytics, CDN de terceros o endpoint de recogida? | 4 hosts de operación: api.hyperliquid.xyz, rpc.hyperliquid.xyz, arb1.arbitrum.io y https://0x2all.xyz (introducido en la 1.0.14, sin cambios aquí), que existe en el APK solo como texto (tarjeta de Seguridad y enlace de la política, abierto en el navegador) y nunca es objetivo de petición: el toque abre el navegador por Intent.ACTION_VIEW, no una conexión de la app. Más dos hosts de contenido (documentación de Hyperliquid y una búsqueda en Google iniciada por el propio usuario). Ningún dominio de analytics/CDN de recolección |
barrido de URLs en app/src/main y reconciliación del DEX: 12 hosts, conjunto idéntico al de la 1.0.16 — ninguno nuevo, ninguno eliminado; SecurityScreen.kt:39,196; HistoryScreen.kt:149 |
| C2 | ¿Todo el tráfico es HTTPS? ¿Existe cleartextTrafficPermitted? ¿Existe certificate pinning — y cubre todos los hosts que reciben datos sensibles? |
SÍ, todo HTTPS. cleartextTrafficPermitted=false en la configuración de red; pinning de CA en Hyperliquid y en el RPC de Arbitrum |
res/xml/network_security_config.xml:3; HyperliquidAPI.kt:460-461; ArbitrumRpc.kt:10 |
| C3 | ¿Qué va exactamente en cada petición (dirección pública, firma, orden, versión de la app)? ¿Se envía algún identificador del dispositivo, del usuario o de la instalación? | Dirección pública, firma y payload de la orden; sin identificador de dispositivo, usuario o instalación | HyperliquidAPI.kt (payloads); búsqueda de ANDROID_ID/AdvertisingId: 0 |
| C4 | ¿El servidor del sitio registra IP, user-agent o fecha de acceso? ¿Qué se retiene y durante cuánto tiempo? ¿Eso está declarado en la política de privacidad, y la política es verdadera cuando se compara con el código? | El sitio registra solo bloqueos (evento, país, región, ruta, horario; sin IP) y lo sirve Cloudflare. La política declara eso desde la v7: la versión 6 afirmaba lo contrario y fue corregida en esta edición — una política que contradice el código es hallazgo, no detalle de redacción | website/src/worker.js:15-17; privacy.html §4 (v7) |
| C5 | ¿La política de privacidad promete algo que el código no cumple? (recogida no declarada, retención no declarada, tercero no listado) | NO (recontrastado tras la corrección de la v7). Política y código coinciden en los puntos verificables: datos en el dispositivo, sin cuenta, sin analytics, log de bloqueo sin IP, ningún tercero además de Hyperliquid/Arbitrum/Cloudflare | privacy.html v7; código citado en C1–C4 |
| # | Pregunta | Respuesta | Evidencia |
|---|---|---|---|
| D1 | ¿El APK distribuido está firmado? ¿Cuál es el certificado (fingerprint SHA-256), es el mismo publicado en el sitio, y el SHA-256 del archivo coincide con el declarado? | SÍ. APK firmado con v2+v3, RSA-4096, certificado 53dac6cb…42c1 — el mismo publicado en el sitio; el SHA-256 del archivo coincide |
apksigner verify --print-certs; sha256sum |
| D2 | ¿El código fuente auditado corresponde al APK distribuido? ¿Cómo puede el usuario verificar esto por su cuenta? ¿Existe build reproducible o, como mínimo, el hash del APK y del certificado publicados junto al informe? | Correspondencia fuente↔APK verificada por inspección del binario (versión, permisos, clases, hosts y direcciones de contrato) — no es un build reproducible, y eso está declarado en las limitaciones | aapt2 dump badging; reconciliación de DEX |
| D3 | ¿La app verifica su propia firma antes de compartir el APK (distribución P2P) o antes de actualizarse? | SÍ. El compartir P2P aborta si el certificado no es el esperado | ShareAppHelper.kt:33,42 |
| D4 | ¿El informe de auditoría tiene hash publicado? ¿Cómo confirma el usuario que el texto que está leyendo es el mismo que fue auditado y no fue editado después? | SÍ. Cada archivo tiene SHA-256 publicado y prueba de fecha OpenTimestamps | audit.json; archivos .ots |
| # | Pregunta | Respuesta | Evidencia |
|---|---|---|---|
| E1 | ¿Qué pasa si el usuario desinstala la app con una posición abierta en el exchange? ¿El dinero queda accesible por otra ruta (seed, sitio del exchange) o se pierde? | El dinero sigue accesible por la seed (otra cartera o importación en la app) y por el propio exchange; las posiciones vivas se leen del exchange al reinstalar | reconciliación de fills/posiciones; MultiWalletManager |
| E2 | Si roban el dispositivo, ¿qué puede hacer el ladrón? ¿La seed está protegida por biometría/credencial del dispositivo? ¿La pantalla está protegida contra capturas de pantalla? | Seed cifrada por el Keystore, pantalla protegida contra capturas; las acciones de custodia piden presencia. Root expone la seed (D2) — desde la 1.0.21 la app avisa en la apertura y bloquea el depósito en un dispositivo señalado | MainActivity.kt:68-71; DeviceIntegrityGate en MainActivity.kt:159-181; AppLockManager.requirePresence en DashboardScreen.kt:586-696 |
| E3 | ¿Existe alguna ruta en la que la app borre una cartera que todavía tiene saldo, o considere "vacía" una cartera con fondos (por error de lectura de saldo)? | La exclusión y el offboard validan el saldo en todas las capas (USDC on-chain, ETH y saldo en el exchange) antes de cualquier acción destructiva; sin saldo = solo polvo eliminable con aceptación | RageQuitController; verificaciones cross-layer |
| E4 | ¿Qué pasa si el exchange está caído, la conexión se corta en medio de una orden, o la respuesta se pierde? ¿La app puede duplicar una orden, duplicar un cobro o quedar en un estado inconsistente? | Las operaciones tienen journal duradero e identidad idempotente; el estado indeterminado no duplica cobro ni retiro | PaymentOperationStore.kt; HyperliquidOperationStore; PaymentManager.kt:70-76,198 |
| E5 | Si el sistema mata el proceso con una posición abierta, ¿el stop loss sigue vigente en el exchange? ¿La app reconcilia al volver? | Los stops viven en el exchange y siguen válidos con la app muerta; la app reconcilia y recrea el stop ausente al volver | reconcileStopWithExchange (checkPositions, ciclo de 2 min) |
| ID | Declaración | ¿Verificada? | Efecto para el usuario | Riesgo asumido |
|---|---|---|---|---|
| DD1 | Dirección de la tasa no publicada | SÍ — constante inmutable (AppConfiguration.kt:32), sin setter; valor ausente de la app y del sitio (búsqueda = 0) |
El destino no se puede comprobar por el texto público | Destino no verificable por lectura |
| DD2 | Clave del Keystore autónoma | SÍ — setUserAuthenticationRequired(false) (MultiWalletManager.kt:422) con puerta de presencia en las acciones manuales |
El bot opera con el dispositivo bloqueado; las acciones manuales piden presencia | Un dispositivo con root expone las seeds; no es un vector remoto |
| DD3 | Retiro automático de ganancia (D12) | SÍ — disparador US$ 22 por evento (ProfitTracker.kt:46) y fracción del 50% (:52) |
La ganancia realizada por encima del disparador se retira parcialmente al propio usuario | Depende de la custodia autónoma (D2) |
| DD4 | Sizing 100% del patrimonio, apalancamiento 10–50x | SÍ — patrimonio leído con fail-closed (TradingBot.kt:1252-1258), posición del 100% (:1270), apalancamiento máximo del activo (:1192-1202) |
Posiciones grandes con objetivos lejanos; pérdida total posible en una reversión fuerte | Pérdida total o parcial del capital |
Ninguna de las cuatro se clasificó como hallazgo, conforme al alcance. Lo que se verificó es que cada una está implementada como se declara; la que no lo estuviera sería hallazgo.
0 hallazgos abiertos (crítico, alto, medio o bajo).
Notas informativas, sin acción obligatoria:
0x2all.xyz está registrado y en línea desde el
20/10/2026; el enlace de la política y la tarjeta de autenticidad abren un destino real, y la
página publica el fingerprint del certificado y el SHA-256 del APK.Corrección del registro de una edición anterior. La nota 4 de la v7.0 afirmaba que el bloque
T5 antiguo se había vuelto código inalcanzable, citando dos copias del test stillOpen.
Recontrastado en el árbol de la 1.0.19 (0c96c95) y en el de la 1.0.20 (6814b8b): hay una
única ocurrencia (TradingBot.kt:2121-2123), ya así en la edición anterior. La duplicación
se había eliminado antes de la 1.0.19 y la nota se retira — sin efecto para el usuario.
La detección de root es aviso, no garantía. La comprobación de la 1.0.21 (DeviceIntegrity)
es heurística y corre en el dispositivo: Magisk DenyList/Shamiko, un APK repatcheado o un hook
(Frida) devuelven el resultado que el atacante quiera. Vale para el usuario honesto y para el
momento antes del primer depósito; no sustituye un dispositivo dedicado, sin root, con bloqueo
de pantalla. Ningún dato sale del dispositivo y no se lee ningún identificador.
version.json)./audit/prompt-pt.md o prompt-en.md) y aplícalo al APK firmado:
apksigner verify --print-certs, aapt2 dump badging/xmltree, descompilación del DEX
(jadx o baksmali) y barrido de hosts y direcciones 0x en los DEX.audit.json.ots verify en los archivos .ots.El repositorio es privado y no es necesario: las referencias archivo:línea apuntan al fuente del
commit citado; auditando solo el APK se comprueba el comportamiento y las cadenas del DEX.
| Item | Valor |
|---|---|
| Commit | 9f69edc (73fe94d y 19209cf = docs/sitio, mismo árbol de app) |
| Versión | 1.0.21 (code 21) |
| APK examinado | 0x2ALL-1.0.21-9f69edc-release.apk |
| SHA-256 del APK | 325245a6542212f0227eb7616f9a550bcd0053e5d7c613a66d080c60698bf830 |
| Tamaño | 6.677.553 bytes |
| Certificado (SHA-256) | 53dac6cbe7edd6894b9377c4bbdc302a883abbe18a01ad2bd87d0a0fafa142c1 |
| Firma | v2 + v3, RSA-4096, CN=0x2ALL |
| Permisos | 13 en el APK, idénticos a los de la 1.0.20 (diff vacío) |
| Hosts en el DEX | 12, conjunto idéntico al de la 1.0.20 (diff vacío) |
Direcciones 0x… en el DEX |
7, idénticas a las de la 1.0.20 (diff vacío) |
| Clases nuevas en el DEX | 83 en total; de dominio: DeviceIntegrity, DeviceIntegrity$Finding, MainActivityKt$DeviceIntegrityGate* — el resto son lambdas Compose renumeradas (66 clases antiguas equivalentes salieron) |
| Fecha de la ejecución | 21/10/2026 |