# Fiche — #188 · Secrets masqués : couverture universelle + clic pour copier - **Statut** : ✅ livré le 2026-10-08 (ouvert le 2026-10-08) - **Effort** : ~1 jour · **Impact** : 🟡 - **Zones** : `backend/secret_redactor.py`, `backend/render.py`, `backend/routers/files_read.py`, `frontend/js/viewer.js`, `frontend/style.css`, `frontend/locales/{fr,en}.json` ## Problème Le redacteur (`secret_redactor.py`) ne masquait que les JWT, les clés `sk-`/`pk-`/`rk-`, `AKIA…`, `ghp_…`, les connection strings et les affectations `api_key=`/`token=`/`secret=` de **20 caractères ou plus**. Résultat : la majorité des clés API réelles (Google, Slack, Stripe, GitLab, Hugging Face, npm…) et **tous les mots de passe courts** passaient en clair dans l'aperçu markdown, et un masque affiché (`[CLÉ API MASQUÉE]`) n'était pas récupérable : il fallait ouvrir la source pour relire la valeur. ## Solution 1. **Détection universelle** — une alternation unique de formats fournisseur (OpenAI/Anthropic `sk-`, Stripe `sk_live_`/`whsec_`, GitLab `glpat-`, GitHub `ghp_`/`github_pat_`, Google `AIza…`/`ya29.`, AWS `AKIA`/`ASIA`, Slack `xoxb-`, SendGrid `SG.`, Hugging Face `hf_`, npm, Docker, Resend, Square, Atlassian, Discord, Telegram, `Bearer …`) en plus des motifs déjà présents ; le plancher des affectations génériques passe de 20 à 8 caractères. 2. **Mots de passe** — motif dédié (`[MOT DE PASSE MASQUÉ]`) valable toute longueur et toute quote (`password=`, `"passwd": "…"`, `db_password=`, `passphrase=`, `mot de passe=`), qualificateur inclus. `PWD=` (dossier de travail shell) reste épargné : `pwd` n'est reconnu que qualifié. 3. **Clic → copie** — le pipeline de rendu passe par des **placeholders** (`\uE000n\uE001`) qui survivent à la conversion markdown (un `` littéral dans un bloc de code serait affiché tel quel), puis `restore_masks()` les réécrit après le rendu : - **aperçu authentifié** (`GET /api/file/…`, `click_to_copy=True`) : `[CLÉ API MASQUÉE]` — la valeur n'est jamais affichée, un clic la copie (listener délégué unique sur la zone de contenu, toast i18n FR/EN, infobulle) ; - **partages publics, exports PDF, contexte IA / MCP** : libellé seul, la valeur ne quitte pas le serveur. Les blocs `
` portant un masque ne sont pas re-colorés
   (highlight.js reconstruirait le markup et perdrait le badge).

## Hors périmètre (volontaire)

- La vue « source » (fichier brut) et les aperçus de fichiers
  **non-markdown** ne sont pas masqués : c'est le fichier lui-même qui est
  affiché, le redacteur ne s'y appliquait jamais.
- Le serveur MCP / l'assistant IA continuent de recevoir les libellés seuls
  (inchangé).

## Tests

`tests/test_api_main.py::TestSecretRedactor` : formats fournisseurs
(paramétrés), mots de passe (paramétrés), `PWD=` non masqué, round-trip
placeholder → span cliquable, rendu markdown cliquable vs libellé seul.