Aller au contenu
Acecore
Sommaire
Rendre en sécurité les liens Markdown dans les réponses de chat IA

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 :

  1. Extraire label et raw href
  2. Appliquer trim() au raw href
  3. Valider le href trimé avec une allowlist
  4. 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.

TypeExempleDécision
Chemin interne/services/Autoriser
Même originhttps://acecore.net/...Autoriser
LINE officielhttps://lin.ee/...Autoriser si le canal est officiel
mailtomailto:[email protected]Adresse fixe uniquement
teltel:05088902788Numéro fixe uniquement
Autres externesToute URLNe 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éeRé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.

Décisions à séparer

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
Checklist de mise en œuvre
  • 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é
Questions fréquentes
markdown-it ou marked suffit-il ?
Même avec une bibliothèque, il faut définir le traitement du HTML, les destinations de liens autorisées, target et rel, et le rejet des URLs dangereuses. Pour un chat, un petit renderer dédié peut suffire.
Autoriser les espaces autour de l URL est-il dangereux ?
Le risque ne vient pas des espaces, mais de ce qui est autorisé après trim. La validation du href normalisé garde la allowlist stricte.
Faut-il supprimer les URLs refusées ?
Les garder comme texte facilite souvent le debug et conserve le contexte. Une politique plus stricte peut aussi supprimer tout le lien.

Commentaires

Chargement des commentaires...

Les liens, e-mails et textes promotionnels ne peuvent pas être publiés.

G

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.

Cadrage des enjeux métierChoix technologiquesConception de systèmesC#/.NETConception bases de données/infrastructureOpérations de développement GitHubIA générativeConception de flux IAConception de la qualitéIntégration terrain

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

Rechercher des articles