Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
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
Outils/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.

il y a 14 joursPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Voir le dépôt
Partager

CVE-2026-64640 — Apache Polaris : délivrance d'identifiants avant validation de l'emplacement dans register

Un reproducteur autonome, en une commande, pour CVE-2026-64640 : les points de terminaison register de l'API REST Iceberg dans Apache Polaris génèrent des identifiants de stockage cloud pour un chemin fourni par l'appelant et lisent ce chemin côté serveur avant de le vérifier par rapport aux allowedLocations du catalogue.

Un principal dont le seul privilège est de créer des tables dans son propre catalogue peut amener Polaris à utiliser les identifiants de stockage du catalogue pour lire des objets que le catalogue n'a jamais été autorisé à toucher — le préfixe d'un autre locataire, un autre bucket, tout ce que le principal de stockage peut atteindre.

CVECVE-2026-64640
Composantpolaris-runtime-service — IcebergCatalog / LocalIcebergCatalog : registerTable, registerView
Points de terminaisonPOST /api/catalog/v1/{prefix}/namespaces/{namespace}/register
POST /api/catalog/v1/{prefix}/namespaces/{namespace}/register-view (1.6.0+)
CWECWE-441 (député confus), CWE-639 (contournement d'autorisation via une clé contrôlée par l'utilisateur), CWE-918 (SSRF)
SévéritéÉlevée — CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N (8.1)
Versions affectées≤ 1.6.0 (vérifié sur 1.3.0-incubating, 1.4.0, 1.4.1, 1.5.0, 1.6.0)
Corrigé dans1.7.0 — 1.6.0 ne corrige que le chemin table et réintroduit la faille sur le nouveau chemin vue
Privilège requisun principal authentifié disposant de TABLE_CREATE / CATALOG_MANAGE_CONTENT sur n'importe quel catalogue — pas d'administrateur

1.6.0 n'est pas un correctif. Il ferme register (au passage, dans une PR de fonctionnalité) et livre le tout nouveau point de terminaison register-view avec la même erreur d'ordre. Le reproducteur prouve les deux moitiés. Passez à 1.7.0.

Exécution

Prérequis : Docker avec le plugin Compose v2, curl, python3, bash. Rien d'autre — l'environnement est construit à partir d'images publiées puis détruit ensuite.

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

Le code de sortie 0 signifie que la vulnérabilité a été reproduite, 1 qu'elle ne l'a pas été, 2 que l'environnement n'a pas pu démarrer. Chaque requête et réponse est écrite dans evidence/<timestamp>-polaris-<tag>/.

À quoi ressemble l'environnement

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

Cette dernière ligne est la partie réaliste. Les opérateurs délimitent un catalogue avec allowedLocations ; le rôle IAM sous-jacent est presque toujours plus large qu'un seul préfixe. allowedLocations est le mur. Ce bug le contourne.

Ce que cela prouve

Test 0 — le mur est réel. La création d'une table avec un emplacement explicite dans s3://tenant-b-private est refusée avec 403 ForbiddenException, avant que quoi que ce soit ne soit lu. Polaris sait parfaitement que l'emplacement est hors limites.

Test 1 — register le lit quand même. Le même principal pointe register vers s3://tenant-b-private/sales/metadata/00007-tenant-b-sales.metadata.json. La réponse est aussi une 403 — mais elle cite s3://tenant-b-private/warehouse/CANARY-64640-4f1c9e2a-tenant-b-sales, une chaîne qui existe uniquement dans le corps de cet objet :

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 requête ne mentionne jamais warehouse/. Polaris ne pouvait produire ces chaînes qu'en récupérant et en analysant l'objet avec les identifiants du catalogue. La 403 est Polaris qui détecte la violation une étape après la lecture qu'elle était censée empêcher.

Test 2 — ce qui revient. Deux champs distincts extraits du document victime sont renvoyés à l'appelant : la location déclarée de la table et sa propriété write.data.path.

Test 3 — un oracle d'énumération de stockage. Le même appel répond différemment pour chaque état d'une cible hors de allowedLocations :

Quatre réponses distinguables signifient quatre faits sur le stockage que l'appelant n'a pas le droit d'apprendre. Sur un AWS réel, la sonde d'existence de bucket atteint l'espace de noms global des buckets S3, en utilisant les identifiants du catalogue.

Sur une version corrigée, chaque ligne de ce tableau est la même 403 ne mentionnant que le chemin demandé, et rien ne revient de l'intérieur de l'objet — le script détecte cette signature et rapporte NOT VULNERABLE — pre-validation observed.

Test 4 — la même faille sur register-view. Polaris 1.6.0 a ajouté POST .../namespaces/{ns}/register-view, atteignant registerView, qui charge le FileIO et analyse le document de l'appelant sans validation préalable — précisément ce que registerTable venait de cesser de faire. Sur 1.6.0, le canari de vue revient :

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

Une installation 1.6.0 est donc toujours exposée, via un point de terminaison différent, à la même primitive. Sur 1.4.1 et antérieurs, le point de terminaison n'existe pas et le script le signale.

Cause racine

IcebergCatalog.registerTable (LocalIcebergCatalog à partir de 1.6.0), avant le correctif — registerView a la forme identique :

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 chaîne de délivrance (loadFileIOForTableLike → StorageAccessConfigProvider.getStorageAccessConfig → *StorageIntegration.getSubscopedCreds) n'effectue aucun contrôle allowedLocations qui lui soit propre, si bien que la seule application est celle au moment du commit — et à ce stade, la lecture privilégiée a déjà eu lieu et son résultat est dans la réponse.

