wopt 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,34 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.10", "3.11", "3.12"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Set up Python ${{ matrix.python-version }}
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+
24
+ - name: Install dependencies
25
+ run: |
26
+ pip install -r requirements.txt
27
+ pip install -r requirements-dev.txt
28
+ pip install -e .
29
+
30
+ - name: Lint with ruff
31
+ run: ruff check .
32
+
33
+ - name: Run tests
34
+ run: pytest -v
@@ -0,0 +1,29 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Set up Python
15
+ uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.12"
18
+
19
+ - name: Install build tools
20
+ run: pip install build twine
21
+
22
+ - name: Build package
23
+ run: python -m build
24
+
25
+ - name: Publish to PyPI
26
+ env:
27
+ TWINE_USERNAME: __token__
28
+ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
29
+ run: twine upload dist/*
wopt-0.1.0/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ build/
6
+ dist/
7
+ .venv/
8
+ venv/
9
+ .pytest_cache/
10
+ .ruff_cache/
11
+ *.egg
12
+ wopt-report.html
13
+ *.json
14
+ !package.json
15
+ .env
16
+ .DS_Store
wopt-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 eloundou nkolo ryan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
wopt-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.4
2
+ Name: wopt
3
+ Version: 0.1.0
4
+ Summary: Mini audit de sécurité web en ligne de commande : headers, TLS, cookies, CORS, fichiers exposés.
5
+ Project-URL: Homepage, https://github.com/eloundou-nkolo/wopt
6
+ Project-URL: Repository, https://github.com/eloundou-nkolo/wopt
7
+ Project-URL: Issues, https://github.com/eloundou-nkolo/wopt/issues
8
+ Project-URL: Portfolio, https://eloundounkolo.com
9
+ Author-email: Eloundou Nkolo Ryan <ryan@eloundounkolo.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: audit,cli,cors,http-headers,security,tls,web
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Security
22
+ Classifier: Topic :: Software Development :: Quality Assurance
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: cryptography
25
+ Requires-Dist: httpx
26
+ Requires-Dist: jinja2
27
+ Requires-Dist: rich
28
+ Requires-Dist: typer
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest; extra == 'dev'
31
+ Requires-Dist: pytest-httpx; extra == 'dev'
32
+ Requires-Dist: ruff; extra == 'dev'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # wopt
36
+
37
+ test audit de sécurité web en ligne de commande — non-intrusif, sans configuration, sans infrastructure.
38
+
39
+ `wopt` scanne un site web et vérifie les points de sécurité les plus fréquemment négligés : en-têtes HTTP, configuration TLS, cookies, CORS, et exposition de fichiers sensibles. Conçu pour s'intégrer facilement à un pipeline CI/CD.
40
+ ## Auteurs
41
+
42
+ Développé par [Eloundou Nkolo Ryan](https://eloundounkolo.com) — développeur web & intégration de solutions numériques.
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ pip install wopt
48
+ ```
49
+
50
+ Ou en local depuis le code source :
51
+
52
+ ```bash
53
+ git clone https://github.com/eloundou-nkolo/wopt.git
54
+ cd wopt
55
+ pip install -r requirements.txt
56
+ pip install -e .
57
+ ```
58
+
59
+ ## Utilisation
60
+
61
+ ```bash
62
+ # Scan simple, affichage table dans le terminal
63
+ wopt exemple.com
64
+
65
+ # Export JSON (pour CI/CD)
66
+ wopt exemple.com --format json --output rapport.json
67
+
68
+ # Export HTML lisible
69
+ wopt exemple.com --format html --output rapport.html
70
+
71
+ # Rapport formaté pour être collé dans un agent IA (Claude Code, Cursor...)
72
+ wopt exemple.com --ai-context
73
+
74
+ # Scan plus léger, sans vérification des chemins sensibles
75
+ wopt exemple.com --no-probes
76
+ ```
77
+
78
+ ## Ce que wopt vérifie
79
+
80
+ | Catégorie | Vérifications |
81
+ |---|---|
82
+ | **Headers** | CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, divulgation de stack |
83
+ | **TLS** | Version du protocole, expiration du certificat, redirection HTTPS |
84
+ | **Cookies** | Flags Secure, HttpOnly, SameSite |
85
+ | **CORS** | Combinaison dangereuse wildcard + credentials |
86
+ | **Exposition** | Fichiers sensibles accessibles (`.env`, `.git/HEAD`, backups...) |
87
+
88
+ ## Philosophie
89
+
90
+ - **100% passif et non-intrusif** : aucun scan de ports, aucune tentative d'exploitation, aucun brute-force. Uniquement des requêtes HTTP GET standards.
91
+ - **Zéro infrastructure** : tourne entièrement en local, aucune donnée envoyée à un serveur tiers.
92
+ - **Pensé pour l'ère du vibe coding** : conçu pour combler les lacunes de sécurité fréquentes dans le code généré par IA (absence de headers de sécurité, CSRF, CORS mal configuré).
93
+
94
+ ## Score
95
+
96
+ Chaque scan produit un score de A à F, calculé par pondération de sévérité (inspiré de l'approche Mozilla Observatory).
97
+
98
+ ## Développement
99
+
100
+ ```bash
101
+ pip install -r requirements-dev.txt
102
+ pytest
103
+ ruff check .
104
+ ```
105
+
106
+ ## Avertissement
107
+
108
+ `wopt` est un outil d'audit passif destiné à un usage sur des sites que vous possédez ou êtes autorisé à tester. L'auteur décline toute responsabilité en cas d'usage non autorisé.
109
+
110
+ ## Licence
111
+
112
+ MIT
wopt-0.1.0/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # wopt
2
+
3
+ test audit de sécurité web en ligne de commande — non-intrusif, sans configuration, sans infrastructure.
4
+
5
+ `wopt` scanne un site web et vérifie les points de sécurité les plus fréquemment négligés : en-têtes HTTP, configuration TLS, cookies, CORS, et exposition de fichiers sensibles. Conçu pour s'intégrer facilement à un pipeline CI/CD.
6
+ ## Auteurs
7
+
8
+ Développé par [Eloundou Nkolo Ryan](https://eloundounkolo.com) — développeur web & intégration de solutions numériques.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ pip install wopt
14
+ ```
15
+
16
+ Ou en local depuis le code source :
17
+
18
+ ```bash
19
+ git clone https://github.com/eloundou-nkolo/wopt.git
20
+ cd wopt
21
+ pip install -r requirements.txt
22
+ pip install -e .
23
+ ```
24
+
25
+ ## Utilisation
26
+
27
+ ```bash
28
+ # Scan simple, affichage table dans le terminal
29
+ wopt exemple.com
30
+
31
+ # Export JSON (pour CI/CD)
32
+ wopt exemple.com --format json --output rapport.json
33
+
34
+ # Export HTML lisible
35
+ wopt exemple.com --format html --output rapport.html
36
+
37
+ # Rapport formaté pour être collé dans un agent IA (Claude Code, Cursor...)
38
+ wopt exemple.com --ai-context
39
+
40
+ # Scan plus léger, sans vérification des chemins sensibles
41
+ wopt exemple.com --no-probes
42
+ ```
43
+
44
+ ## Ce que wopt vérifie
45
+
46
+ | Catégorie | Vérifications |
47
+ |---|---|
48
+ | **Headers** | CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, divulgation de stack |
49
+ | **TLS** | Version du protocole, expiration du certificat, redirection HTTPS |
50
+ | **Cookies** | Flags Secure, HttpOnly, SameSite |
51
+ | **CORS** | Combinaison dangereuse wildcard + credentials |
52
+ | **Exposition** | Fichiers sensibles accessibles (`.env`, `.git/HEAD`, backups...) |
53
+
54
+ ## Philosophie
55
+
56
+ - **100% passif et non-intrusif** : aucun scan de ports, aucune tentative d'exploitation, aucun brute-force. Uniquement des requêtes HTTP GET standards.
57
+ - **Zéro infrastructure** : tourne entièrement en local, aucune donnée envoyée à un serveur tiers.
58
+ - **Pensé pour l'ère du vibe coding** : conçu pour combler les lacunes de sécurité fréquentes dans le code généré par IA (absence de headers de sécurité, CSRF, CORS mal configuré).
59
+
60
+ ## Score
61
+
62
+ Chaque scan produit un score de A à F, calculé par pondération de sévérité (inspiré de l'approche Mozilla Observatory).
63
+
64
+ ## Développement
65
+
66
+ ```bash
67
+ pip install -r requirements-dev.txt
68
+ pytest
69
+ ruff check .
70
+ ```
71
+
72
+ ## Avertissement
73
+
74
+ `wopt` est un outil d'audit passif destiné à un usage sur des sites que vous possédez ou êtes autorisé à tester. L'auteur décline toute responsabilité en cas d'usage non autorisé.
75
+
76
+ ## Licence
77
+
78
+ MIT
@@ -0,0 +1,61 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "wopt"
7
+ version = "0.1.0"
8
+ description = "Mini audit de sécurité web en ligne de commande : headers, TLS, cookies, CORS, fichiers exposés."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Eloundou Nkolo Ryan", email="ryan@eloundounkolo.com", website = "eloundounkolo.com"}
14
+ ]
15
+ keywords = ["security", "web", "audit", "cli", "http-headers", "tls", "cors"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Topic :: Security",
26
+ "Topic :: Software Development :: Quality Assurance",
27
+ ]
28
+
29
+ dependencies = [
30
+ "httpx",
31
+ "typer",
32
+ "rich",
33
+ "jinja2",
34
+ "cryptography",
35
+ ]
36
+
37
+ [project.optional-dependencies]
38
+ dev = [
39
+ "pytest",
40
+ "pytest-httpx",
41
+ "ruff",
42
+ ]
43
+
44
+ [project.scripts]
45
+ wopt = "wopt.cli:main"
46
+
47
+ [project.urls]
48
+ Homepage = "https://github.com/eloundou-nkolo/wopt"
49
+ Repository = "https://github.com/eloundou-nkolo/wopt"
50
+ Issues = "https://github.com/eloundou-nkolo/wopt/issues"
51
+ Portfolio = "https://eloundounkolo.com"
52
+
53
+ [tool.hatch.build.targets.wheel]
54
+ packages = ["src/wopt"]
55
+
56
+ [tool.ruff]
57
+ line-length = 100
58
+ target-version = "py310"
59
+
60
+ [tool.pytest.ini_options]
61
+ testpaths = ["tests"]
@@ -0,0 +1,3 @@
1
+ pytest
2
+ pytest-httpx
3
+ ruff
@@ -0,0 +1,5 @@
1
+ httpx
2
+ typer
3
+ rich
4
+ jinja2
5
+ cryptography
@@ -0,0 +1,7 @@
1
+ """wopt — mini audit de sécurité web en ligne de commande."""
2
+
3
+ __version__ = "0.1.0"
4
+
5
+ from wopt.core.scanner import scan
6
+
7
+ __all__ = ["scan", "__version__"]
@@ -0,0 +1,36 @@
1
+ """
2
+ wopt.checks
3
+
4
+ Registre central des checks disponibles. Pour ajouter un nouveau
5
+ check : créer la classe dans un module de ce package, puis
6
+ l'ajouter à ALL_CHECKS. Le scanner n'a rien d'autre à connaître.
7
+ """
8
+
9
+ from wopt.checks.cookies import CookiesCheck
10
+ from wopt.checks.cors import CORSCheck
11
+ from wopt.checks.exposure import ExposurePathsCheck
12
+ from wopt.checks.headers import SecurityHeadersCheck
13
+ from wopt.checks.tls import TLSCheck
14
+
15
+ # Checks "standards" exécutés directement sur le ScanContext
16
+ ALL_CHECKS = [
17
+ SecurityHeadersCheck,
18
+ TLSCheck,
19
+ CookiesCheck,
20
+ CORSCheck,
21
+ ]
22
+
23
+ # Checks nécessitant des requêtes HTTP additionnelles (probing actif)
24
+ PROBE_CHECKS = [
25
+ ExposurePathsCheck,
26
+ ]
27
+
28
+ __all__ = [
29
+ "ALL_CHECKS",
30
+ "PROBE_CHECKS",
31
+ "SecurityHeadersCheck",
32
+ "TLSCheck",
33
+ "CookiesCheck",
34
+ "CORSCheck",
35
+ "ExposurePathsCheck",
36
+ ]
@@ -0,0 +1,29 @@
1
+ """
2
+ wopt.checks.base
3
+
4
+ Contrat que tout check de sécurité doit respecter.
5
+ Chaque nouveau check hérite de Check et implémente run().
6
+ Le scanner orchestrateur n'a besoin de rien connaître de la
7
+ logique interne de chaque check : il les découvre et les exécute
8
+ tous de la même façon.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from abc import ABC, abstractmethod
14
+
15
+ from wopt.models import Finding, ScanContext
16
+
17
+
18
+ class Check(ABC):
19
+ """Classe abstraite : tout check de sécurité l'implémente."""
20
+
21
+ id: str = "base.check"
22
+ name: str = "Base Check"
23
+ category: str = "general" # headers | tls | cookies | cors | exposure
24
+
25
+ @abstractmethod
26
+ def run(self, ctx: ScanContext) -> list[Finding]:
27
+ """Exécute la vérification et retourne une liste de Finding.
28
+ Une liste vide = rien à signaler (tout est conforme)."""
29
+ raise NotImplementedError
@@ -0,0 +1,58 @@
1
+ """
2
+ wopt.checks.cookies
3
+
4
+ Vérifie que chaque cookie détecté sur la réponse HTTP est
5
+ correctement sécurisé : Secure, HttpOnly, SameSite.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from wopt.checks.base import Check
11
+ from wopt.models import Finding, ScanContext, Severity
12
+
13
+
14
+ class CookiesCheck(Check):
15
+ id = "cookies.flags"
16
+ name = "Cookie Security Flags"
17
+ category = "cookies"
18
+
19
+ def run(self, ctx: ScanContext) -> list[Finding]:
20
+ findings: list[Finding] = []
21
+
22
+ for cookie in ctx.cookies:
23
+ if not cookie.secure:
24
+ findings.append(
25
+ Finding(
26
+ check_id=f"{self.id}.{cookie.name}_not_secure",
27
+ title=f"Cookie '{cookie.name}' sans flag Secure",
28
+ severity=Severity.MEDIUM,
29
+ category=self.category,
30
+ description="Ce cookie peut être transmis en clair sur une connexion non chiffrée.",
31
+ recommendation=f"Ajouter le flag Secure au cookie '{cookie.name}'.",
32
+ )
33
+ )
34
+ if not cookie.http_only:
35
+ findings.append(
36
+ Finding(
37
+ check_id=f"{self.id}.{cookie.name}_not_httponly",
38
+ title=f"Cookie '{cookie.name}' sans flag HttpOnly",
39
+ severity=Severity.MEDIUM,
40
+ category=self.category,
41
+ description="Ce cookie est accessible via JavaScript, ce qui facilite son vol en cas de XSS.",
42
+ recommendation=f"Ajouter le flag HttpOnly au cookie '{cookie.name}'.",
43
+ )
44
+ )
45
+ if not cookie.same_site or cookie.same_site.lower() == "none":
46
+ findings.append(
47
+ Finding(
48
+ check_id=f"{self.id}.{cookie.name}_samesite_weak",
49
+ title=f"Cookie '{cookie.name}' avec SameSite absent ou 'None'",
50
+ severity=Severity.LOW,
51
+ category=self.category,
52
+ description="Ce cookie peut être envoyé lors de requêtes cross-site, augmentant le risque CSRF.",
53
+ recommendation=f"Définir 'SameSite=Lax' ou 'Strict' sur le cookie '{cookie.name}'.",
54
+ evidence=cookie.same_site or "absent",
55
+ )
56
+ )
57
+
58
+ return findings
@@ -0,0 +1,60 @@
1
+ """
2
+ wopt.checks.cors
3
+
4
+ Détecte les configurations CORS dangereuses, en particulier
5
+ la combinaison Access-Control-Allow-Origin: * associée à
6
+ Access-Control-Allow-Credentials: true, qui permet à n'importe
7
+ quel site tiers de lire des réponses authentifiées.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from wopt.checks.base import Check
13
+ from wopt.models import Finding, ScanContext, Severity
14
+
15
+
16
+ class CORSCheck(Check):
17
+ id = "cors.configuration"
18
+ name = "CORS Configuration"
19
+ category = "cors"
20
+
21
+ def run(self, ctx: ScanContext) -> list[Finding]:
22
+ findings: list[Finding] = []
23
+ headers_lower = {k.lower(): v for k, v in ctx.response_headers.items()}
24
+
25
+ acao = headers_lower.get("access-control-allow-origin")
26
+ acac = headers_lower.get("access-control-allow-credentials", "").lower() == "true"
27
+
28
+ if acao == "*" and acac:
29
+ findings.append(
30
+ Finding(
31
+ check_id=f"{self.id}.wildcard_with_credentials",
32
+ title="CORS critique : origine wildcard combinée aux credentials",
33
+ severity=Severity.CRITICAL,
34
+ category=self.category,
35
+ description=(
36
+ "Access-Control-Allow-Origin est réglé sur '*' alors que "
37
+ "Access-Control-Allow-Credentials est à 'true'. N'importe quel "
38
+ "site tiers peut lire des réponses authentifiées de l'utilisateur."
39
+ ),
40
+ recommendation=(
41
+ "Remplacer '*' par une liste blanche explicite d'origines de confiance, "
42
+ "ou désactiver les credentials si le wildcard est nécessaire."
43
+ ),
44
+ evidence=f"Access-Control-Allow-Origin: {acao}",
45
+ )
46
+ )
47
+ elif acao == "*":
48
+ findings.append(
49
+ Finding(
50
+ check_id=f"{self.id}.wildcard_origin",
51
+ title="CORS permissif : origine wildcard",
52
+ severity=Severity.LOW,
53
+ category=self.category,
54
+ description="Access-Control-Allow-Origin accepte toute origine ('*').",
55
+ recommendation="Restreindre aux origines réellement nécessaires si l'API contient des données sensibles.",
56
+ evidence=f"Access-Control-Allow-Origin: {acao}",
57
+ )
58
+ )
59
+
60
+ return findings
@@ -0,0 +1,60 @@
1
+ """
2
+ wopt.checks.exposure
3
+
4
+ Vérifie passivement si des chemins sensibles connus répondent
5
+ avec un statut 200 (fichier accessible). Aucune tentative de
6
+ lecture/exploitation du contenu au-delà de la détection : on
7
+ observe uniquement le code de statut HTTP renvoyé.
8
+
9
+ Ce check nécessite des requêtes HTTP additionnelles, effectuées
10
+ par le scanner (pas par ScanContext initial) via check.probe_paths().
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from wopt.checks.base import Check
16
+ from wopt.models import Finding, ScanContext, Severity
17
+
18
+ SENSITIVE_PATHS = {
19
+ "/.env": Severity.CRITICAL,
20
+ "/.git/HEAD": Severity.HIGH,
21
+ "/.git/config": Severity.HIGH,
22
+ "/wp-config.php.bak": Severity.CRITICAL,
23
+ "/config.php.bak": Severity.CRITICAL,
24
+ "/.DS_Store": Severity.LOW,
25
+ "/backup.zip": Severity.MEDIUM,
26
+ "/.aws/credentials": Severity.CRITICAL,
27
+ }
28
+
29
+
30
+ class ExposurePathsCheck(Check):
31
+ """Ce check est particulier : il a besoin de requêtes HTTP
32
+ supplémentaires (une par chemin testé). Le scanner l'invoque
33
+ via `probe_paths()` plutôt que `run()` classique -- voir
34
+ core/scanner.py pour l'intégration."""
35
+
36
+ id = "exposure.sensitive_paths"
37
+ name = "Sensitive Paths Exposure"
38
+ category = "exposure"
39
+
40
+ def paths_to_probe(self) -> dict[str, Severity]:
41
+ return SENSITIVE_PATHS
42
+
43
+ def build_finding(self, path: str, severity: Severity, status_code: int) -> Finding:
44
+ return Finding(
45
+ check_id=f"{self.id}.{path.strip('/').replace('/', '_').replace('.', '_')}",
46
+ title=f"Chemin sensible potentiellement exposé : {path}",
47
+ severity=severity,
48
+ category=self.category,
49
+ description=(
50
+ f"La requête vers '{path}' a retourné un statut {status_code}, "
51
+ "suggérant que ce fichier pourrait être accessible publiquement."
52
+ ),
53
+ recommendation=f"Vérifier manuellement '{path}' et bloquer son accès public si confirmé.",
54
+ evidence=f"HTTP {status_code}",
55
+ )
56
+
57
+ def run(self, ctx: ScanContext) -> list[Finding]:
58
+ # Ce check ne fait rien via run() seul -- voir probe_paths()
59
+ # dans le scanner qui gère les requêtes réseau réelles.
60
+ return []