Skip to content

fix(security): escape systématique dans code-generator (CodeQL #63) - #484

Merged
bmatge merged 1 commit into
mainfrom
fix/security-xss-code-generator
Aug 19, 2026
Merged

fix(security): escape systématique dans code-generator (CodeQL #63)#484
bmatge merged 1 commit into
mainfrom
fix/security-xss-code-generator

Conversation

@bmatge

@bmatge bmatge commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Ferme l'alerte CodeQL #63

Règle : js/html-constructed-from-input (CWE-79 XSS) — medium.

Vecteur

Une source enregistrée (STORAGE_KEYS.SOURCES) avec un apiUrl bidouillé comme :

x" onerror="alert(document.cookie)

produisait un tag HTML :

<dsfr-data-source id="layer-1" url="x" onerror="alert(document.cookie)" ...>

Deux points d'impact :

  1. Immédiat : field-service.ts:145 fait host.innerHTML = tag pour scanner les champs de la source — le HTML est parsé et l'attribut event fires.
  2. En cascade utilisateur : le même HTML est produit par le bouton « Obtenir le code » — un utilisateur qui colle ce code dans son propre site propage la XSS chez lui.

CodeQL avait tracé :

  • Source : packages/shared/src/providers/index.ts:34 (input externe : registerProvider)
  • Flow via : apps/builder-carto/src/field-service.ts:145 (innerHTML)
  • Sink : apps/builder-carto/src/ui/code-generator.ts:178 (construction du template)

Fix

Helper esc() en tête de code-generator.ts (échappe &, ", <, >& en premier pour ne pas double-escape). Application à toutes les interpolations dans :

  • layerAttrs() : URLs, IDs, champs de colonnes, filtres, bornes de zoom…
  • popupTag() : mode, title-field, popup-width…
  • autoTemplateFromFields() : noms de colonnes dans le HTML et dans le mustache
  • buildSourceTag() : URLs, base-URLs, resource-IDs, dataset-IDs…
  • generateCode() : center, zoom, tiles, name, max-bounds, insets…

Bonus : attribut data='…' du mode manual échappe désormais << dans le JSON stringifié (bloque un </script> embarqué qui casserait le HTML ambiant).

Exceptions documentées

  • layer.popupTemplate reste HTML brut (mustache {{champ}} + markup DSFR libre, intentionnel — documenté dans le code).
  • L'attribut data='…' reste en single-quoted car JSON.stringify produit des " internes.

Tests

Refs

🤖 Generated with Claude Code

Ferme l'alerte CodeQL js/html-constructed-from-input (CWE-79) : un
`apiUrl` bidouillé `x" onerror="alert(1)` produisait
`url="x" onerror="alert(1)"…` — parsé et exécuté au moment où le HTML
est injecté (field-service.ts:145 `host.innerHTML = tag`), et
redistribué à l'utilisateur qui copie le code exporté dans son propre
site.

Corrections :
- Ajout d'un helper `esc()` en tête de fichier (échappe `&`, `"`, `<`,
  `>` — `&` en premier pour ne pas double-escape les entités).
- Application à TOUTES les interpolations dans `layerAttrs()`,
  `popupTag()`, `autoTemplateFromFields()`, `buildSourceTag()` et
  `generateCode()` : URLs, IDs, champs de colonnes, noms, filtres,
  bornes de zoom, etc.
- Attribut `data='…'` du mode manual : ajout d'un échappement `<` →
  `<` dans le JSON stringifié (bloque un `</script>` embarqué qui
  casserait le HTML ambiant).

Exceptions documentées :
- `layer.popupTemplate` reste HTML brut (mustache + markup DSFR libre,
  intentionnel — l'utilisateur est responsable).
- L'attribut `data` du mode manual reste en single-quoted (`'…'`) car
  JSON.stringify produit des `"` internes.

Tests : 3699/3699 verts, prettier + typecheck OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bmatge bmatge added the bug Something isn't working label Aug 19, 2026
@bmatge
bmatge merged commit 3226add into main Aug 19, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant