Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-64640 — Reproducer for CVE-2026-64640 — Apache Polaris Iceberg REST register/register-view vends storage credentials and reads an attacker-chosen metadata location before validating allowedLocations (confused-deputy cross-tenant read). Affected ≤ 1.6.0, fixed in 1.7.0. | Kitploit
Strumenti/GitHubGitHub/oscerd/cve-2026-64640
ReconnaissanceVulnerability AnalysisExploitationWeb Application ExploitationData ExfiltrationPenetration TestingCloud SecurityAPI Security
GitHuboscerd/cve-2026-64640

CVE-2026-64640

Reproducer for CVE-2026-64640 — Apache Polaris Iceberg REST register/register-view vends storage credentials and reads an attacker-chosen metadata location before validating allowedLocations (confused-deputy cross-tenant read). Affected ≤ 1.6.0, fixed in 1.7.0.

14 giorni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi
Vedi Repository

CVE-2026-64640 — Apache Polaris: emissione di credenziali prima della validazione della location in register

Uno strumento di riproduzione autonomo, con un solo comando, per CVE-2026-64640: gli endpoint register dell'Iceberg REST in Apache Polaris generano credenziali di storage cloud per un percorso fornito dal chiamante e leggono quel percorso lato server prima di controllarlo rispetto agli allowedLocations del catalogo.

Un principal il cui unico privilegio è creare tabelle nel proprio catalogo può far sì che Polaris usi le credenziali di storage del catalogo per leggere oggetti che il catalogo non avrebbe mai dovuto toccare — il prefisso di un altro tenant, un altro bucket, qualsiasi cosa raggiungibile dal principal di storage.

CVECVE-2026-64640
Componentepolaris-runtime-service — IcebergCatalog / LocalIcebergCatalog: registerTable, registerView
EndpointPOST /api/catalog/v1/{prefix}/namespaces/{namespace}/register
POST /api/catalog/v1/{prefix}/namespaces/{namespace}/register-view (1.6.0+)
CWECWE-441 (confused deputy), CWE-639 (authorization bypass through user-controlled key), CWE-918 (SSRF)
GravitàAlta — CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N (8.1)
Versioni affette≤ 1.6.0 (verificato su 1.3.0-incubating, 1.4.0, 1.4.1, 1.5.0, 1.6.0)
Corretto in1.7.0 — la 1.6.0 corregge solo il percorso delle tabelle e reintroduce il difetto nel nuovo percorso delle viste
Privilegio richiestoun principal autenticato con TABLE_CREATE / CATALOG_MANAGE_CONTENT su qualsiasi catalogo — nessun admin

La 1.6.0 non è una correzione. Chiude register (incidentalmente, dentro una PR di funzionalità) e introduce il nuovo endpoint register-view con lo stesso errore di ordinamento. Lo strumento di riproduzione dimostra entrambe le metà. Aggiornare alla 1.7.0.

Esecuzione

Requisiti: Docker con il plugin Compose v2, curl, python3, bash. Nient'altro — l'ambiente è costruito da immagini pubblicate e smantellato al termine.

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

Il codice di uscita 0 significa che la vulnerabilità è stata riprodotta, 1 che non lo è stata, 2 che l'ambiente non è riuscito ad avviarsi. Ogni richiesta e risposta viene scritta in evidence/<timestamp>-polaris-<tag>/.

Com'è fatto l'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

L'ultima riga è la parte realistica. Gli operatori delimitano un catalogo con allowedLocations; il ruolo IAM sottostante è quasi sempre più ampio di un singolo prefisso. allowedLocations è il muro. Questo bug lo aggira.

Cosa dimostra

Test 0 — il muro è reale. La creazione di una tabella con una location esplicita in s3://tenant-b-private viene rifiutata con 403 ForbiddenException, prima che venga letta qualsiasi cosa. Polaris sa perfettamente che la location è fuori dai limiti.

