From 4a668c8c10a441cffa6b56367f9fb941dd6f2b85 Mon Sep 17 00:00:00 2001 From: Robin Lopez Date: Thu, 27 Aug 2026 11:25:12 +0200 Subject: [PATCH 1/3] fix(security): FSHSP-177 sanitize inlined SVG and forbid Angular bypass APIs --- CHANGELOG.md | 8 + SECURITY.md | 4 + docs/SECURITY-PRACTICES.md | 248 ++++++++++++++++++ eslint.config.js | 60 ++++- .../ui-image/src/lib/ui-image-svg.spec.ts | 94 +++++++ .../base/ui-image/src/lib/ui-image-svg.ts | 78 ++++++ .../base/ui-image/src/lib/ui-image.html | 10 + .../ui-kit/base/ui-image/src/lib/ui-image.ts | 47 +++- projects/ui-kit/base/ui-image/ui-image.mdx | 24 +- .../ui-editor/src/lib/ui-editor-commands.ts | 7 + .../forms/ui-editor/src/lib/ui-editor.ts | 6 + .../forms/ui-editor/ui-editor.stories.ts | 2 +- .../ui-tooltip/src/lib/ui-tooltip-panel.html | 1 + 13 files changed, 577 insertions(+), 12 deletions(-) create mode 100644 docs/SECURITY-PRACTICES.md create mode 100644 projects/ui-kit/base/ui-image/src/lib/ui-image-svg.spec.ts create mode 100644 projects/ui-kit/base/ui-image/src/lib/ui-image-svg.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d9133c8..2fdedaa1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,10 @@ Le format suit [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/) et le pr ### Changed +- **`ng add @4sh/ui-kit-schematics` écrit les commandes du gestionnaire de paquets du projet, plus `npm run` en dur** (FSHSP-177). Les scripts posés dans le `package.json` du consommateur (`storybook`, `build-storybook`, le hook `postinstall`) et la commande de démarrage affichée en fin d'installation nommaient `npm run` quel que soit le projet. Dans un projet pnpm ou yarn, ces scripts fonctionnaient — npm est toujours présent — mais contournaient le lockfile et faisaient apparaître un `package-lock.json` parasite au premier lancement. Le gestionnaire est désormais déduit du champ `packageManager` puis, à défaut, du lockfile présent, dans le même ordre de précédence que le CLI Angular (pnpm, yarn, bun, npm). L'**installation** des dépendances, elle, était déjà correcte : le CLI Angular transmet le gestionnaire qu'il détecte à `NodePackageInstallTask`. +- **Les scripts de la chaîne de doc copiés chez le consommateur nomment son gestionnaire dans leurs messages d'erreur** (FSHSP-177). `docs.config.mjs` et `docs.search.mjs` conseillaient « lance `npm run docs:config` » ; ils lisent maintenant `npm_config_user_agent` (renseigné par npm, pnpm, yarn et bun) et affichent une commande copiable telle quelle. Les messages rendus **dans le navigateur** (table `ConfigTable`, addons de recherche), qui n'ont pas accès à cette information, nomment désormais le script seul plutôt qu'un client. +- **`projects/ui-kit/README.md` (EN/FR) mène l'installation avec `pnpm add`** (FSHSP-177), en précisant que npm et yarn installent exactement la même chose — le package reste un tarball npm standard. C'est le fichier affiché sur npmjs.com. + - **`ui-datepicker` : la plage sélectionnée (`range`) se lit comme une seule zone continue** (FSHSP-166). Elle était peinte sur la cellule elle-même — fond en dégradé mi-cellule sur les deux extrémités, filets haut et bas en bordure — ce qui la faisait _encadrer_ la sélection plutôt que la porter, avec deux débordements visibles : les filets couraient sur toute la largeur des cellules de début et de fin, donc au-delà de la moitié réellement remplie, et la pastille des jours de début/fin, dont la bordure transparente s'ajoutait à sa taille (`content-box`), dépassait la hauteur de la bande. La bande est désormais une couche à part, exactement de la hauteur d'une pastille et arrêtée au centre des deux extrémités : plus rien ne peut la dépasser, ni en hauteur ni sur les côtés. Les filets sont retirés, et seuls les deux bouts d'une ligne de semaine sont arrondis — sur le retrait qu'une pastille laisse dans sa colonne, pas sur le bord de la cellule, pour qu'une plage finissant sur la dernière colonne s'aligne avec la rangée du dessus au lieu de s'arrêter une demi-gouttière trop tôt. Et une date de début dont la fin n'est pas encore choisie n'affiche plus de demi-bande partant vers une extrémité qui n'existe pas : la pastille reste seule jusqu'au second clic. Deux nouveaux réglages, `--ui-datepicker-range-background` et `--ui-datepicker-range-color`, permettent de re-skinner la bande et le chiffre qu'elle porte (voir la table « Theming » de la doc). - **La boîte de `ui-field` est désormais enveloppée dans un `.ui-field-control`** (FSHSP-157). C'est le contexte de positionnement du libellé flottant, et il est rendu dans les deux modes plutôt que conditionnellement, pour que le DOM d'un champ ne dépende pas de l'option. Aucun impact visuel ni sur les sélecteurs publics ; un consommateur qui aurait écrit du CSS sur l'enchaînement direct `.ui-field > .ui-field-box` doit passer par le descendant. @@ -82,6 +86,10 @@ Le format suit [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/) et le pr ### Fixed +- **`ui-image` inlinait les SVG locaux sans les assainir** (FSHSP-177). Le composant est le seul du kit à lever un `bypassSecurityTrustHtml()` — inévitable, puisque l'assainisseur d'Angular supprime `` en entier et que l'inline est ce qui permet à l'asset d'hériter du CSS (`currentColor`, tokens de thème). Mais la réponse HTTP y était passée **telle quelle** : un SVG servi depuis `assets/img/` exécutait son propre JavaScript dans l'origine de l'application. Vérifié dans un navigateur réel : un `` glissé dans un `` s'exécutait **sans aucune interaction**, et les attributs `onload`/`onclick`/`onerror` survivaient dans le DOM. Le markup passe désormais par un scrub explicite (`sanitizeInlineSvg`) avant le bypass : `script`, `foreignObject`, `iframe`, `object`, `embed` et les éléments SMIL (`animate`, `animateTransform`, `animateMotion`, `set`, `handler`) sont retirés **avec leur contenu** ; tout attribut `on…` est supprimé ; `href`/`xlink:href`/`src` sont réduits à une référence intra-document (`#id`) ou à une URL `http(s)`, ce qui écarte `javascript:` et `data:`. Le parsing a lieu dans un `