Skip to content

FEAT : Secret redaction filter #7

Description

@junkoku38

Feature: Redaction des secrets dans les rapports

Contexte

AttackSim ne possède aucune fonction de redaction dans report/reporter.py. Les champs evidence, detail, location sont écrits en clair dans tous les formats de sortie (console, JSON, SARIF, HTML, Markdown). Un module qui capture un mot de passe opérateur, un token JWT, ou un secret application (ex: secret_scanner qui récolte des creds Kafka/Okta) le fait fuiter intégralement dans l'artefact de rapport, qui peut être archivé, commité ou partagé.

Ceci est contradictoire avec la promesse centrale du produit : "credentials never written to the report".

Description

Ajouter une couche de redaction automatique appliquée à tous les champs textuels des findings avant sérialisation dans les rapports.

Spécifications fonctionnelles

Patterns à détecter et masquer

Type Regex Remplacement Exemple
AWS Access Key ID AKIA[0-9A-Z]{16} AKIA****REDACTED AKIAIOSFODNN7EXAMPLEAKIA****REDACTED
AWS Secret Key [A-Za-z0-9/+=]{40} après aws_secret_access_key ****REDACTED contextuel
JWT eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,} eyJ****REDACTED.****.****
Private key PEM -----BEGIN (RSA |EC |OPENSSH |PGP )?PRIVATE KEY-----[\s\S]*?-----END [REDACTED PRIVATE KEY]
Password in URL ://([^:]+):([^@]+)@ ://$1:****@ http://admin:secret@hosthttp://admin:****@host
Bearer token Bearer\s+[A-Za-z0-9._\-+/=]{20,} Bearer ****REDACTED
Slack webhook https://hooks.slack.com/services/[A-Z0-9/]+ [REDACTED SLACK WEBHOOK]
GitHub token gh[pousr]_[A-Za-z0-9]{36,} ghp_****REDACTED
Generic API key [A-Za-z0-9]{32,} après api_key|apikey|api-key|token (contextuel) ****REDACTED
Connection string mongodb(\+srv)?://[^:]+:[^@]+@ mongodb://$1:****@
Credit card \b(?:\d[ -]*?){13,16}\b (Luhn check) [REDACTED CC]
Private IP in evidence (optionnel) 10\.\d+\.\d+\.\d+ garder (info utile)
Email (optionnel, configurable) garder par défaut

Champs traités

Appliquer la redaction sur tous les champs textuels du finding :

  • title (mais garder le contexte : AWS access key appears live: AKIA****REDACTED)
  • evidence
  • detail
  • location (masquer le password dans l'URL seulement)
  • refs (pas masqué — ce sont des CWE/CVE)

Mode

  • Par défaut : redaction active sur tous les rapports
  • --no-redact : désactive la redaction (pour debug, nécessite --yes)
  • L'état de la redaction est tracé dans le rapport : "redaction": "enabled" ou "redaction": "disabled (--no-redact)"

Output

{
  "name": "secret-harvester",
  "title": "AWS access key appears live: AKIA****REDACTED",
  "evidence": "STS response HTTP 200: 'Arn': 'arn:aws:iam::123456:****REDACTED'",
  "redacted": true,
  "redaction_patterns_applied": ["aws_access_key_id", "aws_secret_key"]
}

Spécifications techniques

Fichier à créer

sandbox/redaction.py

import re
from dataclasses import dataclass

@dataclass
class RedactionPattern:
    name: str
    pattern: re.Pattern
    replacement: str

PATTERNS = [
    RedactionPattern("aws_access_key_id",
        re.compile(r"AKIA[0-9A-Z]{16}"), "AKIA****REDACTED"),
    RedactionPattern("aws_secret_key",
        re.compile(r"(aws_secret_access_key\s*[=:]\s*)([A-Za-z0-9/+=]{40})"),
        r"\1****REDACTED"),
    RedactionPattern("jwt",
        re.compile(r"eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}"),
        "eyJ****REDACTED.****.****"),
    RedactionPattern("private_key_pem",
        re.compile(r"-----BEGIN (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY-----[\s\S]*?-----END"),
        "[REDACTED PRIVATE KEY]"),
    RedactionPattern("password_in_url",
        re.compile(r"(://[^:/@\s]+:)([^@\s]+)(@)"), r"\1****\3"),
    RedactionPattern("bearer_token",
        re.compile(r"(Bearer\s+)[A-Za-z0-9._\-+/=]{20,}"), r"\1****REDACTED"),
    RedactionPattern("slack_webhook",
        re.compile(r"https://hooks\.slack\.com/services/[A-Z0-9/]+"),
        "[REDACTED SLACK WEBHOOK]"),
    RedactionPattern("github_token",
        re.compile(r"gh[pousr]_[A-Za-z0-9]{36,}"), "ghp_****REDACTED"),
    RedactionPattern("mongodb_connstring",
        re.compile(r"(mongodb(?:\+srv)?://[^:]+:)([^@]+)(@)"), r"\1****\3"),
    RedactionPattern("generic_api_key",
        re.compile(r"((?:api_key|apikey|api-key|token)\s*[=:]\s*)([A-Za-z0-9]{32,})"),
        r"\1****REDACTED"),
]

def redact(text: str, patterns=None) -> tuple[str, list[str]]:
    if not text or not isinstance(text, str):
        return text, []
    applied = []
    for p in (patterns or PATTERNS):
        if p.pattern.search(text):
            text = p.pattern.sub(p.replacement, text)
            applied.append(p.name)
    return text, applied

Fichier à modifier

report/reporter.py

Changements

  1. Importer from sandbox.redaction import redact
  2. Ajouter un paramètre redact: bool = True à render_console, write_json, write_sarif, write_html, write_markdown
  3. Avant chaque sérialisation d'un finding, appliquer redact() sur title, evidence, detail, location
  4. Ajouter le champ "redacted": True/False et "redaction_patterns_applied": [...] au JSON/SARIF
  5. Le metadata du rapport inclut "redaction": "enabled" | "disabled (--no-redact)"

Changements dans main.py

  • Ajouter l'argument --no-redact (necessite --yes)
  • Passer redact=not args.no_redact aux fonctions du reporter

Changements dans exploits/secret_scanner.py

  • Ligne 131 : title=f"AWS access key appears live: {_access_key_id[:8]}****" (tronquer dans le titre)
  • Le detail et evidence sont redacted par la couche globale

Tests

tests/test_redaction.py (nouveau) :

  • redact("token=AKIAIOSFODNN7EXAMPLE")"token=AKIA****REDACTED", applied=["aws_access_key_id"]
  • redact("Authorization: Bearer eyJhbGci...") → bearer masqué
  • redact("-----BEGIN RSA PRIVATE KEY-----...")[REDACTED PRIVATE KEY]
  • redact("http://admin:secret@host/")"http://admin:****@host/"
  • redact("mongodb://user:pass@host/")"mongodb://user:****@host/"
  • redact("no secrets here")"no secrets here", applied=[]
  • redact("")"", applied=[]
  • redact(None)None, applied=[]

tests/test_reporter_outputs.py (existant) — vérifier que les tests passent toujours avec redaction active.

Acceptance criteria

  • 10+ patterns de secrets détectés et masqués
  • Redaction appliquée à console, JSON, SARIF, HTML, Markdown
  • --no-redact disponible (nécessite --yes)
  • État de la redaction tracé dans le rapport JSON ("redaction": "enabled/disabled")
  • secret_scanner ne fait plus fuiter d'access key ID complet dans le titre
  • Tests unitaires passent
  • Tests existants non cassés

Références

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions