← /audit

Auditoria na perspectiva do usuário — 0x2ALL (edição v9.0)

Prompt aplicado: AUDIT_PROMPT_USER_pt-BR.md v2.1 (público, reproduzível) — inalterado Data da execução: 21 de outubro de 2026 Auditor: DeepSeek v4.1 Flash (1017) — revisão em quatro frentes (dinheiro, malware, rede, custódia) com verificação manual dos itens que mudam o veredicto Código auditado: commit 9f69edc — v1.0.21 (code 21). A árvore de arquivos que gerou o APK é a deste commit (a feature entrou em 36115b0; 9f69edc corrige o espaçamento da tela Estratégia); commits posteriores são documentação e site Binário examinado: 0x2ALL-1.0.21-9f69edc-release.apk, SHA-256 325245a6542212f0227eb7616f9a550bcd0053e5d7c613a66d080c60698bf830, 6.677.553 bytes, certificado 53dac6cbe7edd6894b9377c4bbdc302a883abbe18a01ad2bd87d0a0fafa142c1 Substitui: edição v8.0 (1.0.20, 6814b8b) Escopo: prompt v2.1 — as decisões de design declaradas em §2b estão fora do escopo de achado, mas foram verificadas uma a uma.


0. O que mudou nesta edição

Esta é a reauditoria do binário 1.0.21. O delta desde a edição v8.0 (1.0.20, 6814b8b) tem uma mudança funcional e uma correção de texto:

O que muda para o usuário, em linguagem simples. Se o celular tem root ou bootloader destravado, o app agora avisa em vez de fingir que está tudo bem — e não deixa ele colocar dinheiro novo num aparelho onde a frase de recuperação pode ser lida por qualquer aplicativo com root. Quem já tem fundos ali continua conseguindo sacar, enviar e ver a frase: o app informa e bloqueia a entrada, nunca a saída.

Por que isso não afrouxa nenhuma proteção. A checagem é local — nada é enviado, nada é persistido e nenhum identificador do aparelho é lido. Não há endpoint, permissão ou destino de fundos novo: o <queries> do manifest apenas torna visível se um gerenciador de root está instalado. Permissões (13), hosts (12) e endereços 0x (7) seguem idênticos aos da 1.0.20.

Limite declarado. A detecção é heurística: Magisk DenyList/Shamiko, APK repatcheado e hook (Frida) derrotam. Ela serve ao usuário honesto e ao momento antes do primeiro depósito — não ao atacante. O app não afirma em nenhum lugar que "sem aviso = seguro".

Reauditoria. As 30 respostas foram reconferidas contra a árvore e o binário novos. Provas de que o código auditado é o assinado: 83 classes novas no DEX, sendo as de domínio DeviceIntegrity, DeviceIntegrity$Finding e MainActivityKt$DeviceIntegrityGate* (o restante são lambdas Compose renumeradas, 66 classes antigas equivalentes saíram); as strings androidboot.verifiedbootstate (4 ocorrências), androidboot.flash.locked, test-keys, kernelsu e /system/xbin/su presentes no classes.dex; e as 10 chaves novas de aviso/estado em cada um dos 6 locales no resources.arsc. Tamanhos: classes.dex +1.456 bytes, classes3.dex +12.196, resources.arsc +16.972.


1. Veredicto

Critério Resultado
Veredicto APROVADO — 0 achados abertos
Crítico 0
Alto 0
Médio 0
Baixo 0
Informativo 5 (distribuição, domínio, correção de registro e a nova detecção de root, §3)

2. Respostas diretas

Grupo A — Dinheiro