Test 1 — register la legge comunque. Lo stesso principal punta register a s3://tenant-b-private/sales/metadata/00007-tenant-b-sales.metadata.json. La risposta è anch'essa un 403 — ma cita s3://tenant-b-private/warehouse/CANARY-64640-4f1c9e2a-tenant-b-sales, una stringa che esiste solo all'interno del corpo di quell'oggetto:

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}}

La richiesta non menziona mai warehouse/. Polaris può produrre quelle stringhe solo recuperando e analizzando l'oggetto con le credenziali del catalogo. Il 403 è Polaris che intercetta la violazione un passo dopo la lettura che avrebbe dovuto impedire.

Test 2 — cosa torna indietro. Due campi distinti estratti dal documento della vittima vengono restituiti al chiamante: la location dichiarata della tabella e la sua proprietà write.data.path.

Test 3 — un oracolo di enumerazione dello storage. La stessa chiamata risponde in modo diverso per ogni stato di un target esterno agli allowedLocations:

Quattro risposte distinguibili significano quattro informazioni sullo storage che il chiamante non ha il diritto di apprendere. Su AWS reale la sonda sull'esistenza del bucket raggiunge lo spazio dei nomi globale dei bucket S3, usando le credenziali del catalogo.

Su una build corretta ogni riga di quella tabella è lo stesso 403 che nomina solo il percorso richiesto, e nulla dall'interno dell'oggetto torna indietro — lo script rileva quella firma e riporta NOT VULNERABLE — pre-validation observed.

Test 4 — lo stesso difetto su register-view. Polaris 1.6.0 ha aggiunto POST .../namespaces/{ns}/register-view, che raggiunge registerView, il quale carica la FileIO e analizza il documento del chiamante senza alcuna validazione preliminare — esattamente ciò che registerTable aveva appena smesso di fare. Sulla 1.6.0 il canary della vista torna:

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}}

Quindi un'installazione 1.6.0 è ancora esposta, attraverso un endpoint diverso, alla stessa primitiva. Sulla 1.4.1 e precedenti l'endpoint non esiste e lo script lo segnala.

Causa principale

IcebergCatalog.registerTable (LocalIcebergCatalog dalla 1.6.0), prima della correzione — registerView ha la forma identica:

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

La catena di emissione (loadFileIOForTableLike → StorageAccessConfigProvider.getStorageAccessConfig → *StorageIntegration.getSubscopedCreds) non esegue alcun controllo su allowedLocations per conto proprio, quindi l'unica verifica è quella al momento del commit — e a quel punto la lettura privilegiata è già avvenuta e il suo risultato è nella risposta.

I percorsi gemelli nello stesso file hanno l'ordine giusto: la creazione di viste e sendNotificationForTableLike validano entrambi prima di caricare la FileIO. registerTable era quello incoerente. Analisi completa in docs/ANALYSIS.md.

La correzione, in due parti

Percorso tabelle — commit 1dd5feeb (2026-06-02, pubblicata per la prima volta nella 1.6.0) ha aggiunto una riga nel punto giusto:

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

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

È arrivata all'interno di una PR di funzionalità ("add RegisterTable overwrite support"), non di una correzione di sicurezza, quindi la 1.6.0 ha distribuito la correzione senza alcun advisory che la nominasse.

