Audit web France
Revue factuelle d'un site ou d'une app destinés au public français: bugs, pentest limité (surface / debug / hygiène), identification, RGPD, cookies, conso, accessibilité, SEO technique. Ce n'est pas un avis juridique, pas un test d'intrusion PASSI, et pas un audit de ranking. Chaque constat a une preuve (URL, en-tête, extrait, capture) et un texte de référence. Pas de preuve = pas de constat, ou statut non verifie.
Cadre et sources: references/cadre-legal.md. Sécu: references/pentest-limite.md. SEO: references/seo.md. URLs relues: references/sources.md. Grille: references/grille.md. Rapport: templates/rapport.md.
When to Use
- Review d'un site avant livraison ou mise en ligne.
- Audit global: bugs, pentest limité, RGPD, mentions, cookies, accessibilité, SEO technique.
- Contrôle ciblé: page légale, bandeau cookies, formulaire, surface sécu / debug, indexation.
Don't use for: avis juridique opposable; pentest avec exploitation, payload, fuzz, brute-force; prestation PASSI; promesse de position / trafic; revue de code interne sans URL publique ou de préprod.
Prerequisites
- URL publique, ou dépôt + URL de préprod. Sans cible, s'arrêter.
- Classer l'acteur avant de cocher la grille: association, EI, société, e-commerce B2C, service public, plateforme.
- Outils:
python3 (stdlib), un GET HTTP. Navigateur si disponible. Sans navigateur, le sondage HTTP reste valable et le JS n'est pas observé.
- Ne jamais coller mot de passe, cookie de session, ni clé dans le rapport.
How to Run
python3 skills/audit-fr/scripts/probe.py "https://exemple.fr" -o ./audit-probe.json
Puis suivre la Procedure. Rapport dans ./audit-fr-<slug>-<date>.md.
Quick Reference
| Action |
Commande |
| Surface HTTP / TLS / cookies / liens légaux / chemins connus / SEO |
python3 skills/audit-fr/scripts/probe.py URL -o probe.json |
| Accueil seulement (pas de liste de chemins) |
python3 skills/audit-fr/scripts/probe.py URL --no-surface |
| Relire un certificat / proto TLS |
probe.json → tls (protocol, legacy_accepted, days_left) |
| Relire fuites / surface |
probe.json → leaks, surface, http_upgrade |
| Relire SEO |
probe.json → seo (title, canonical, robots, sitemap, hreflang, flags) |
| Tests offline du sondeur |
python3 skills/audit-fr/scripts/test_probe.py |
Procedure
1. Cadrer
Noter: URL, repo s'il est fourni, date UTC, acteur, ce qui est en ligne vs en préprod. Activer seulement les modules de la grille qui s'appliquent (une asso vitrine n'a pas de CGV B2C; un e-commerce si).
Fait quand: le rapport a une ligne Acteur + Modules actifs, sans module hors champ coché comme échec.
2. Sonder la surface
Lancer probe.py sur l'accueil, puis sur /mentions-legales, /politique-de-confidentialite (et variantes: /legal, /privacy, /cookies, /cgv, /accessibilite). Suivre la chaîne de redirects. Recouper un 403 / timeout avant d'écrire « down ».
Fait quand: probe.json existe et chaque URL sondée a un code final.
3. Identifier et pages légales
Contrôler accessibilité permanente (lien footer ou équivalent sur l'accueil) et le contenu attendu pour l'acteur. Source de vérité: LCEN art. 1-1 / 1-2 (Légifrance). F37351 / F31228 listent encore l'ancien art. 6: utiles pour la liste, pas pour le numéro. Exiger le directeur de la publication (1-1, I, 3°). Détail dans la grille module C.
Fait quand: chaque mention obligatoire est ok, manquant, incomplet, ou non applicable, avec extrait ou URL.
4. RGPD et cookies (vue publique)
Politique distincte des CGV. Formulaires: information au moment de la collecte. Bandeau: refus aussi simple que l'acceptation; pas de traceur non exempté avant choix. Relire probe.json → cookies et trackers (premier GET, sans JS). Si navigateur: charger l'accueil sans cliquer, lister cookies et scripts tiers, puis tester « tout refuser ».
Fait quand: le rapport dit ce qui part avant consentement, avec noms de cookies / domaines, ou dit clairement « JS non observé ».
5. Bugs, pentest limité, debug
Lire references/pentest-limite.md. Cocher H puis K.
- Relire
probe.json: tls, security_headers, http_upgrade, cookies, html.forms.
- Surface: chaque ligne
surface[] a un verdict. exposed avec signature = constat. catchall / gated / absent = pas un écart.
- Fuites:
leaks.debug_signatures et leaks.secret_types (type seulement). Une 5xx ou une 404 habillée: même scan.
- Flux principal et pages légales: liens cassés, formulaires, pas de mixte.
- Repo fourni: revue statique (secrets,
eval, SQL concat). Pas de payload.
- TLS ≤ 30 j: le noter; ne pas engager un renouvellement payant sans accord.
Fait quand: chaque trou H/K a une preuve reproduisible, ou le point est non verifie. Zéro valeur secrète dans le markdown.
6. SEO technique
Lire references/seo.md. Cocher L. Relire probe.json → seo et seo.flags.
- Accueil: title, meta description,
html lang, viewport, H1.
- Indexation:
noindex / X-Robots-Tag. En préprod, noindex = ok.
- Canonical: HTTPS, absolu, pas de fragment, pas de conflit HTML vs
Link.
robots.txt et sitemap (déjà dans surface). Disallow: / sur une prod publique = écart. Disallow ≠ noindex.
- Si
hreflang présent: self + URLs absolues; lire hreflang_return (3 GET max).
- JSON-LD: types seulement. Absent = info. CWV =
non verifie.
- Autre page sondée (mentions, locale): title distinct si le HTML l'est. Un SPA catch-all: le dire.
Fait quand: chaque case L active a un statut + preuve, ou non verifie. Aucun constat « ça ne ranke pas ».
7. Modules conditionnels
E-commerce / abo: CGV, prix TTC, rétractation 14 j, médiateur, « résilier votre contrat » si abo (depuis 2023-06-01), « renoncer au contrat ici » si vente en ligne (depuis 2026-06-19). Accessibilité: EAA / RGAA seulement si le champ s'applique; sinon fumée (contraste, labels, clavier) en mineur / reco. IA (art. 50 depuis 2026-08-02), santé, mineurs, plateforme: voir cadre-legal.
Fait quand: chaque module inactif est marqué hors champ avec la raison.
8. Rédiger
Remplir templates/rapport.md. Sévérités: critique (donnée ou paiement exposé, auth cassée, infraction manifeste + preuve), majeur (obligation absente), mineur (incomplet / hygiène), info (hors champ, outil manquant). Relire: zéro constat sans preuve. Publication du rapport ou envoi au client: accord de l'éditeur.
Fait quand: le fichier rapport existe, les totaux du tableau égalent les constats listés, et la cible a été relue (probe + pages légales) après rédaction.
Pitfalls
- Identification éditeur = LCEN art. 1-1 / 1-2 (SREN, 23 mai 2024). F37351 / F31228 citent encore l'art. 6. Légifrance gagne. Le directeur de publication est obligatoire (1-1, I, 3°); les fiches SP ne le listent pas.
- Courriel et TVA: pas dans 1-1. Art. 19 (e-commerce) et RGPD art. 13.
- L.34-5: 75 000 € PP / 375 000 € PM. Pas 15 000 € (erreur fréquente).
- Rétractation en ligne (L.221-21) en vigueur depuis le 19 juin 2026. Résiliation abo (L.215-1-1) depuis le 1er juin 2023. Ce n'est pas le même bouton.
- Premier GET sans JS: les cookies et tags posés en JavaScript n'apparaissent pas. Le dire.
- Absence de bandeau ≠ écart: un site sans traceur non exempté n'a pas à en afficher un. Fermer le bandeau = refus.
- Consentement multi-terminaux: facultatif (reco CNIL janv. 2026). Ne pas le cocher comme manquant.
- Micro-entreprise prestataire (< 10 personnes et CA ou bilan ≤ 2 M€, L.412-13): EAA hors champ. Ne pas inventer l'effectif. RGAA ≠ EAA (250 M€ / public vs service listé). Un e-commerce privé n'a pas à publier une déclaration RGAA. Le délai 2030 vise les produits déjà utilisés, pas le site.
- EAA, sanction: R.451-4-I = contravention 5e classe (fiche DGCCRF). Corps de R.451-4 souvent derrière Cloudflare. Montants lus sur France Num (17 déc. 2025) et ecologie.gouv.fr: 1 500 € / 3 000 € récidive (PP), 7 500 € / 15 000 € récidive (PM), cumulables par service et par obligation. Aligné CP 131-13, 131-41, 132-11, 132-15. Ne pas écrire ces montants comme s'ils figuraient dans le corps de R.451-4.
- Ce skill ne « valide » pas un traitement interne (registre, DPA, 72 h). Vue publique seulement, sauf si l'éditeur fournit les docs internes.
- Pas d'exploit, pas de scan agressif, pas de mot de passe dans le livrable. Chemins GET: liste figée de
probe.py. On n'ajoute pas un path traversal ni un paramètre crafté.
- Catch-all SPA (200 HTML = accueil sur
/.env): pas un secret exposé.
- HSTS / CSP absents sur une vitrine:
mineur, pas critique. Cookie de session sans Secure sur un flux compte: critique.
- TLS 1.0/1.1: un handshake de config (refus/accepté). Pas un scan de suites.
- Auth L1 (longueur mdp, MFA, comptes par défaut):
non verifie sans compte de test fourni. On n'essaie aucun mot de passe.
- Ce skill n'est pas une portée PASSI (archi / conf machine / code / intrusion / orga). Un client qui demande « un pentest »: revue de surface, le dire.
- SEO: Search Central, pas un blog. Canonical / sitemap / JSON-LD absents = info, sauf conflit ou
noindex de prod. Disallow ≠ masquer une URL. Ranking, backlinks, CWV: hors sondeur.
- Title générique (
Home, Accueil): mineur. Title vide sur l'accueil public: majeur. Google peut réécrire le title link.
Verification
probe.py a tourné sur l'accueil (sortie JSON lue, pas inventée). tls + surface + leaks + seo présents sauf --no-surface (seo HTML reste).
python3 skills/audit-fr/scripts/test_probe.py passe si le sondeur a été modifié.
- Chaque case de la grille active (dont H, K et L) a un statut.
- Chaque constat critique/majeur a URL + extrait ou en-tête.
- Totaux du rapport = nombre de constats.
- Aucune clé ni session dans le markdown.
1---2name: audit-fr3description: Audit web France4---56# Audit web France78Revue factuelle d'un site ou d'une app destinés au public français: bugs, pentest limité (surface / debug / hygiène), identification, RGPD, cookies, conso, accessibilité, SEO technique. Ce n'est pas un avis juridique, pas un test d'intrusion PASSI, et pas un audit de ranking. Chaque constat a une preuve (URL, en-tête, extrait, capture) et un texte de référence. Pas de preuve = pas de constat, ou statut `non verifie`.910Cadre et sources: [references/cadre-legal.md](references/cadre-legal.md). Sécu: [references/pentest-limite.md](references/pentest-limite.md). SEO: [references/seo.md](references/seo.md). URLs relues: [references/sources.md](references/sources.md). Grille: [references/grille.md](references/grille.md). Rapport: [templates/rapport.md](templates/rapport.md).1112## When to Use1314- Review d'un site avant livraison ou mise en ligne.15- Audit global: bugs, pentest limité, RGPD, mentions, cookies, accessibilité, SEO technique.16- Contrôle ciblé: page légale, bandeau cookies, formulaire, surface sécu / debug, indexation.1718Don't use for: avis juridique opposable; pentest avec exploitation, payload, fuzz, brute-force; prestation PASSI; promesse de position / trafic; revue de code interne sans URL publique ou de préprod.1920## Prerequisites2122- URL publique, ou dépôt + URL de préprod. Sans cible, s'arrêter.23- Classer l'acteur avant de cocher la grille: association, EI, société, e-commerce B2C, service public, plateforme.24- Outils: `python3` (stdlib), un GET HTTP. Navigateur si disponible. Sans navigateur, le sondage HTTP reste valable et le JS n'est pas observé.25- Ne jamais coller mot de passe, cookie de session, ni clé dans le rapport.2627## How to Run2829```bash30python3 skills/audit-fr/scripts/probe.py "https://exemple.fr" -o ./audit-probe.json31```3233Puis suivre la Procedure. Rapport dans `./audit-fr-<slug>-<date>.md`.3435## Quick Reference3637| Action | Commande |38|---|---|39| Surface HTTP / TLS / cookies / liens légaux / chemins connus / SEO | `python3 skills/audit-fr/scripts/probe.py URL -o probe.json` |40| Accueil seulement (pas de liste de chemins) | `python3 skills/audit-fr/scripts/probe.py URL --no-surface` |41| Relire un certificat / proto TLS | `probe.json` → `tls` (`protocol`, `legacy_accepted`, `days_left`) |42| Relire fuites / surface | `probe.json` → `leaks`, `surface`, `http_upgrade` |43| Relire SEO | `probe.json` → `seo` (`title`, `canonical`, `robots`, `sitemap`, `hreflang`, `flags`) |44| Tests offline du sondeur | `python3 skills/audit-fr/scripts/test_probe.py` |4546## Procedure4748### 1. Cadrer4950Noter: URL, repo s'il est fourni, date UTC, acteur, ce qui est en ligne vs en préprod. Activer seulement les modules de la grille qui s'appliquent (une asso vitrine n'a pas de CGV B2C; un e-commerce si).5152Fait quand: le rapport a une ligne Acteur + Modules actifs, sans module hors champ coché comme échec.5354### 2. Sonder la surface5556Lancer `probe.py` sur l'accueil, puis sur `/mentions-legales`, `/politique-de-confidentialite` (et variantes: `/legal`, `/privacy`, `/cookies`, `/cgv`, `/accessibilite`). Suivre la chaîne de redirects. Recouper un 403 / timeout avant d'écrire « down ».5758Fait quand: `probe.json` existe et chaque URL sondée a un code final.5960### 3. Identifier et pages légales6162Contrôler accessibilité permanente (lien footer ou équivalent sur l'accueil) et le contenu attendu pour l'acteur. Source de vérité: LCEN art. 1-1 / 1-2 (Légifrance). F37351 / F31228 listent encore l'ancien art. 6: utiles pour la liste, pas pour le numéro. Exiger le directeur de la publication (1-1, I, 3°). Détail dans la grille module C.6364Fait quand: chaque mention obligatoire est `ok`, `manquant`, `incomplet`, ou `non applicable`, avec extrait ou URL.6566### 4. RGPD et cookies (vue publique)6768Politique distincte des CGV. Formulaires: information au moment de la collecte. Bandeau: refus aussi simple que l'acceptation; pas de traceur non exempté avant choix. Relire `probe.json` → `cookies` et `trackers` (premier GET, sans JS). Si navigateur: charger l'accueil sans cliquer, lister cookies et scripts tiers, puis tester « tout refuser ».6970Fait quand: le rapport dit ce qui part avant consentement, avec noms de cookies / domaines, ou dit clairement « JS non observé ».7172### 5. Bugs, pentest limité, debug7374Lire [references/pentest-limite.md](references/pentest-limite.md). Cocher H puis K.75761. Relire `probe.json`: `tls`, `security_headers`, `http_upgrade`, `cookies`, `html.forms`.772. Surface: chaque ligne `surface[]` a un verdict. `exposed` avec signature = constat. `catchall` / `gated` / `absent` = pas un écart.783. Fuites: `leaks.debug_signatures` et `leaks.secret_types` (type seulement). Une 5xx ou une 404 habillée: même scan.794. Flux principal et pages légales: liens cassés, formulaires, pas de mixte.805. Repo fourni: revue statique (secrets, `eval`, SQL concat). Pas de payload.816. TLS ≤ 30 j: le noter; ne pas engager un renouvellement payant sans accord.8283Fait quand: chaque trou H/K a une preuve reproduisible, ou le point est `non verifie`. Zéro valeur secrète dans le markdown.8485### 6. SEO technique8687Lire [references/seo.md](references/seo.md). Cocher L. Relire `probe.json` → `seo` et `seo.flags`.88891. Accueil: title, meta description, `html lang`, viewport, H1.902. Indexation: `noindex` / `X-Robots-Tag`. En préprod, `noindex` = `ok`.913. Canonical: HTTPS, absolu, pas de fragment, pas de conflit HTML vs `Link`.924. `robots.txt` et sitemap (déjà dans `surface`). `Disallow: /` sur une prod publique = écart. `Disallow` ≠ `noindex`.935. Si `hreflang` présent: self + URLs absolues; lire `hreflang_return` (3 GET max).946. JSON-LD: types seulement. Absent = info. CWV = `non verifie`.957. Autre page sondée (mentions, locale): title distinct si le HTML l'est. Un SPA catch-all: le dire.9697Fait quand: chaque case L active a un statut + preuve, ou `non verifie`. Aucun constat « ça ne ranke pas ».9899### 7. Modules conditionnels100101E-commerce / abo: CGV, prix TTC, rétractation 14 j, médiateur, « résilier votre contrat » si abo (depuis 2023-06-01), « renoncer au contrat ici » si vente en ligne (depuis 2026-06-19). Accessibilité: EAA / RGAA seulement si le champ s'applique; sinon fumée (contraste, labels, clavier) en `mineur` / reco. IA (art. 50 depuis 2026-08-02), santé, mineurs, plateforme: voir cadre-legal.102103Fait quand: chaque module inactif est marqué `hors champ` avec la raison.104105### 8. Rédiger106107Remplir [templates/rapport.md](templates/rapport.md). Sévérités: `critique` (donnée ou paiement exposé, auth cassée, infraction manifeste + preuve), `majeur` (obligation absente), `mineur` (incomplet / hygiène), `info` (hors champ, outil manquant). Relire: zéro constat sans preuve. Publication du rapport ou envoi au client: accord de l'éditeur.108109Fait quand: le fichier rapport existe, les totaux du tableau égalent les constats listés, et la cible a été relue (probe + pages légales) après rédaction.110111## Pitfalls112113- Identification éditeur = LCEN art. 1-1 / 1-2 (SREN, 23 mai 2024). F37351 / F31228 citent encore l'art. 6. Légifrance gagne. Le directeur de publication est obligatoire (1-1, I, 3°); les fiches SP ne le listent pas.114- Courriel et TVA: pas dans 1-1. Art. 19 (e-commerce) et RGPD art. 13.115- L.34-5: 75 000 € PP / 375 000 € PM. Pas 15 000 € (erreur fréquente).116- Rétractation en ligne (L.221-21) en vigueur depuis le 19 juin 2026. Résiliation abo (L.215-1-1) depuis le 1er juin 2023. Ce n'est pas le même bouton.117- Premier GET sans JS: les cookies et tags posés en JavaScript n'apparaissent pas. Le dire.118- Absence de bandeau ≠ écart: un site sans traceur non exempté n'a pas à en afficher un. Fermer le bandeau = refus.119- Consentement multi-terminaux: facultatif (reco CNIL janv. 2026). Ne pas le cocher comme manquant.120- Micro-entreprise prestataire (< 10 personnes et CA ou bilan ≤ 2 M€, L.412-13): EAA hors champ. Ne pas inventer l'effectif. RGAA ≠ EAA (250 M€ / public vs service listé). Un e-commerce privé n'a pas à publier une déclaration RGAA. Le délai 2030 vise les produits déjà utilisés, pas le site.121- EAA, sanction: R.451-4-I = contravention 5e classe (fiche DGCCRF). Corps de R.451-4 souvent derrière Cloudflare. Montants lus sur France Num (17 déc. 2025) et ecologie.gouv.fr: 1 500 € / 3 000 € récidive (PP), 7 500 € / 15 000 € récidive (PM), cumulables par service et par obligation. Aligné CP 131-13, 131-41, 132-11, 132-15. Ne pas écrire ces montants comme s'ils figuraient dans le corps de R.451-4.122- Ce skill ne « valide » pas un traitement interne (registre, DPA, 72 h). Vue publique seulement, sauf si l'éditeur fournit les docs internes.123- Pas d'exploit, pas de scan agressif, pas de mot de passe dans le livrable. Chemins GET: liste figée de `probe.py`. On n'ajoute pas un path traversal ni un paramètre crafté.124- Catch-all SPA (200 HTML = accueil sur `/.env`): pas un secret exposé.125- HSTS / CSP absents sur une vitrine: `mineur`, pas `critique`. Cookie de session sans `Secure` sur un flux compte: `critique`.126- TLS 1.0/1.1: un handshake de config (refus/accepté). Pas un scan de suites.127- Auth L1 (longueur mdp, MFA, comptes par défaut): `non verifie` sans compte de test fourni. On n'essaie aucun mot de passe.128- Ce skill n'est pas une portée PASSI (archi / conf machine / code / intrusion / orga). Un client qui demande « un pentest »: revue de surface, le dire.129- SEO: Search Central, pas un blog. Canonical / sitemap / JSON-LD absents = info, sauf conflit ou `noindex` de prod. `Disallow` ≠ masquer une URL. Ranking, backlinks, CWV: hors sondeur.130- Title générique (`Home`, `Accueil`): mineur. Title vide sur l'accueil public: majeur. Google peut réécrire le title link.131132## Verification133134- `probe.py` a tourné sur l'accueil (sortie JSON lue, pas inventée). `tls` + `surface` + `leaks` + `seo` présents sauf `--no-surface` (seo HTML reste).135- `python3 skills/audit-fr/scripts/test_probe.py` passe si le sondeur a été modifié.136- Chaque case de la grille active (dont H, K et L) a un statut.137- Chaque constat critique/majeur a URL + extrait ou en-tête.138- Totaux du rapport = nombre de constats.139- Aucune clé ni session dans le markdown.