Skip to content

Release assets are extracted without checking their sha256, and public IP lookups run with TLS verification disabled #715

Description

@luandhgt

Two issues in pythonlib/, both in code paths that exist to protect the user. Reporting together because they are one-line-ish fixes in the same package; happy to split into separate issues if you'd prefer.

1. Downloaded release assets are never verified against their digest

webdl() streams a release asset into a buffer, install_versioned() hands that buffer straight to unzip(), and the extracted tree is then chmod -R 755'd and executed.

The digest is already available. PkgManager.check_asset() reads it from the GitHub API response and stores it:

digest = asset.get('digest') or ''
if digest.startswith('sha256:'):
    self.installed_sha256 = digest.split(':', 1)[1]

AvailableVersion.sha256 carries it further, into version.json. But it is never compared against the downloaded bytes. Every sha256 == comparison in the package compares metadata to metadata to identify which installed version a folder holds; hashlib appears once, in utils.py, to key a config cache.

So the archive is accepted on transport security alone. A truncated download, a bad mirror, or a substituted asset all extract silently.

Repro: point webdl() at a modified archive — installation completes normally, version.json records the expected sha256 that the installed bytes do not have.

2. public_ip() disables TLS certificate verification

camoufox/ip.py:

with _suppress_insecure_warning():
    resp = requests.get(url, ..., verify=False)

_suppress_insecure_warning() filters out urllib3's InsecureRequestWarning, so the disabled verification is also silent.

These requests go through the user's proxy when one is configured — the exact position an attacker occupies. A forged response controls what public_ip() returns, and callers use that to spoof the WebRTC IP. validate_ip() constrains the result to a well-formed address, but which address is the attacker's choice, so the leak the function exists to prevent becomes attacker-selectable.

The ip-api.com lookups in sync_api.py / async_api.py have a related weakness (plain http://), but that appears to be forced by ip-api's free tier, so I have left it alone rather than break the feature.

Environment

Reproduced on main @ f1febf4, Python 3.13, Linux.

Fix

PR follows — verify=True plus a verify_sha256() call between download and extraction on both install paths, with 12 unit tests. No browser patches touched.

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