{"record":{"id":"a1405204b54f24ca","repo":"CloakHQ/CloakBrowser","slug":"version-mismatch-in-signed-pro-sha256sums-request-a14052","errorCode":null,"errorMessage":"Version mismatch in signed Pro SHA256SUMS: requested {version}, manifest declares {declared or 'none'}. Refusing (possible downgrade).","messagePattern":"Version mismatch in signed Pro SHA256SUMS: requested (.+?), manifest declares (.+?)\\. Refusing \\(possible downgrade\\)\\.","errorType":"exception","errorClass":"BinaryVerificationError","httpStatus":null,"severity":"critical","filePath":"cloakbrowser/download.py","lineNumber":597,"sourceCode":"        # BinaryVerificationError (which it surfaces as a tampering signal).\n        raise RuntimeError(\n            f\"Could not fetch the signed SHA256SUMS for Pro {version} ({exc})\"\n        ) from exc\n\n    manifest_bytes = manifest_resp.content\n    # _verify_signature / _verify_checksum raise plain RuntimeError; convert to\n    # BinaryVerificationError so the Pro router treats them as tampering signals\n    # (re-raise) rather than transient failures (fall back to free).\n    try:\n        _verify_signature(manifest_bytes, sig_resp.content)\n    except RuntimeError as exc:\n        raise BinaryVerificationError(str(exc)) from exc\n    manifest_text = manifest_bytes.decode(\"utf-8\")\n\n    # Version binding: same forced-downgrade defense as the official path.\n    declared = _parse_manifest_version(manifest_text)\n    if declared != version:\n        raise BinaryVerificationError(\n            f\"Version mismatch in signed Pro SHA256SUMS: requested {version}, \"\n            f\"manifest declares {declared or 'none'}. Refusing (possible downgrade).\"\n        )\n\n    tarball_name = get_archive_name()\n    expected = _parse_checksums(manifest_text).get(tarball_name)\n    if expected is None:\n        raise BinaryVerificationError(\n            f\"Signature-verified Pro SHA256SUMS has no entry for {tarball_name} — \"\n            f\"cannot confirm binary integrity.\"\n        )\n    try:\n        _verify_checksum(file_path, expected)\n    except RuntimeError as exc:\n        raise BinaryVerificationError(str(exc)) from exc\n\n\ndef _verify_download_checksum(file_path: Path, version: str | None = None) -> None:","sourceCodeStart":579,"sourceCodeEnd":615,"githubUrl":"https://github.com/CloakHQ/CloakBrowser/blob/d6bad5de261bedf025280ace1d14e800aee13923/cloakbrowser/download.py#L579-L615","documentation":"The signature on the Pro SHA256SUMS is valid, but the version declared inside the manifest differs from the requested version. This blocks a forced-downgrade attack where a genuinely-signed older release is served in place of the requested one.","triggerScenarios":"Pro download where _parse_manifest_version(manifest_text) != requested version — e.g. a mirror/cache serving an older signed manifest.","commonSituations":"Stale CDN cache for the manifest; downgrade-serving proxy; server-side release mix-up.","solutions":["Clear caches and retry with the exact version pinned","Check for a MITM proxy rewriting responses","Report upstream with requested vs declared versions"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"from cloakbrowser.download import BinaryVerificationError\ntry:\n    _download_pro_binary(PIN, key)\nexcept BinaryVerificationError as e:\n    if \"Version mismatch\" in str(e):\n        clear_caches(); _download_pro_binary(PIN, key)  # once\n    else:\n        raise","preventionTips":["Always pin exact versions for reproducible installs","Investigate proxies that cache release metadata when mismatches repeat"],"tags":["security","downgrade","version-mismatch","verification"],"backgroundTag":"version-pin-mismatch","analyzedSha":"d6bad5de261bedf025280ace1d14e800aee13923","analyzedAt":"2026-08-28T14:13:12.918Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}