# Pergunta Resposta Evidência
A1 O aplicativo tem algum caminho que retire dinheiro do usuário além da taxa de ativação de 2% sobre cada depósito declarada? (taxa recorrente, participação no lucro, assinatura, cobrança por operação, gorjeta, "doação") NÃO. A única cobrança é 2% sobre cada depósito, feita antes do crédito na exchange. Não existe taxa por lucro, por operação, por saque, assinatura ou gorjeta PaymentManager.kt:109-111 (2%), :127-138 (cobrança antes do depósito), :114-121 (ordem do fluxo); busca por "performance fee/profit share/management fee": 0 ocorrências em app/src/main
A2 Liste todos os destinos possíveis de fundos: transferências on-chain, saques na exchange, pagamento de taxa. Para cada um, diga se o destino é o próprio endereço do usuário, um endereço fixo declarado embutido no código, ou algo calculado em tempo de execução. Existe algum destino que dependa de dado recebido da rede? (Não reproduza o valor literal dos endereços — §1.2.) 3 destinos. (i) taxa → endereço fixo de custódia embutido no código; (ii) depósito → contrato Bridge2 da Hyperliquid; (iii) saque withdraw3 → sempre o próprio endereço que assina. Nenhum destino vem da rede AppConfiguration.kt:32 (constante imutável), PaymentManager.kt:100-101; WalletManager.kt:92 (Bridge2); HyperliquidAPI.kt:1716 (destination = masterCredentials.address) e :1727
A3 A taxa pode ser cobrada duas vezes pelo mesmo depósito? (reinício do app, retomada do robô, reinstalação, importação da mesma carteira, duas carteiras com a mesma seed, falha de rede antes da confirmação) NÃO pelo mesmo depósito. Journal durável com identidade <depósito>:fee; estado indeterminado não vira reversão e a operação é retomada com a mesma identidade. Depósitos novos pagam 2% de novo — está declarado PaymentOperationStore.kt:24-34; PaymentManager.kt:70-76, :198
A4 Existe backdoor, "modo desenvolvedor", feature flag, configuração remota ou resposta de servidor capaz de mudar destino, valor ou destinatário de uma operação? O app obedece a alguma instrução vinda da rede sobre para onde mandar dinheiro? NÃO. URL base é constante de código; não existe configuração remota, feature flag, "modo dev" nem resposta HTTP capaz de definir destino HyperliquidSigner.kt:38 (MAINNET_URL constante); busca por remote config/flags: sem caminho que altere destino
A5 O app pede aprovação (approve/allowance) de token em algum momento? Se sim, qual é o limite aprovado e ele pode ser gasto por terceiro? NÃO. Nenhum approve/allowance é solicitado. O contrato ERC-20 é usado só para balanceOf e para montar a transferência de USDC ERC20Contract.kt:31; busca por "approve(/allowance": 0 ocorrências
A6 A seed ou a chave privada saem do aparelho em qualquer caminho? (rede, log, backup, clipboard, intent, arquivo externo, notificação, screenshot) NÃO. A seed não sai por rede, log, backup, clipboard ou intent; aparece só na tela, sob gate de presença busca por log de seed: 0 ocorrências; MultiWalletManager.kt:422; MainActivity.kt:68-71 (FLAG_SECURE no app inteiro); allowBackup=false
A7 Quem tem o APK na mão consegue extrair a seed? Considere: aparelho com root, adb backup, armazenamento externo, logcat, dumps de memória, APK repackaging. Relacione com D2 (decisão declarada). Com root, sim — decisão declarada DD2: a chave do Keystore é autônoma para o robô operar 24h. adb backup não (allowBackup=false); logcat não; APK repackaging pode trocar a constante da taxa, por isso o certificado é publicado e verificado MultiWalletManager.kt:422; AndroidManifest.xml:55-57; ShareAppHelper.kt:33,42
A8 O usuário consegue perder fundos por um caminho que ele não autorizou explicitamente? Descreva o pior caso realista e o pior caso adversarial. Relacione com D4 (decisão declarada). Realista: perda pela estratégia (D4 — alavancagem 10–50x, sizing 100%). Adversarial: aparelho comprometido → seed → todas as carteiras; APK reassinado fora da distribuição oficial TradingBot.kt:1257,1282-1285,1338; MainActivity.kt:68-71

Grupo B — Malware / comportamento no aparelho

