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
CVE-2026-64640 — Reprodutor que explora a emissão de credenciais antes da validação de localização no Apache Polaris Iceberg REST, comprovando leituras de nuvem entre locatários (cross-tenant) e oráculo de existência de bucket. | Kitploit
Ferramentas/GitHubGitHub/oscerd/cve-2026-64640
ReconhecimentoAnálise de VulnerabilidadesExploraçãoExploração de Aplicações WebExfiltração de DadosTestes de PenetraçãoSegurança na NuvemSegurança de API
GitHuboscerd/cve-2026-64640

CVE-2026-64640

Reprodutor que explora a emissão de credenciais antes da validação de localização no Apache Polaris Iceberg REST, comprovando leituras de nuvem entre locatários (cross-tenant) e oráculo de existência de bucket.

há 13 diasAinda 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
Ver Repositório

CVE-2026-64640 — Apache Polaris: emissão de credenciais antes da validação de localização em register

Um reprodutor autocontido, acionado com um único comando, para a CVE-2026-64640: os endpoints register do Iceberg REST no Apache Polaris emitem credenciais de armazenamento em nuvem para um caminho fornecido pelo chamador e leem esse caminho no lado do servidor antes de verificá-lo em relação aos allowedLocations do catálogo.

Um principal cujo único privilégio é criar tabelas em seu próprio catálogo pode fazer o Polaris usar as credenciais de armazenamento do catálogo para ler objetos que o catálogo nunca teve permissão de tocar — o prefixo de outro tenant, outro bucket, qualquer coisa que o principal de armazenamento consiga alcançar.

CVECVE-2026-64640
Componentepolaris-runtime-service — IcebergCatalog / LocalIcebergCatalog: registerTable, registerView
EndpointsPOST /api/catalog/v1/{prefix}/namespaces/{namespace}/register
POST /api/catalog/v1/{prefix}/namespaces/{namespace}/register-view (1.6.0+)
CWECWE-441 (deputado confuso), CWE-639 (bypass de autorização por meio de chave controlada pelo usuário), CWE-918 (SSRF)
GravidadeAlta — CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N (8.1)
Afetadas≤ 1.6.0 (verificado em 1.3.0-incubating, 1.4.0, 1.4.1, 1.5.0, 1.6.0)
Corrigida em1.7.0 — a 1.6.0 corrige apenas o caminho de tabela e reintroduz a falha no novo caminho de view
Privilégio necessárioum principal autenticado com TABLE_CREATE / CATALOG_MANAGE_CONTENT em qualquer catálogo — sem admin

A 1.6.0 não é uma correção. Ela fecha o register (incidentalmente, dentro de um PR de funcionalidade) e entrega o recém-criado endpoint register-view com o mesmo erro de ordenação. O reprodutor prova as duas metades. Atualize para a 1.7.0.

Como executar

Pré-requisitos: Docker com o plugin Compose v2, curl, python3, bash. Nada mais — o ambiente é construído a partir de imagens publicadas e derrubado em seguida.

root@kitploit:~
./exploit.sh                 # default: apache/polaris:1.4.1  -> reproduces via register
./exploit.sh --tag 1.6.0     # partially fixed               -> reproduces via register-view
./exploit.sh --tag 1.7.0     # comprehensively fixed         -> refuses cleanly on both
./scripts/version-matrix.sh  # every release, side by side

O código de saída 0 significa que a vulnerabilidade foi reproduzida, 1 significa que não foi, 2 significa que o ambiente não conseguiu subir. Cada requisição e resposta é gravada em evidence/<timestamp>-polaris-<tag>/.

Como é o ambiente