Percorso viste — commit 7e822f23 ("Validate locations when registering tables and views", #5114), 2026-07-20, pubblicata per la prima volta nella 1.7.0, ha aggiunto la stessa guardia a registerView e ha consolidato i controlli post-analisi per entrambi i percorsi.

La 1.7.0 include anche 85a0c292 (#4860, "Fix native catalog credential vending skipping allowedLocations re-validation"), che chiude il relativo gap di difesa in profondità: il percorso delle credenziali stesso ora rivalida invece di fidarsi di ogni chiamante. Questa è la metà strutturale del problema, ed è un altro motivo per cui la 1.7.0, e non la 1.6.0, è la release su cui stare.

Il contenimento è stato verificato sui tag di release: 1dd5feeb è nella 1.6.0 e nella 1.7.0; 7e822f23 e 85a0c292 sono solo nella 1.7.0.

Per chi è vincolato a una linea più vecchia, entrambe le modifiche sono fornite come patch: 0001 per il percorso tabelle ≤ 1.5.0, 0002 per il percorso viste della 1.6.0.

Linee guida per gli operatori — percorso di aggiornamento, mitigazioni e come cercare segni di sfruttamento nei log esistenti — sono in docs/REMEDIATION.md.

Matrice delle versioni verificata

Prodotta con ./scripts/version-matrix.sh; ogni riga è un avvio completo dello stack e un tentativo di exploit dal vivo. Vedi docs/AFFECTED-VERSIONS.md.

La 1.4.1 è importante: è la release che ha corretto CVE-2026-42809, lo stesso errore "valida dopo l'emissione" nel percorso stage-create. Quella correzione era limitata all'endpoint del report, e poi il pattern si è ripetuto due volte — register ha mantenuto il comportamento fino alla 1.6.0, e la nuova register-view della 1.6.0 è nata con esso.

Ambito e onestà sull'impatto

Ciò che questo strumento di riproduzione dimostra, e nulla di più:

  • Polaris esegue una lettura lato server, con credenziali emesse, di una location arbitraria scelta dall'attaccante, al di fuori del confine di storage dichiarato del catalogo — tramite register su ≤ 1.5.0 e tramite register-view sulla 1.6.0.
  • I campi di tipo location estratti da quell'oggetto vengono restituiti al chiamante.
  • L'esistenza dell'oggetto, l'esistenza del bucket e il tipo di oggetto sono osservabili su tutto ciò che il principal di storage del catalogo può raggiungere.

Ciò che non dimostra: il recupero in blocco del contenuto completo di un oggetto fuori ambito tramite l'API. Due controlli successivi (la metadata-location deve trovarsi sotto la location della tabella, e la location analizzata deve essere negli allowedLocations) impediscono alla registrazione di completarsi, quindi il chiamante ottiene un oracolo più frammenti di metadati, non l'intero documento. Con un override dell'endpoint S3 configurato sul catalogo, la stessa primitiva è una falsificazione di richieste lato server contro l'host configurato.

Sicurezza

Tutto viene eseguito in locale: un progetto Docker Compose su porte di loopback, un'istanza S3 monouso (RustFS) e file "vittima" sintetici che questo repository crea da sé. Non viene contattato alcun host esterno, nessuna credenziale lascia la macchina, e docker compose down -v viene eseguito all'uscita a meno che non si passi --keep. Gli oggetti victim-data/ sono fabbricati; non ci sono dati reali da nessuna parte qui.

Usalo su sistemi di tua proprietà o che sei autorizzato a testare.

Crediti e divulgazione

Trovato durante una revisione della correzione di CVE-2026-42809, segnalato al team di sicurezza dell'Apache Software Foundation tramite la procedura descritta nel SECURITY.md del progetto, e tracciato come CVE-2026-64640.

Licenza

Apache License 2.0 — vedi LICENSE. L'ambiente Compose deriva dalla quickstart di Apache Polaris; vedi NOTICE.

Scarica lo strumento
probe (tutti fuori dagli allowedLocations)risposta 1.4.1
metadati Iceberg validi, esistenti403 ForbiddenException + location analizzate restituite
chiave mancante400 NotFoundException — Location does not exist: …
bucket inesistente400 NoSuchBucketException — errore S3 SDK grezzo
esiste ma non è metadati Iceberg503 RuntimeIOException — Failed to read file: …
Releaseregister (tabella)register-viewVerdetto
1.3.0-incubatingvulnerabileendpoint assentevulnerabile
1.4.0vulnerabileendpoint assentevulnerabile
1.4.1vulnerabileendpoint assentevulnerabile
1.5.0vulnerabileendpoint assentevulnerabile
1.6.0validato prima dell'emissionevulnerabilevulnerabile
1.7.0validato prima dell'emissionevalidato prima dell'emissionecorretto