From 2b763efef992c53ddd8f902e5ab49b4766c805dc Mon Sep 17 00:00:00 2001 From: 3252a8 <3252a8@proton.me> Date: Mon, 1 Jun 2026 14:20:38 +0300 Subject: [PATCH] fix: redact secrets and ids from panel dry-run logs CodeQL flagged clear-text logging of sensitive information in the panel dry-run logger: it dumped the full request payload (which can include proxy credentials like trojanPassword/ssPassword and PII such as email and telegramId) and the raw endpoint (embedding user UUIDs). Recursively redact values under sensitive keys before building the payload preview, and mask opaque id-like segments in logged endpoints. --- .../bot/services/panel_dry_run_api_service.py | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/backend/bot/services/panel_dry_run_api_service.py b/backend/bot/services/panel_dry_run_api_service.py index fa47339..a1d84b7 100644 --- a/backend/bot/services/panel_dry_run_api_service.py +++ b/backend/bot/services/panel_dry_run_api_service.py @@ -22,6 +22,20 @@ _INTERNAL_SQUAD_BULK_RE = re.compile( _LIVE_POST_ENDPOINTS = frozenset({"/system/tools/happ/encrypt"}) _KNOWN_TRAFFIC_STRATEGIES = frozenset({"NO_RESET", "DAY", "WEEK", "MONTH"}) +# Panel payloads can carry proxy credentials (e.g. trojanPassword, ssPassword, +# vless/vmess uuids) and PII (email, telegramId). Redact such values before they +# reach the dry-run log so secrets are never written in clear text. +_SENSITIVE_KEY_RE = re.compile( + r"pass|pwd|secret|token|key|credential|auth|cookie|session|" + r"email|mail|phone|telegram|mnemonic", + re.IGNORECASE, +) +# Mask opaque id-like path segments (UUIDs, long tokens) in logged endpoints. +_ENDPOINT_ID_RE = re.compile( + r"(?<=/)(?:[0-9a-fA-F]{8}-[0-9a-fA-F-]{8,}|[A-Za-z0-9_-]{24,})" +) +_REDACTED = "***" + @dataclass class _DryRunValidation: @@ -89,11 +103,35 @@ class PanelDryRunApiService(PanelApiService): return f"/{str(endpoint or '').lstrip('/')}" @staticmethod - def _payload_preview(payload: Any) -> str: + def _safe_endpoint(endpoint: str) -> str: + """Mask opaque id-like segments so logged paths carry no private ids.""" + return _ENDPOINT_ID_RE.sub("", str(endpoint or "")) + + @classmethod + def _redact(cls, value: Any, _depth: int = 0) -> Any: + """Recursively replace values under sensitive keys with a placeholder.""" + if _depth > 6: + return "..." + if isinstance(value, dict): + return { + k: ( + _REDACTED + if isinstance(k, str) and _SENSITIVE_KEY_RE.search(k) + else cls._redact(v, _depth + 1) + ) + for k, v in value.items() + } + if isinstance(value, (list, tuple)): + return [cls._redact(item, _depth + 1) for item in value] + return value + + @classmethod + def _payload_preview(cls, payload: Any) -> str: + redacted = cls._redact(payload) try: - text = json.dumps(payload, ensure_ascii=False, default=str, sort_keys=True) + text = json.dumps(redacted, ensure_ascii=False, default=str, sort_keys=True) except Exception: - text = str(payload) + text = str(redacted) if len(text) > 1200: return f"{text[:1200]}..." return text @@ -111,7 +149,7 @@ class PanelDryRunApiService(PanelApiService): "[PANEL DRY-RUN %s] would %s %s payload=%s%s", status, method, - endpoint, + self._safe_endpoint(endpoint), self._payload_preview(payload), f" errors={errors}" if errors else "", )