Rendre en sécurité les liens Markdown dans les réponses de chat IA
Sommaire
Quand un chat IA répond Voir [Services]( /services/ ), le lien peut ne pas être rendu et le Markdown brut peut rester visible.
Acecore a rencontré ce cas dans son chat de contact, puis a ajusté le renderer dans le PR de correction du rendu des liens Markdown.
Cet article part de cette petite correction pour expliquer comment convertir les réponses IA en DOM de manière sûre.
Les réponses IA ne sont pas du HTML fiable
La sortie du modèle doit être traitée comme du texte.
Les liens, le gras et les listes sont utiles dans un chat. Mais placer la réponse dans innerHTML laisse le navigateur interpréter une chaîne produite par le modèle.
Il ne faut pas forcément implémenter tout Markdown. Il faut détecter les quelques expressions supportées et créer seulement des nœuds DOM sûrs.
Le problème ne se limite pas aux espaces
Le bug direct était un lien comme :
[Services](/services/)
Une regex stricte suppose souvent que l URL ne contient pas d espace :
;/\[([^\]]+)\]\(([^)\s]+)\)/
[^)\s]+ rejette les espaces, donc ( /services/ ) n est pas reconnu. La correction consiste à tolérer les espaces dans les parenthèses puis normaliser.
;/\[([^\]]+)\]\(\s*([^)]+?)\s*\)/
Mais assouplir le parser ne suffit pas. La valeur normalisée doit ensuite être validée.
Trimmer href avant validation
L ordre doit rester clair :
- Extraire label et raw href
- Appliquer
trim()au raw href - Valider le href trimé avec une allowlist
- Créer
<a>seulement si le href est autorisé
const href = String(rawHref || '').trim()
if (label && isSafeMarkdownHref(href)) {
const link = document.createElement('a')
link.href = href
link.rel = 'noopener noreferrer'
if (/^https?:\/\//i.test(href)) {
link.target = '_blank'
}
link.textContent = label
parent.appendChild(link)
}
La valeur validée doit être la même que celle rendue dans le DOM.
La allowlist dépend du produit
Chaque site doit décider quelles URLs son IA peut afficher.
| Type | Exemple | Décision |
|---|---|---|
| Chemin interne | /services/ | Autoriser |
| Même origin | https://acecore.net/... | Autoriser |
| LINE officiel | https://lin.ee/... | Autoriser si le canal est officiel |
| mailto | mailto:[email protected] | Adresse fixe uniquement |
| tel | tel:05088902788 | Numéro fixe uniquement |
| Autres externes | Toute URL | Ne pas lier par défaut |
function isSafeMarkdownHref(href) {
if (href.startsWith('/')) return true
try {
const url = new URL(href, window.location.origin)
if (url.origin === window.location.origin) return true
if (url.hostname === 'acecore.net') return true
if (url.hostname === 'lin.ee') return true
} catch {
return false
}
return href === 'mailto:[email protected]' || href === 'tel:05088902788'
}
Un site de recrutement peut autoriser des plateformes emploi. Un SaaS peut autoriser documentation et page de statut. La fonction doit refléter le produit.
Revenir au texte pour les liens refusés
Quand un lien échoue à la validation, le supprimer n est pas toujours le meilleur choix.
Dans un chat de contact, conserver le Markdown comme texte garde le contexte pour l utilisateur et aide les développeurs à voir ce que le modèle a tenté de produire.
Le renderer doit créer des liens sûrs et échouer de façon sûre.
Tester les mauvais cas
Vérifie au minimum :
| Entrée | Résultat attendu |
|---|---|
[Services](/services/) | Lien interne |
[Services]( /services/ ) | Lien interne après trim |
[LINE]( https://lin.ee/example ) | Lien externe autorisé |
[Mauvais](javascript:alert(1)) | Pas de lien |
[Externe](https://example.com/) | Pas de lien si le domaine est refusé |
[Cassé](/services/ | Affichage comme texte |
Dans le PR #99, les variantes avec et sans espaces ont été vérifiées comme pointant vers la même URL attendue.
Ne pas implémenter tout Markdown par défaut
Pour un chat, le sous-ensemble peut rester simple :
- Paragraphes
- Listes
- Gras
- Code inline
- Liens
Tables, images, HTML brut et notes de bas de page augmentent vite le périmètre. Même avec une bibliothèque, la politique HTML et URL reste à définir séparément.
Résumé
Le rendu des liens Markdown dans une réponse IA ressemble à un détail d interface, mais il fixe la frontière de confiance envers la sortie du modèle.
La règle pratique : texte d abord, petit sous-ensemble, trim avant validation, allowlist stricte et fallback sûr.
Flux de rendu des liens
Text
Traiter la réponse du modèle comme du texte brut.
Parse
Détecter uniquement le Markdown réellement supporté par le chat.
Validate
Trimmer href et accepter seulement les URLs internes ou domaines approuvés.
Render
Créer des éléments sûrs avec DOM API, pas avec innerHTML.
Rendu trop permissif
- Mettre les réponses IA directement dans innerHTML
- Essayer de couvrir tout Markdown dès le départ
- Ne pas créer de lien quand l URL contient des espaces
- Traiter URLs externes et javascript: de la même façon
Rendu petit et sûr
- Recevoir les réponses comme texte et convertir seulement le nécessaire en DOM
- Supporter uniquement le sous-ensemble Markdown du chat
- Valider les URLs après trim
- Garder les URLs refusées comme texte
- Terminé : Ne pas faire confiance aux réponses IA comme HTML
- Terminé : Accepter les espaces autour des URLs Markdown
- Terminé : Toujours trimmer href avant validation
- Terminé : Autoriser seulement chemins internes, origin courant et domaines nécessaires
- Terminé : Définir target et rel sur les liens externes
- Terminé : Conserver les liens refusés comme texte
- Terminé : Tester les URLs dangereuses et le Markdown cassé
markdown-it ou marked suffit-il ?
Autoriser les espaces autour de l URL est-il dangereux ?
Faut-il supprimer les URLs refusées ?
Commentaires
Gui
PDG d'Acecore. Pilote les systèmes métier, le web, les bases de données et l'infrastructure, la qualité et l'adoption de l'IA, du cadrage des enjeux métier à la conception, au déploiement et à l'amélioration continue. S'appuie sur une capacité pratique en C#/.NET tout en couvrant aussi PHP/JavaScript, SQL Server/PostgreSQL/MySQL et Linux/Windows Server, afin de concevoir les besoins, les choix technologiques, les standards de qualité et les opérations de développement basées sur GitHub comme un flux cohérent. Intègre l'IA générative aux processus de développement, de vérification et d'organisation de l'information, comme une base pratique pour aider les petites équipes à livrer plus vite et plus sûrement.
Envie d'en savoir plus sur nos services ?
Nous offrons un accompagnement complet : développement de systèmes, design web, design graphique et éducation IT.
Articles connexes
Concevoir un site Astro + Cloudflare qui grandit fonctionnalité par fonctionnalité 7 juin 2026 à 19:00
Ajouter des commentaires à un blog Astro avec Cloudflare uniquement 7 juin 2026 à 18:00
Guide d'installation de Sveltia CMS 7 juin 2026 à 16:00