root@kitploit:~
  catalog  tenant_a_catalog        allowedLocations = [ s3://bucket123 ]
  actor    low_priv_user           CATALOG_MANAGE_CONTENT on that catalog, nothing else
  target   s3://tenant-b-private   another tenant's bucket:
                                     no allowedLocations entry, no grant, no relation
                                     to the attacker's catalog — but reachable by the
                                     credentials that back it

Essa última linha é a parte realista. Os operadores delimitam um catálogo com allowedLocations; a role de IAM subjacente é quase sempre mais ampla do que um único prefixo. allowedLocations é a parede. Este bug a contorna.

O que ele prova

Teste 0 — a parede é real. Criar uma tabela com uma localização explícita em s3://tenant-b-private é recusado com 403 ForbiddenException, antes que qualquer coisa seja lida. O Polaris sabe muito bem que a localização está fora dos limites.

Teste 1 — o register lê mesmo assim. O mesmo principal aponta register para s3://tenant-b-private/sales/metadata/00007-tenant-b-sales.metadata.json. A resposta também é um 403 — mas ela cita s3://tenant-b-private/warehouse/CANARY-64640-4f1c9e2a-tenant-b-sales, uma string que existe apenas no corpo daquele objeto:

root@kitploit:~
{"error":{"message":"Invalid locations '[s3://tenant-b-private/warehouse/sales/data,
s3://tenant-b-private/warehouse/CANARY-64640-4f1c9e2a-tenant-b-sales]' for identifier
'tenant_a_ns.pwn_canary': s3://tenant-b-private/warehouse/sales/data is not in the list
of allowed locations: [s3://bucket123/tenant_a_ns]","type":"ForbiddenException","code":403}}

A requisição nunca menciona warehouse/. O Polaris só poderia produzir essas strings buscando e analisando o objeto com as credenciais do catálogo. O 403 é o Polaris capturando a violação um passo depois da leitura que deveria prevenir.

Teste 2 — o que volta. Dois campos distintos extraídos do documento vítima são ecoados de volta ao chamador: a location declarada da tabela e sua propriedade write.data.path.

Teste 3 — um oráculo de enumeração de armazenamento. A mesma chamada responde de forma diferente para cada estado de um alvo fora de allowedLocations:

Quatro respostas distinguíveis significam quatro fatos sobre o armazenamento que o chamador não tem o direito de aprender. Em AWS real, a sonda de existência de bucket alcança o namespace global de buckets S3, usando as credenciais do catálogo.

Em uma build corrigida, cada linha dessa tabela é o mesmo 403 mencionando apenas o caminho solicitado, e nada de dentro do objeto volta — o script detecta essa assinatura e reporta NOT VULNERABLE — pre-validation observed.

Teste 4 — a mesma falha em register-view. O Polaris 1.6.0 adicionou POST .../namespaces/{ns}/register-view, alcançando o registerView, que carrega o FileIO e analisa o documento do chamador sem validação prévia — exatamente o que o registerTable tinha acabado de parar de fazer. Na 1.6.0, o canário de view volta:

root@kitploit:~
{"error":{"message":"Invalid locations '[s3://tenant-b-private/warehouse/CANARY-64640-VIEW-8d3b7a15-tenant-b]'
for identifier 'tenant_a_ns.pwn_view': … is not in the list of allowed locations:
[s3://bucket123/tenant_a_ns]","type":"ForbiddenException","code":403}}

Portanto, uma implantação na 1.6.0 ainda está exposta, por meio de um endpoint diferente, à mesma primitiva. Na 1.4.1 e em versões anteriores, o endpoint não existe e o script informa isso.

Causa raiz

IcebergCatalog.registerTable (LocalIcebergCatalog a partir da 1.6.0), antes da correção — registerView tem exatamente a mesma forma:

root@kitploit:~
String locationDir = metadataFileLocation.substring(0, lastSlashIndex);   // attacker-controlled
...
FileIO fileIO =
    loadFileIOForTableLike(
        identifier,
        Set.of(locationDir),                                              // credentials minted here
        resolvedParent,
        new HashMap<>(tableDefaultProperties),
        Set.of(PolarisStorageActions.READ, PolarisStorageActions.LIST));

InputFile metadataFile = fileIO.newInputFile(metadataFileLocation);       // server-side GET
TableMetadata metadata = TableMetadataParser.read(metadataFile);          // server-side parse
ops.commit(null, metadata);                                               // allowedLocations checked HERE

A cadeia de emissão (loadFileIOForTableLike → StorageAccessConfigProvider.getStorageAccessConfig → *StorageIntegration.getSubscopedCreds) não realiza nenhuma verificação própria de allowedLocations; portanto, a única aplicação é a do momento do commit — e nesse ponto a leitura privilegiada já aconteceu e o resultado dela está na resposta.

Os caminhos irmãos no mesmo arquivo acertam a ordem: a criação de view e o sendNotificationForTableLike validam antes de carregar o FileIO. O registerTable era o inconsistente. Análise completa em docs/ANALYSIS.md.

A correção, em duas partes

Caminho de tabela — commit 1dd5feeb (2026-06-02, lançado pela primeira vez na 1.6.0) adicionou uma linha no lugar certo:

root@kitploit:~
validateLocationForTableLike(identifier, metadataFileLocation, resolvedParent);

FileIO fileIO = loadFileIOForTableLike(identifier, Set.of(locationDir), ...);

Ela chegou dentro de um PR de funcionalidade ("add RegisterTable overwrite support"), não de uma correção de segurança, então a 1.6.0 entregou a correção sem nenhum advisory que a mencionasse.

Caminho de view — commit 7e822f23 ("Validate locations when registering tables and views", #5114), 2026-07-20, lançado pela primeira vez na 1.7.0, adicionou a mesma proteção ao registerView e consolidou as verificações de pós-análise para ambos os caminhos.

A 1.7.0 também traz o 85a0c292 (#4860, "Fix native catalog credential vending skipping allowedLocations re-validation"), que fecha a lacuna relacionada de defesa em profundidade: o próprio caminho de credenciais agora revalida em vez de confiar em cada chamador. Essa é a metade estrutural do problema e é mais um motivo para estar na 1.7.0 em vez da 1.6.0.

A contenção foi verificada em relação às tags de release: 1dd5feeb está na 1.6.0 e na 1.7.0; 7e822f23 e 85a0c292 estão apenas na 1.7.0.

Para quem estiver em uma linha mais antiga, ambas as mudanças são fornecidas como patches: 0001 para o caminho de tabela ≤ 1.5.0, 0002 para o caminho de view da 1.6.0.

A orientação para operadores — caminho de atualização, mitigações e como procurar exploração em logs existentes — está em docs/REMEDIATION.md.

Matriz de versões verificadas

Produzida com ./scripts/version-matrix.sh; cada linha é uma subida completa da stack e uma tentativa real de exploração. Veja docs/AFFECTED-VERSIONS.md.

A 1.4.1 importa: é a versão que corrigiu a CVE-2026-42809, o mesmo erro de validar-após-emitir no caminho stage-create. Essa correção foi limitada ao endpoint do relatório, e o padrão então se repetiu duas vezes — o register manteve o comportamento até a 1.6.0, e a nova register-view da 1.6.0 nasceu com ele.

Escopo e honestidade sobre o impacto

O que este reprodutor demonstra, e nada mais:

  • O Polaris realiza uma leitura no lado do servidor, com credenciais emitidas, de uma localização arbitrária escolhida pelo atacante, fora do limite de armazenamento declarado do catálogo — por meio de register em ≤ 1.5.0 e de register-view em 1.6.0.
  • Campos em formato de localização extraídos desse objeto são devolvidos ao chamador.
  • A existência do objeto, a existência do bucket e o tipo do objeto são observáveis em tudo o que o principal de armazenamento do catálogo consegue alcançar.

O que ele não demonstra: recuperação em massa do conteúdo completo de um objeto fora do escopo por meio da API. Duas verificações posteriores (a localização dos metadados deve estar sob a localização da tabela, e a localização analisada deve estar em allowedLocations) impedem que o registro seja concluído; portanto, o chamador recebe um oráculo mais fragmentos de metadados, não o documento inteiro. Com um override de endpoint S3 configurado no catálogo, a mesma primitiva é uma falsificação de requisição no lado do servidor contra o host configurado.

Segurança

Tudo roda localmente: um projeto Docker Compose em portas de loopback, uma instância S3 descartável (RustFS) e arquivos "vítima" sintéticos que este repositório planta por conta própria. Nenhum host externo é contatado, nenhuma credencial sai da máquina, e docker compose down -v é executado na saída, a menos que você passe --keep. Os objetos em victim-data/ são fabricados; não há dados reais em lugar nenhum aqui.

Use-o em sistemas que você possui ou está autorizado a testar.

Crédito e divulgação

Encontrada durante uma revisão da correção da CVE-2026-42809, reportada à equipe de segurança da Apache Software Foundation por meio do processo descrito no SECURITY.md do projeto e rastreada como CVE-2026-64640.

Licença

Apache License 2.0 — consulte LICENSE. O ambiente Compose é derivado do quickstart do Apache Polaris; consulte NOTICE.

Baixar ferramenta
sonda (todas fora de allowedLocations)resposta da 1.4.1
metadados Iceberg válidos, existem403 ForbiddenException + localizações analisadas ecoadas
chave ausente400 NotFoundException — Location does not exist: …
bucket não existe400 NoSuchBucketException — erro bruto do SDK S3
existe, mas não é metadado Iceberg503 RuntimeIOException — Failed to read file: …
Versãoregister (tabela)register-viewVeredito
1.3.0-incubatingvulnerávelendpoint ausentevulnerável
1.4.0vulnerávelendpoint ausentevulnerável
1.4.1vulnerávelendpoint ausentevulnerável
1.5.0vulnerávelendpoint ausentevulnerável
1.6.0validado antes da emissãovulnerávelvulnerável
1.7.0validado antes da emissãovalidado antes da emissãocorrigido