Les chemins frères dans le même fichier font les choses dans le bon ordre : la création de vue et sendNotificationForTableLike valident toutes deux avant de charger le FileIO. registerTable était celui qui était incohérent. Analyse détaillée dans docs/ANALYSIS.md.

Le correctif, en deux parties

Chemin table — commit 1dd5feeb (2026-06-02, publié pour la première fois dans 1.6.0) a ajouté une ligne au bon endroit :

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

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

Il est arrivé dans une PR de fonctionnalité (« add RegisterTable overwrite support »), pas dans un correctif de sécurité, si bien que 1.6.0 a livré la correction sans qu'aucun avis de sécurité la mentionne.

Chemin vue — commit 7e822f23 (« Validate locations when registering tables and views », #5114), 2026-07-20, publié pour la première fois dans 1.7.0, a ajouté la même protection à registerView et consolidé les vérifications post-analyse pour les deux chemins.

1.7.0 contient également 85a0c292 (#4860, « Fix native catalog credential vending skipping allowedLocations re-validation »), qui comble la lacune de défense en profondeur associée : le chemin des identifiants lui-même revalide désormais au lieu de faire confiance à chaque appelant. C'est la moitié structurelle du problème, et c'est une raison de plus pour être sur 1.7.0 plutôt que sur 1.6.0.

La présence des correctifs a été vérifiée par rapport aux tags de version : 1dd5feeb est dans 1.6.0 et 1.7.0 ; 7e822f23 et 85a0c292 sont uniquement dans 1.7.0.

Pour quiconque est resté sur une ancienne ligne de version, les deux modifications sont fournies sous forme de correctifs : 0001 pour le chemin table ≤ 1.5.0, 0002 pour le chemin vue 1.6.0.

Les recommandations aux opérateurs — parcours de mise à niveau, mesures d'atténuation et comment rechercher une exploitation dans les journaux existants — se trouvent dans docs/REMEDIATION.md.

Matrice des versions vérifiées

Produite avec ./scripts/version-matrix.sh ; chaque ligne est un démarrage complet de la pile et une tentative d'exploitation réelle. Voir docs/AFFECTED-VERSIONS.md.

1.4.1 compte : c'est la version qui a corrigé CVE-2026-42809, la même erreur de validation après délivrance dans le chemin stage-create. Ce correctif était limité au point de terminaison mentionné dans le rapport, et le schéma s'est ensuite reproduit deux fois — register a conservé ce comportement jusqu'à 1.6.0, et le nouveau register-view de 1.6.0 est né avec ce comportement.

Périmètre et transparence sur l'impact

Ce que ce reproducteur démontre, et rien de plus :

  • Polaris effectue une lecture côté serveur avec des identifiants délivrés d'un emplacement arbitraire choisi par l'attaquant, en dehors de la limite de stockage déclarée du catalogue — via register sur ≤ 1.5.0 et via register-view sur 1.6.0.
  • Les champs de type emplacement extraits de cet objet sont renvoyés à l'appelant.
  • L'existence d'objets, l'existence de buckets et le type d'objet sont observables sur tout ce que le principal de stockage du catalogue peut atteindre.

Ce qu'il ne démontre pas : la récupération en masse du contenu complet d'un objet hors périmètre via l'API. Deux vérifications ultérieures (l'emplacement des métadonnées doit se trouver sous l'emplacement de la table, et l'emplacement analysé doit être dans allowedLocations) empêchent l'enregistrement d'aboutir, si bien que l'appelant obtient un oracle ainsi que des fragments de métadonnées, et non le document entier. Avec une surcharge de point de terminaison S3 configurée sur le catalogue, la même primitive est une falsification de requête côté serveur contre l'hôte configuré.

Sûreté

Tout s'exécute en local : un projet Docker Compose sur des ports de loopback, une instance S3 jetable (RustFS), et des fichiers « victime » synthétiques que ce dépôt installe lui-même. Aucun hôte externe n'est contacté, aucun identifiant ne quitte la machine, et docker compose down -v s'exécute à la sortie, sauf si vous passez --keep. Les objets victim-data/ sont fabriqués ; il n'y a aucune donnée réelle nulle part ici.

Utilisez-le sur des systèmes que vous possédez ou que vous êtes autorisé à tester.

Crédit et divulgation

Découverte lors d'une revue du correctif de CVE-2026-42809, signalée à l'équipe de sécurité de l'Apache Software Foundation via la procédure décrite dans le SECURITY.md du projet, et suivie sous la référence CVE-2026-64640.

Licence

Licence Apache 2.0 — voir LICENSE. L'environnement Compose est dérivé du guide de démarrage rapide d'Apache Polaris ; voir NOTICE.

Télécharger l’outil
sonde (toutes hors allowedLocations)réponse 1.4.1
métadonnées Iceberg valides, existantes403 ForbiddenException + emplacements analysés renvoyés
clé manquante400 NotFoundException — Location does not exist: …
bucket inexistant400 NoSuchBucketException — erreur brute du SDK S3
existe mais n'est pas de la métadonnée Iceberg503 RuntimeIOException — Failed to read file: …
Versionregister (table)register-viewVerdict
1.3.0-incubatingvulnérablepoint de terminaison absentvulnérable
1.4.0vulnérablepoint de terminaison absentvulnérable
1.4.1vulnérablepoint de terminaison absentvulnérable
1.5.0vulnérablepoint de terminaison absentvulnérable
1.6.0validation avant délivrancevulnérablevulnérable
1.7.0validation avant délivrancevalidation avant délivrancecorrigé