# Pergunta Resposta Evidência
B1 Liste todas as permissões declaradas e por que cada uma é necessária. Existe alguma de risco: SMS, contatos, chamadas, localização, acessibilidade, administrador de dispositivo, sobreposição de tela, instalação de pacotes, leitura de armazenamento externo? 13 no APK, todas funcionais. 11 declaradas no manifest (internet, rede, biometria, notificações, vibração, foreground service, data sync do serviço, wake lock, otimização de bateria, boot, alarme exato) + USE_FINGERPRINT (alias legado da API de biometria) + uma permissão interna de assinatura do AndroidX para receivers dinâmicos. Nenhuma de risco: sem SMS, contatos, localização, acessibilidade, admin, overlay ou instalação de pacotes AndroidManifest.xml:6-31; conferido no APK com aapt2 dump badging
B2 O app carrega código em tempo de execução? (DexClassLoader, PathClassLoader, download de DEX/JAR, eval, WebView com JavaScript bridge, plugins) NÃO. Zero DexClassLoader, PathClassLoader, WebView, eval ou plugin; zero biblioteca nativa (.so) no APK busca em app/src/main: 0 ocorrências; find por .so: 0
B3 Quais componentes são exportados (exported=true)? O que um aplicativo terceiro instalado no mesmo aparelho consegue fazer com eles? MainActivity (só abre o app; não lê Intent) e BootReceiver (descarta action ≠ BOOT_COMPLETED). Demais componentes exported=false AndroidManifest.xml:46-93
B4 Existe alguma biblioteca de terceiros que faça telemetria, analytics, anúncios, crash reporting ou coleta de identificadores? Liste todas as dependências e o que cada uma envia pela rede. NÃO. Sem telemetria, analytics, anúncios, crash reporting ou coleta de identificador busca por firebase/crashlytics/analytics/sentry: 0 ocorrências
B5 O app se esconde ou resiste à remoção? (ícone falso, some da lista de apps, impede desinstalação, roda sem notificação visível) NÃO. Ícone normal, desinstalação normal, notificação do serviço sempre visível AndroidManifest.xml; serviço em foreground
B6 O app faz detecção de root, emulador, depurador ou "fingerprint" do aparelho? Com que finalidade e para onde esse dado vai? SIM, local (novo na 1.0.21). Detecta root/bootloader destravado para avisar o usuário e bloquear custódia nova. Não detecta emulador nem depurador, não lê identificador do aparelho e não envia nada DeviceIntegrity.kt (sinais em §0); <queries> em AndroidManifest.xml:31-51 (sem permissão)
B7 O app se atualiza sozinho, instala APK ou baixa código fora do consentimento explícito do usuário? NÃO. Não consulta versão, não baixa APK, não instala nada; atualização é download manual no site. O card novo do site oficial só abre o navegador do usuário quando ele toca — nenhum byte do APK é baixado pelo app busca por UpdateChecker/UPDATE_CHECK_URL: 0 ocorrências; SecurityScreen.kt:191-226 (apenas ACTION_VIEW); DEX sem download nativo
B8 Existe serviço em segundo plano que continue agindo depois de o usuário parar o robô, fechar o app ou revogar permissão? Serviço em foreground só age enquanto o robô está ativo e para quando o usuário para; a notificação é permanente e não removível sem parar o serviço TradingBotService (foreground, canal visível)

Grupo C — Rede e privacidade

# Pergunta Resposta Evidência
C1 Liste exaustivamente os domínios e IPs que o app pode contatar. Todo destino é necessário (exchange, RPC da rede, site oficial)? Existe algum domínio não declarado, analytics, CDN de terceiro ou endpoint de coleta? 4 hosts de operação: api.hyperliquid.xyz, rpc.hyperliquid.xyz, arb1.arbitrum.io e https://0x2all.xyz (introduzido na 1.0.14, inalterado aqui), que existe no APK apenas como texto (card de Segurança e link da política, aberto no navegador) e nunca é alvo de requisição: o toque abre o navegador por Intent.ACTION_VIEW, não uma conexão do app. Mais dois hosts de conteúdo (documentação da Hyperliquid e uma busca no Google iniciada pelo próprio usuário). Nenhum domínio de analytics/CDN de coleta varredura de URLs em app/src/main e reconciliação do DEX: 12 hosts, conjunto idêntico ao da 1.0.16 — nenhum novo, nenhum removido; SecurityScreen.kt:39,196; HistoryScreen.kt:149
C2 Todo tráfego é HTTPS? Existe cleartextTrafficPermitted? Existe certificate pinning — e ele cobre todos os hosts que recebem dado sensível? SIM, tudo HTTPS. cleartextTrafficPermitted=false na configuração de rede; pinning de CA em Hyperliquid e no RPC da Arbitrum res/xml/network_security_config.xml:3; HyperliquidAPI.kt:460-461; ArbitrumRpc.kt:10
C3 O que exatamente vai em cada requisição (endereço público, assinatura, ordem, versão do app)? Algum identificador do aparelho, do usuário ou da instalação é enviado? Endereço público, assinatura e payload da ordem; sem identificador de aparelho, usuário ou instalação HyperliquidAPI.kt (payloads); busca por ANDROID_ID/AdvertisingId: 0
C4 O servidor do site registra IP, user-agent ou data de acesso? O que é retido e por quanto tempo? Isso está declarado na política de privacidade, e a política é verdadeira quando comparada ao código? O site registra apenas bloqueios (evento, país, região, rota, horário; sem IP) e é servido pela Cloudflare. A política declara isso desde a v7: a versão 6 afirmava o contrário e foi corrigida nesta edição — política que contradiz o código é achado, não detalhe de redação website/src/worker.js:15-17; privacy.html §4 (v7)
C5 A política de privacidade promete algo que o código não cumpre? (coleta não declarada, retenção não declarada, terceiro não listado) NÃO (reconferido após a correção da v7). Política e código coincidem nos pontos verificáveis: dados no aparelho, sem conta, sem analytics, log de bloqueio sem IP, nenhum terceiro além de Hyperliquid/Arbitrum/Cloudflare privacy.html v7; código citado em C1–C4

Grupo D — Autenticidade e integridade

# Pergunta Resposta Evidência
D1 O APK distribuído é assinado? Qual é o certificado (fingerprint SHA-256), ele é o mesmo publicado no site, e o SHA-256 do arquivo confere com o declarado? SIM. APK assinado com v2+v3, RSA-4096, certificado 53dac6cb…42c1 — o mesmo publicado no site; SHA-256 do arquivo confere apksigner verify --print-certs; sha256sum
D2 O código-fonte auditado corresponde ao APK distribuído? Como o usuário pode verificar isso sozinho? Existe build reprodutível ou, no mínimo, o hash do APK e do certificado publicados junto do relatório? Correspondência fonte↔APK verificada por inspeção do binário (versão, permissões, classes, hosts e endereços de contrato) — não é build reprodutível, e isso está declarado nas limitações aapt2 dump badging; reconciliação de DEX
D3 O app verifica a própria assinatura antes de compartilhar o APK (distribuição P2P) ou antes de se atualizar? SIM. O compartilhamento P2P aborta se o certificado não for o esperado ShareAppHelper.kt:33,42
D4 O relatório de auditoria tem hash publicado? Como o usuário confirma que o texto que ele está lendo é o mesmo que foi auditado e não foi editado depois? SIM. Cada arquivo tem SHA-256 publicado e prova de data OpenTimestamps audit.json; arquivos .ots

Grupo E — Falha, perda e recuperação

# Pergunta Resposta Evidência
E1 O que acontece se o usuário desinstalar o app com posição aberta na exchange? O dinheiro fica acessível por outro caminho (seed, site da exchange) ou se perde? O dinheiro continua acessível pela seed (outra carteira ou importação no app) e pela própria exchange; posições vivas são lidas da exchange na reinstalação reconciliação de fills/posições; MultiWalletManager
E2 Se o aparelho for roubado, o que o ladrão consegue fazer? A seed está protegida por biometria/credencial do aparelho? A tela é protegida contra screenshot? Seed cifrada pelo Keystore, tela protegida contra captura; ações de custódia pedem presença. Root expõe a seed (D2) — desde a 1.0.21 o app avisa na abertura e bloqueia depósito em aparelho sinalizado MainActivity.kt:68-71; DeviceIntegrityGate em MainActivity.kt:159-181; AppLockManager.requirePresence em DashboardScreen.kt:586-696
E3 Existe algum caminho em que o app apague uma carteira que ainda tem saldo, ou considere "vazia" uma carteira com fundos (por erro de leitura de saldo)? Exclusão e offboard validam saldo em todas as camadas (on-chain USDC, ETH e saldo na exchange) antes de qualquer ação destrutiva; sem saldo = só poeira excluível com aceite RageQuitController; verificações cross-layer
E4 O que acontece se a exchange estiver fora do ar, a conexão cair no meio de uma ordem, ou a resposta se perder? O app pode duplicar uma ordem, duplicar uma cobrança ou ficar em estado inconsistente? Operações têm journal durável e identidade idempotente; estado indeterminado não duplica cobrança nem saque PaymentOperationStore.kt; HyperliquidOperationStore; PaymentManager.kt:70-76,198
E5 Se o processo for morto pelo sistema com posição aberta, o stop loss continua valendo na exchange? O app reconcilia ao voltar? Os stops vivem na exchange e continuam válidos com o app morto; o app reconcilia e recria stop ausente ao voltar reconcileStopWithExchange (checkPositions, ciclo de 2 min)

2b. Decisões de design declaradas

