diff --git a/app/templates/admin/acces.php b/app/templates/admin/acces.php
index c000580..005bae2 100644
--- a/app/templates/admin/acces.php
+++ b/app/templates/admin/acces.php
@@ -1429,6 +1429,19 @@
+%%%%%%% diff from: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
+\\\\\\\ to: osltsstu c8c1516d "fix: validation error messages hidden by generic fallback in ErrorHandler::userMessage" (rebased revision)
++ $linkName = $link['name'] ?? '';
+++ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: osltsstu c8c1516d "fix: validation error messages hidden by generic fallback in ErrorHandler::userMessage" (rebased revision)
+\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
+- $linkName = $link['name'] ?? '';
+- $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: somsyvxz 14a3cd10 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebase destination)
+\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: srupvzpw 6bfa45fc "feat: add passive pentest scanner script with PEP 723 uv metadata" (rebased revision)
+ $linkName = $link['name'] ?? '';
+ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
+ $linkLockedYear = $link['locked_year'] ?? null;
++%%%%%%% diff from: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
++\\\\\\\ to: srupvzpw 5a2ec7e2 "feat: add passive pentest scanner script with PEP 723 uv metadata" (rebased revision)
+++ $linkName = $link['name'] ?? '';
++ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
?>
diff --git a/pentest_xamxam.py b/pentest_xamxam.py
new file mode 100644
index 0000000..5d0a208
--- /dev/null
+++ b/pentest_xamxam.py
@@ -0,0 +1,469 @@
+#!/usr/bin/env -S uv run
+# /// script
+# requires-python = ">=3.12"
+# dependencies = [
+# "requests",
+# "dnspython",
+# "colorama",
+# ]
+# ///
+"""
+Passive / Non-Destructive Pentest Script
+Target: xamxam.erg.be
+Author: generated for site owner / authorized use only
+
+Checks performed:
+ 1. DNS & WHOIS metadata
+ 2. TLS certificate info
+ 3. HTTP security headers audit
+ 4. Cookie flags audit
+ 5. Sensitive file/path exposure
+ 6. robots.txt & sitemap.xml parsing
+ 7. Open redirect probe (non-exploiting)
+ 8. Reflected XSS canary in search param (detection only)
+ 9. Directory listing detection
+ 10. Software version disclosure in headers/meta
+ 11. CORS misconfiguration check
+ 12. Clickjacking (X-Frame-Options / CSP frame-ancestors)
+ 13. HSTS check
+ 14. Subdomain enumeration (wordlist)
+ 15. Summary report
+
+Usage:
+ pip install requests dnspython colorama
+ python3 pentest_xamxam.py
+"""
+
+import socket
+import ssl
+import json
+import re
+import datetime
+import urllib.parse
+from dataclasses import dataclass, field
+from typing import Optional
+
+import requests
+import dns.resolver
+from colorama import Fore, Style, init
+
+init(autoreset=True)
+
+# ── Config ────────────────────────────────────────────────────────────────────
+TARGET_HOST = "xamxam.erg.be"
+TARGET_BASE = f"https://{TARGET_HOST}"
+TIMEOUT = 8
+HEADERS = {"User-Agent": "PentestScanner/1.0 (authorized audit)"}
+
+# Paths an attacker would probe first
+SENSITIVE_PATHS = [
+ "/.env", "/.env.local", "/.env.production",
+ "/.git/HEAD", "/.git/config",
+ "/wp-admin", "/wp-login.php", # CMS probes
+ "/admin", "/administrator", "/admin/login",
+ "/phpmyadmin", "/pma",
+ "/backup.zip", "/backup.sql", "/db.sql",
+ "/config.php", "/config.json", "/settings.py",
+ "/robots.txt", "/sitemap.xml",
+ "/.htaccess", "/web.config",
+ "/api", "/api/v1", "/api/users",
+ "/graphql",
+ "/server-status", # Apache status page
+ "/actuator", "/actuator/health", # Spring Boot
+ "/_next/static", # Next.js artefacts
+ "/static",
+ "/uploads", "/files", "/media",
+]
+
+SECURITY_HEADERS = {
+ "Strict-Transport-Security": "HSTS — forces HTTPS",
+ "Content-Security-Policy": "CSP — mitigates XSS",
+ "X-Frame-Options": "Clickjacking protection",
+ "X-Content-Type-Options": "MIME sniffing protection",
+ "Referrer-Policy": "Controls referrer leakage",
+ "Permissions-Policy": "Limits browser feature access",
+ "X-XSS-Protection": "Legacy XSS filter (deprecated but informative)",
+ "Cross-Origin-Opener-Policy": "Isolates browsing context",
+ "Cross-Origin-Resource-Policy": "Controls cross-origin resource sharing",
+}
+
+SUBDOMAIN_WORDLIST = [
+ "www", "mail", "smtp", "ftp", "dev", "staging", "test", "api",
+ "admin", "portal", "old", "beta", "cdn", "static", "media",
+ "docs", "blog", "intranet", "vpn", "login", "auth",
+]
+
+XSS_CANARY = ""
+OPEN_REDIRECT_PAYLOADS = ["//evil.com", "https://evil.com", "/\\evil.com"]
+
+
+# ── Helpers ───────────────────────────────────────────────────────────────────
+def ok(msg): print(f" {Fore.GREEN}[✓]{Style.RESET_ALL} {msg}")
+def warn(msg): print(f" {Fore.YELLOW}[!]{Style.RESET_ALL} {msg}")
+def bad(msg): print(f" {Fore.RED}[✗]{Style.RESET_ALL} {msg}")
+def info(msg): print(f" {Fore.CYAN}[i]{Style.RESET_ALL} {msg}")
+def section(title):
+ print(f"\n{Fore.MAGENTA}{'═'*60}{Style.RESET_ALL}")
+ print(f"{Fore.MAGENTA} {title}{Style.RESET_ALL}")
+ print(f"{Fore.MAGENTA}{'═'*60}{Style.RESET_ALL}")
+
+
+@dataclass
+class Finding:
+ severity: str # CRITICAL / HIGH / MEDIUM / LOW / INFO
+ title: str
+ detail: str
+
+
+findings: list[Finding] = []
+
+def add(severity, title, detail=""):
+ findings.append(Finding(severity, title, detail))
+
+
+def get(path="", params=None, allow_redirects=True) -> Optional[requests.Response]:
+ try:
+ return requests.get(
+ TARGET_BASE + path,
+ params=params,
+ headers=HEADERS,
+ timeout=TIMEOUT,
+ allow_redirects=allow_redirects,
+ verify=True,
+ )
+ except requests.exceptions.SSLError as e:
+ add("HIGH", f"SSL error on {path}", str(e))
+ return None
+ except requests.exceptions.ConnectionError:
+ return None
+ except requests.exceptions.Timeout:
+ return None
+
+
+# ── 1. DNS & IP ───────────────────────────────────────────────────────────────
+def check_dns():
+ section("1. DNS & IP Resolution")
+ try:
+ ip = socket.gethostbyname(TARGET_HOST)
+ info(f"A record → {ip}")
+ add("INFO", "A record", ip)
+ except Exception as e:
+ bad(f"DNS resolution failed: {e}")
+
+ for rtype in ("MX", "TXT", "NS", "AAAA"):
+ try:
+ answers = dns.resolver.resolve(TARGET_HOST, rtype)
+ for r in answers:
+ info(f"{rtype:5s} → {r}")
+ except Exception:
+ pass
+
+
+# ── 2. TLS Certificate ────────────────────────────────────────────────────────
+def check_tls():
+ section("2. TLS Certificate")
+ try:
+ ctx = ssl.create_default_context()
+ with ctx.wrap_socket(socket.socket(), server_hostname=TARGET_HOST) as s:
+ s.connect((TARGET_HOST, 443))
+ cert = s.getpeercert()
+
+ subject = dict(x[0] for x in cert["subject"])
+ issuer = dict(x[0] for x in cert["issuer"])
+ not_after = datetime.datetime.strptime(cert["notAfter"], "%b %d %H:%M:%S %Y %Z")
+ days_left = (not_after.replace(tzinfo=datetime.timezone.utc) - datetime.datetime.now(datetime.UTC)).days
+
+ info(f"Subject : {subject.get('commonName')}")
+ info(f"Issuer : {issuer.get('organizationName')}")
+ info(f"Expires : {not_after.date()} ({days_left} days)")
+
+ sans = [v for t, v in cert.get("subjectAltName", []) if t == "DNS"]
+ info(f"SANs : {', '.join(sans)}")
+
+ if days_left < 30:
+ bad(f"Certificate expires in {days_left} days!")
+ add("HIGH", "Certificate near expiry", f"{days_left} days remaining")
+ else:
+ ok("Certificate valid and not near expiry")
+
+ except Exception as e:
+ bad(f"TLS check failed: {e}")
+ add("HIGH", "TLS check failed", str(e))
+
+
+# ── 3. Security Headers ───────────────────────────────────────────────────────
+def check_headers():
+ section("3. HTTP Security Headers")
+ r = get("/")
+ if not r:
+ bad("Could not reach target"); return
+
+ # Show server / technology leakage
+ for leak_header in ("Server", "X-Powered-By", "X-AspNet-Version", "X-Generator"):
+ val = r.headers.get(leak_header)
+ if val:
+ warn(f"Version disclosure — {leak_header}: {val}")
+ add("LOW", f"Version disclosure: {leak_header}", val)
+
+ for header, description in SECURITY_HEADERS.items():
+ val = r.headers.get(header)
+ if val:
+ ok(f"{header}: {val}")
+ else:
+ bad(f"Missing: {header} ({description})")
+ severity = "HIGH" if header in ("Strict-Transport-Security", "Content-Security-Policy", "X-Frame-Options") else "MEDIUM"
+ add(severity, f"Missing header: {header}", description)
+
+
+# ── 4. Cookie Flags ───────────────────────────────────────────────────────────
+def check_cookies():
+ section("4. Cookie Security Flags")
+ r = get("/")
+ if not r: return
+
+ raw_cookies = r.headers.get("Set-Cookie", "")
+ if not raw_cookies:
+ info("No Set-Cookie header on homepage (may appear after login)")
+ return
+
+ for cookie_str in raw_cookies.split(","):
+ name = cookie_str.split("=")[0].strip()
+ flags = cookie_str.lower()
+ issues = []
+ if "httponly" not in flags:
+ issues.append("missing HttpOnly")
+ if "secure" not in flags:
+ issues.append("missing Secure")
+ if "samesite" not in flags:
+ issues.append("missing SameSite")
+ if issues:
+ warn(f"Cookie '{name}': {', '.join(issues)}")
+ add("MEDIUM", f"Cookie flags: {name}", "; ".join(issues))
+ else:
+ ok(f"Cookie '{name}' has all recommended flags")
+
+
+# ── 5. Sensitive File Exposure ────────────────────────────────────────────────
+def check_sensitive_paths():
+ section("5. Sensitive Path Exposure")
+ for path in SENSITIVE_PATHS:
+ r = get(path, allow_redirects=False)
+ if r is None:
+ continue
+ if r.status_code == 200:
+ size = len(r.content)
+ if path in ("/robots.txt", "/sitemap.xml"):
+ info(f"{r.status_code} {path} ({size}B)")
+ add("INFO", f"Found: {path}", r.text[:300])
+ else:
+ bad(f"{r.status_code} {path} ({size}B) ← EXPOSED")
+ add("HIGH", f"Sensitive path exposed: {path}", f"HTTP 200, {size} bytes")
+ elif r.status_code in (301, 302):
+ loc = r.headers.get("Location", "")
+ info(f"{r.status_code} {path} → {loc}")
+ elif r.status_code == 403:
+ warn(f"403 {path} (exists but forbidden — still interesting)")
+ add("LOW", f"Forbidden path (exists): {path}")
+
+
+# ── 6. robots.txt & sitemap ───────────────────────────────────────────────────
+def check_robots():
+ section("6. robots.txt Analysis")
+ r = get("/robots.txt")
+ if r and r.status_code == 200:
+ info("robots.txt found:")
+ disallowed = [l for l in r.text.splitlines() if "Disallow" in l]
+ for line in disallowed:
+ warn(f" {line.strip()} ← attacker will check these first")
+ path = line.split(":", 1)[-1].strip()
+ add("INFO", "robots.txt Disallow path", path)
+ else:
+ info("No robots.txt found")
+
+
+# ── 7. Open Redirect ─────────────────────────────────────────────────────────
+def check_open_redirect():
+ section("7. Open Redirect Probe")
+ redirect_params = ["redirect", "url", "next", "return", "returnUrl", "goto", "dest", "target"]
+ for param in redirect_params:
+ for payload in OPEN_REDIRECT_PAYLOADS[:1]: # Just one payload for non-destructive check
+ r = get("/", params={param: payload}, allow_redirects=False)
+ if r and r.status_code in (301, 302, 303, 307, 308):
+ loc = r.headers.get("Location", "")
+ if "evil.com" in loc:
+ bad(f"Open redirect via ?{param}= → {loc}")
+ add("HIGH", "Open Redirect", f"?{param}={payload} → {loc}")
+ else:
+ info(f"Redirect on ?{param}= but to: {loc} (not vulnerable)")
+ # No redirect = not vulnerable to this param
+
+
+# ── 8. XSS Canary in Search ───────────────────────────────────────────────────
+def check_xss():
+ section("8. Reflected XSS Canary (search param)")
+ search_paths = ["/", "/repertoire", "/search"]
+ search_params = ["q", "s", "query", "search", "keyword", "term"]
+
+ for path in search_paths:
+ for param in search_params:
+ r = get(path, params={param: XSS_CANARY})
+ if r and XSS_CANARY in r.text:
+ bad(f"XSS canary reflected unencoded at {path}?{param}=")
+ add("CRITICAL", "Reflected XSS", f"{path}?{param}={XSS_CANARY}")
+ elif r and urllib.parse.quote(XSS_CANARY) in r.text:
+ ok(f"{path}?{param}= — canary is URL-encoded (likely safe)")
+ elif r and "<script>" in r.text.lower():
+ ok(f"{path}?{param}= — canary is HTML-encoded (safe)")
+
+
+# ── 9. Directory Listing ──────────────────────────────────────────────────────
+def check_dir_listing():
+ section("9. Directory Listing")
+ dirs = ["/uploads/", "/files/", "/media/", "/static/", "/assets/"]
+ for path in dirs:
+ r = get(path)
+ if r and r.status_code == 200:
+ markers = ["index of", "parent directory", "directory"]
+ if any(m in r.text.lower() for m in markers):
+ bad(f"Directory listing ENABLED at {path}")
+ add("HIGH", "Directory listing enabled", path)
+ else:
+ info(f"{path} → 200 but no listing detected")
+
+
+# ── 10. CORS Misconfiguration ─────────────────────────────────────────────────
+def check_cors():
+ section("10. CORS Misconfiguration")
+ try:
+ r = requests.get(
+ TARGET_BASE + "/api",
+ headers={**HEADERS, "Origin": "https://evil.com"},
+ timeout=TIMEOUT,
+ verify=True,
+ )
+ acao = r.headers.get("Access-Control-Allow-Origin", "")
+ acac = r.headers.get("Access-Control-Allow-Credentials", "")
+ if acao == "*":
+ warn("CORS: Access-Control-Allow-Origin: * (wildcard — no credentials risk)")
+ add("LOW", "CORS wildcard origin", "ACAO: *")
+ elif acao == "https://evil.com":
+ bad("CORS reflects arbitrary Origin!")
+ add("HIGH", "CORS reflects arbitrary Origin", f"ACAO: {acao}, ACAC: {acac}")
+ if acac.lower() == "true":
+ add("CRITICAL", "CORS reflects Origin + credentials allowed", "Full CORS bypass")
+ else:
+ ok(f"CORS origin: '{acao}' (not reflected)")
+ except Exception as e:
+ info(f"CORS check skipped: {e}")
+
+
+# ── 11. Subdomain Enumeration ─────────────────────────────────────────────────
+def check_subdomains():
+ section("11. Subdomain Enumeration (passive wordlist)")
+ parent = ".".join(TARGET_HOST.split(".")[-2:]) # erg.be
+ found = []
+ for sub in SUBDOMAIN_WORDLIST:
+ fqdn = f"{sub}.{parent}"
+ try:
+ ip = socket.gethostbyname(fqdn)
+ info(f"Found: {fqdn} → {ip}")
+ found.append(fqdn)
+ add("INFO", "Subdomain found", f"{fqdn} → {ip}")
+ except socket.gaierror:
+ pass
+ if not found:
+ ok("No additional subdomains discovered from wordlist")
+
+
+# ── 12. HSTS Preload ──────────────────────────────────────────────────────────
+def check_hsts():
+ section("12. HSTS & HTTPS Redirect")
+ # Check HTTP → HTTPS redirect
+ try:
+ r = requests.get(f"http://{TARGET_HOST}/", headers=HEADERS, timeout=TIMEOUT,
+ allow_redirects=False, verify=False)
+ if r.status_code in (301, 302):
+ loc = r.headers.get("Location", "")
+ if loc.startswith("https://"):
+ ok(f"HTTP redirects to HTTPS ({r.status_code})")
+ else:
+ bad(f"HTTP redirects to non-HTTPS: {loc}")
+ add("HIGH", "HTTP does not redirect to HTTPS", loc)
+ else:
+ bad(f"HTTP returns {r.status_code} (no HTTPS redirect)")
+ add("HIGH", "No HTTP→HTTPS redirect", f"Status: {r.status_code}")
+ except Exception:
+ pass
+
+ r = get("/")
+ if r:
+ hsts = r.headers.get("Strict-Transport-Security", "")
+ if "max-age" in hsts:
+ age = re.search(r"max-age=(\d+)", hsts)
+ age_val = int(age.group(1)) if age else 0
+ if age_val < 31536000:
+ warn(f"HSTS max-age too short: {age_val}s (recommend ≥31536000)")
+ add("LOW", "HSTS max-age too short", f"{age_val}s")
+ else:
+ ok(f"HSTS max-age OK: {age_val}s")
+ if "includeSubDomains" not in hsts:
+ warn("HSTS missing includeSubDomains")
+ if "preload" not in hsts:
+ warn("HSTS missing preload directive")
+ else:
+ bad("HSTS header missing entirely")
+ add("HIGH", "HSTS not set")
+
+
+# ── Summary ───────────────────────────────────────────────────────────────────
+def print_summary():
+ section("SUMMARY REPORT")
+ order = {"CRITICAL": 0, "HIGH": 1, "MEDIUM": 2, "LOW": 3, "INFO": 4}
+ color_map = {
+ "CRITICAL": Fore.RED,
+ "HIGH": Fore.YELLOW,
+ "MEDIUM": Fore.CYAN,
+ "LOW": Fore.WHITE,
+ "INFO": Fore.BLUE,
+ }
+ sorted_findings = sorted(findings, key=lambda f: order.get(f.severity, 9))
+ counts = {k: 0 for k in order}
+ for f in sorted_findings:
+ counts[f.severity] = counts.get(f.severity, 0) + 1
+ c = color_map.get(f.severity, "")
+ print(f" {c}[{f.severity:8s}]{Style.RESET_ALL} {f.title}")
+ if f.detail:
+ detail_preview = f.detail[:120].replace("\n", " ")
+ print(f" └─ {detail_preview}")
+
+ print()
+ for sev, cnt in counts.items():
+ if cnt:
+ c = color_map[sev]
+ print(f" {c}{sev}: {cnt}{Style.RESET_ALL}")
+
+ print(f"\n Scan completed: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
+ print(f" Target: {TARGET_BASE}")
+
+
+# ── Main ──────────────────────────────────────────────────────────────────────
+if __name__ == "__main__":
+ print(f"""
+{Fore.CYAN}╔══════════════════════════════════════════════════════════╗
+║ Passive Pentest Scanner — authorized use only ║
+║ Target : {TARGET_HOST:<44} ║
+╚══════════════════════════════════════════════════════════╝{Style.RESET_ALL}
+""")
+ check_dns()
+ check_tls()
+ check_headers()
+ check_cookies()
+ check_sensitive_paths()
+ check_robots()
+ check_open_redirect()
+ check_xss()
+ check_dir_listing()
+ check_cors()
+ check_subdomains()
+ check_hsts()
+ print_summary()