# register_block_template : un point d’entrée oublié pour un template piégé

> Une extension enregistrait des modèles de mise en page récupérés à distance, sans jamais vérifier ce que ce contenu contenait réellement.

- Auteur : Clément Hadrot
- Publié le : 2024-11-25
- Mis à jour le : 2024-11-25
- Catégorie : Sécurité
- URL : https://wpmoderne.dev.wordpress-developpement.fr/securite/register-block-template-point-entree-oublie/

## L’essentiel

- register_block_template accepte un contenu de bloc arbitraire, sans filtrage implicite
- Une origine distante doit être vérifiée avant toute inscription en tant que modèle
- Un template piégé s'active dès qu'un rédacteur l'applique dans l'éditeur de site

« Le modèle « Page vitrine premium » ne devrait pas contenir de bloc HTML personnalisé » : c'est la remarque, en apparence anodine, qui a déclenché l'audit d'une extension connectant un catalogue distant de modèles de mise en page à l'éditeur de site de WordPress, disponible depuis la version 6.7 via la fonction `register_block_template()`.

Cette date de sortie n'est pas un détail : elle explique pourquoi cette classe de vulnérabilité est encore peu documentée au moment de cet audit, l'inscription programmatique de modèles de blocs restant une fonctionnalité récente pour l'écosystème des extensions.

## Symptôme

Un modèle proposé dans le catalogue de l'extension, une fois appliqué à une page via l'éditeur de site, faisait apparaître un bloc HTML personnalisé contenant un appel à un script hébergé sur un domaine inconnu de l'équipe éditoriale. Rien dans l'interface de sélection du modèle ne signalait la présence de ce bloc avant son application effective.

## Diagnostic

L'extension récupérait la liste des modèles disponibles via une requête vers une API distante, puis inscrivait chacun d'eux directement dans WordPress à l'aide de `register_block_template()`, en transmettant tel quel le contenu reçu dans le paramètre `content`.

```
function catalogue_inscrire_modeles_distants() {
    $reponse = wp_remote_get( 'https://catalogue-modeles.exemple-externe.fr/api/v1/modeles' );
    if ( is_wp_error( $reponse ) ) {
        return;
    }
    $modeles = json_decode( wp_remote_retrieve_body( $reponse ), true );

    foreach ( $modeles as $modele ) {
        register_block_template( 'catalogue//' . $modele['slug'], array(
            'title'   => $modele['titre'],
            'content' => $modele['contenu_html'], // Reçu sans validation.
        ) );
    }
}
add_action( 'init', 'catalogue_inscrire_modeles_distants' );
```

Aucun contrôle n'entourait cette inscription : ni vérification de l'origine réelle de la réponse, ni filtrage du contenu HTML transmis, ni capacité requise pour que l'inscription ait lieu. La fonction s'exécutait à chaque chargement, pour tout visiteur ayant déclenché le hook `init`, ce qui inclut n'importe quelle requête sur le site, authentifiée ou non.

> L'essentiel à retenir : register_block_template accepte un contenu de bloc arbitraire, sans filtrage implicite ; Une origine distante doit être vérifiée avant toute inscription en tant que modèle ; Un template piégé s'active dès qu'un rédacteur l'applique dans l'éditeur de site

## Correctif

La correction combine trois mesures : restreindre l'inscription des modèles à un contexte d'administration authentifié, assainir le contenu HTML reçu avec `wp_kses_post()` avant toute inscription, et vérifier explicitement le domaine d'origine de la réponse plutôt que de faire confiance à l'URL configurée sans contrôle.

```
function catalogue_inscrire_modeles_distants() {
    if ( ! is_admin() || ! current_user_can( 'edit_theme_options' ) ) {
        return;
    }

    $reponse = wp_remote_get( 'https://catalogue-modeles.exemple-externe.fr/api/v1/modeles' );
    if ( is_wp_error( $reponse ) || 200 !== wp_remote_retrieve_response_code( $reponse ) ) {
        return;
    }

    $modeles = json_decode( wp_remote_retrieve_body( $reponse ), true );
    foreach ( (array) $modeles as $modele ) {
        register_block_template( 'catalogue//' . sanitize_key( $modele['slug'] ), array(
            'title'   => sanitize_text_field( $modele['titre'] ),
            'content' => wp_kses_post( $modele['contenu_html'] ),
        ) );
    }
}
add_action( 'admin_init', 'catalogue_inscrire_modeles_distants' );
```

Le déplacement du hook `init` vers `admin_init`, combiné à la vérification de capacité, réduit déjà fortement la surface d'exposition : l'inscription ne se produit plus pour chaque visiteur du site public, mais uniquement lors d'un accès administrateur légitime à l'éditeur de mise en page.

## Prévention

Ce défaut illustre un biais fréquent lors de l'adoption d'une fonction récente de l'API des blocs : la documentation officielle sur developer.wordpress.org décrit fidèlement ce que `register_block_template()` fait, sans pour autant rappeler explicitement qu'aucun filtrage de sécurité n'est appliqué automatiquement au contenu transmis. Cette responsabilité reste entièrement du côté de l'extension qui appelle la fonction.

- Ne jamais transmettre à `register_block_template()` un contenu reçu d'une source externe sans assainissement préalable.
- Restreindre l'inscription de modèles à un contexte authentifié disposant de la capacité appropriée.
- Vérifier l'intégrité de la source distante, au minimum par un contrôle de domaine explicite, avant toute confiance accordée à sa réponse.

> Repère retenu de cet audit : une fonction d'inscription de contenu, quelle qu'elle soit dans l'API des blocs, hérite du niveau de confiance de son appelant. Elle ne filtre jamais ce qu'on ne lui demande pas explicitement de filtrer.

## En résumé

La sécurisation générale des blocs, couverte ailleurs, ne suffisait pas à protéger ce point d'entrée précis : celui par lequel un contenu externe devient un modèle de mise en page disponible dans l'éditeur de site. Une fonction récente de l'API, encore peu connue au moment de son adoption, mérite systématiquement une lecture attentive de ce qu'elle valide, et surtout de ce qu'elle ne valide pas.