ID Declaração Verificada? Efeito para o usuário Risco assumido
DD1 Endereço da taxa não publicado SIM — constante imutável (AppConfiguration.kt:32), sem setter; valor ausente do app e do site (busca = 0) O destino não é conferível pelo texto público Destino não verificável por leitura
DD2 Chave do Keystore autônoma SIM — setUserAuthenticationRequired(false) (MultiWalletManager.kt:422) com gate de presença nas ações manuais O robô opera com o aparelho bloqueado; ações manuais pedem presença Aparelho com root expõe as seeds; não é vetor remoto
DD3 Saque automático de lucro (D12) SIM — gatilho US$ 22 por evento (ProfitTracker.kt:46) e fração de 50% (:52) Lucro realizado acima do gatilho é parcialmente sacado para o próprio usuário Depende da custódia autônoma (D2)
DD4 Sizing 100% do patrimônio, alavancagem 10–50x SIM — patrimônio lido com fail-closed (TradingBot.kt:1252-1258), posição de 100% (:1270), alavancagem máxima do ativo (:1192-1202) Posições grandes com alvos distantes; perda total possível em reversão forte Perda total ou parcial do capital

Nenhuma das quatro foi classificada como achado, conforme o escopo. O que foi verificado é que cada uma está implementada como declarada; a que não estivesse seria achado.


3. Achados

0 achados abertos (crítico, alto, médio ou baixo).

Notas informativas, sem ação obrigatória:

  1. Repackaging na distribuição P2P. Quem recebe o APK por compartilhamento pode receber um arquivo reassinado por terceiro. A defesa existe (fingerprint do certificado no app, no site e verificação no compartilhamento), mas depende de o usuário comparar o valor.
  2. D1 não é verificável por texto público. É consequência aceita da decisão de design.
  3. Nota 3 da v7.0 resolvida. O domínio 0x2all.xyz está registrado e no ar desde 20/10/2026; o link da política e o card de autenticidade abrem destino real, e a página publica o fingerprint do certificado e o SHA-256 do APK.
  4. Correção de registro da edição anterior. A nota 4 da v7.0 dizia que o bloco T5 antigo havia virado código inalcançável, citando duas cópias do teste stillOpen. Reconferido na árvore da 1.0.19 (0c96c95) e na da 1.0.20 (6814b8b): existe uma única ocorrência (TradingBot.kt:2121-2123), já assim na edição anterior. A duplicação havia sido removida antes da 1.0.19 e a nota é retirada — nenhum efeito para o usuário.

  5. Detecção de root é aviso, não garantia. A checagem da 1.0.21 (DeviceIntegrity) é heurística e roda no aparelho: Magisk DenyList/Shamiko, um APK repatcheado ou um hook (Frida) devolvem o resultado que o atacante quiser. Ela vale para o usuário honesto e para o momento antes do primeiro depósito; não substitui aparelho dedicado, sem root, com bloqueio de tela. Nenhum dado sai do aparelho e nenhum identificador é lido.


4. Limitações


5. Como reproduzir

  1. Baixe o APK na página de download e confira o SHA-256 e o fingerprint do certificado (tabela desta página e version.json).
  2. Baixe o prompt (/audit/prompt-pt.md ou prompt-en.md) e aplique ao APK assinado: apksigner verify --print-certs, aapt2 dump badging/xmltree, descompilação do DEX (jadx ou baksmali) e varredura de hosts e endereços 0x nos DEX.
  3. Confira o SHA-256 de cada arquivo desta página com a tabela publicada e com o audit.json.
  4. Verifique a prova de data com ots verify nos arquivos .ots.
  5. Compare as respostas com as tabelas acima. Divergência é um achado.

O repositório é privado e não é necessário: as referências arquivo:linha apontam para o fonte do commit citado; auditando só o APK, confere-se o comportamento e as strings do DEX.


6. Binário e fonte examinados

Item Valor
Commit 9f69edc (feature em 36115b0; correção de espaçamento em 9f69edc; demais commits são docs/site)
Versão 1.0.21 (code 21)
APK examinado 0x2ALL-1.0.21-9f69edc-release.apk
SHA-256 do APK 325245a6542212f0227eb7616f9a550bcd0053e5d7c613a66d080c60698bf830
Tamanho 6.677.553 bytes
Certificado (SHA-256) 53dac6cbe7edd6894b9377c4bbdc302a883abbe18a01ad2bd87d0a0fafa142c1
Assinatura v2 + v3, RSA-4096, CN=0x2ALL
Permissões 13 no APK, idênticas às da 1.0.20 (diff vazio)
Hosts no DEX 12, conjunto idêntico ao da 1.0.20 (diff vazio)
Endereços 0x… no DEX 7, idênticos aos da 1.0.20 (diff vazio)
Classes novas no DEX 83 no total; de domínio: DeviceIntegrity, DeviceIntegrity$Finding, MainActivityKt$DeviceIntegrityGate* — o restante são lambdas Compose renumeradas (66 classes antigas equivalentes saíram)
Data da execução 21/10/2026