Skip to content

Release for security updates after certificates incident #4299

Closed

Description

@thomas-ferchau

Upgrade to rules_python 2.4.5 to pick up the certifi update, or follow the patch/workarounds in #4299 (comment)
-- rules_python maintainers


From https://discuss.python.org/t/information-for-python-users-regarding-emudhra-emsign-ca-certificate-security-incident/109576 :

A security incident affecting eMudhra intermediate certificates has required removing the emSign root CA certificate from CA bundles such as “certifi”. It’s important to immediately upgrade the software packages below to at least the versions specified and rebuild container images to fetch the latest system certificates.

Failure to do so could result in monster-in-the-middle (MITM) attacks against TLS clients, including python.org and pypi.org .

certifi 2026.10.19
pip 26.2.2
uv 0.13.4
sigstore 4.5.1

For all existing virtual environments on your system, please upgrade pip and uv to the latest versions.

In a Python project that uses Bazel, I find an older version of certifi (2026.7.22) in the MODULE.bazel.lock file:

  "facts": {
    "@@rules_python+//python/extensions:pip.bzl%pip": {
      "dist_hashes": {
        "https://pypi.org/simple": {
          "backports-tarfile": {
            "https://files.pythonhosted.org/packages/86/72/cd9b395f25e290e633655a100af28cb253e4393396264a98bd5f5951d50f/backports_tarfile-1.2.0.tar.gz": "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991",
            "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl": "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"
          },
          "certifi": {
            "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl": "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775",
            "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz": "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55"
          },
....

But I am happy to see that the version update has already been applied in rules_python's main branch: #4297

Is there a new release planned to fix this security issue?

Or, if that release should take some more time, is there a way to use the already modified version, or to define a patch that Bazel can apply locally? Currently the dependency definition looks like this: bazel_dep(name = "rules_python", version = "2.4.2")

Thank you very much!

Pinned by rickeylev

Activity

  1. rickeylev commented on Oct 22, 2026

    @rickeylev
    Collaborator

    Looking at what that PR fixes, it looks like the only thing of relevance to users is the tools/publish requirements files. That gets used by, I think its the twine binary used by default for the py_wheel .publish target.

    As a user, you can specify your own twine binary as an arg. Alternatively you can patch that requirements file in tools/publish. I'll have a my agent post how to do both methods shortly.

    #4301 for the patch release

  2. rickeylev commented on Oct 22, 2026

    @rickeylev
    Collaborator

    Recommended: Upgrade to rules_python 2.4.4

    Upgrade to
    rules_python 2.4.4
    to pick up both certificate fixes:

    In MODULE.bazel:

    bazel_dep(name = "rules_python", version = "2.4.4")

    If your project tracks MODULE.bazel.lock, refresh it so cached facts reflect
    the updated certifi hashes:

    bazel mod deps --lockfile_mode=update

    Note

    Prior to 2.4.4, rules_python was affected in two places:

    1. Internal pip (python/private/pypi/deps.bzl, <= 2.4.3): Pinned
      pypi__pip to pip 26.0.1 (which vendors certifi 2026.01.04). This
      internal pip is used when rules_python invokes pip to make network
      requests: locking requirements via compile_pip_requirements, building
      sdists in whl_library, or falling back to pip to download wheels (for
      example, when using simpleapi_skip). Standard wheel downloads handled by
      Bazel's downloader use the host OS trust store and lockfile SHA-256 hashes.
    2. Wheel publishing (tools/publish/requirements_*.txt, <= 2.4.2):
      Pinned certifi==2026.7.22 in the rules_python_publish_deps hub used by
      @rules_python//tools/publish:twine (the default twine_binary for
      py_wheel's manual <name>.publish target). Because rules_python's
      MODULE.bazel registers rules_python_publish_deps with the pip
      extension, Bazel records certifi-2026.7.22 in MODULE.bazel.lock under
      facts whenever the pip extension is evaluated, even if
      @rules_python//tools/publish:twine is never fetched or built.

    Workaround 1: Patch rules_python via single_version_override

    If you cannot upgrade to 2.4.4 yet, you can patch rules_python in place
    using single_version_override (ensure patches/BUILD.bazel exists, even if
    empty, so the patch labels are valid).

    1a. Patch pip in python/private/pypi/deps.bzl (for <= 2.4.3)

    Save patches/rules-python-pip.patch to upgrade rules_python's internal pip
    to 26.2.2, pip-tools to 7.6.2, and associated internal PyPI tooling
    dependencies (applies cleanly to rules_python 2.0.0 through 2.4.3):

    Note

    The full commit (94a42cae6fdc018ee2df49ac43146fecf4454f20) from PR #4310
    also adds a new pypi__typing_extensions repository to MODULE.bazel,
    python/private/pypi/deps.bzl, and python/private/pypi/pip_compile.bzl.
    Because single_version_override reads MODULE.bazel from the Bazel Central
    Registry before applying patches, new repositories cannot be added to
    use_repo via single_version_override.

    The patch below omits pypi__typing_extensions, which is only required by
    pip-tools 7.6.2 when running compile_pip_requirements with Python < 3.11
    (on Python >= 3.11, including rules_python 2.4's default Python 3.14, it
    is unused). If you use compile_pip_requirements with Python 3.10, pass
    extra_deps = ["@pypi//typing_extensions"] to compile_pip_requirements or
    upgrade to rules_python 2.4.4.

    rules_python-2.4.2-certifi-2026-10-19.patch

    Details
    diff --git a/python/private/pypi/deps.bzl b/python/private/pypi/deps.bzl
    --- a/python/private/pypi/deps.bzl
    +++ b/python/private/pypi/deps.bzl
    @@ -21,13 +21,13 @@ _RULE_DEPS = [
         # START: maintained by 'bazel run //dev/update_deps:update_pip_deps'
         (
             "pypi__build",
    -        "https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl",
    -        "6a07c1b8eb6f2b311b96fcbdbce5dab5fe637ffda0fd83c9cac622e927501596",
    +        "https://files.pythonhosted.org/packages/ad/9b/9fb3585dabcd73a1b2a6267f63f62649347c9e6d072c9fde365b105abb2c/build-1.6.1-py3-none-any.whl",
    +        "ecd351a4be9d35a9eaaba244a7687143c9c7d4aea6ac964e7e7ddab20cbcf4e7",
         ),
         (
             "pypi__click",
    -        "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl",
    -        "981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6",
    +        "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl",
    +        "255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360",
         ),
         (
             "pypi__colorama",
    @@ -36,23 +36,23 @@ _RULE_DEPS = [
         ),
         (
             "pypi__importlib_metadata",
    -        "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl",
    -        "5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151",
    +        "https://files.pythonhosted.org/packages/b3/55/ecca97ae19075f1fac62def77731e7f535e6c1fb8f92ff08160c5e6dade8/importlib_metadata-9.0.1-py3-none-any.whl",
    +        "bba5600596a7e21f3eef53281cf28d6a5195634d2f2b78ff9501a3272c6eaab0",
         ),
         (
             "pypi__installer",
    -        "https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl",
    -        "05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53",
    +        "https://files.pythonhosted.org/packages/d7/7a/63547a792a12148882205d79e07644091d5b7690f40c2bb9d41452a8bdc2/installer-1.1.0-py3-none-any.whl",
    +        "f55f5728ff61d3dd54dbc5a397cf3f7307cb64b180c20b72afbebf01c9e2c8a0",
         ),
         (
             "pypi__more_itertools",
    -        "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl",
    -        "52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b",
    +        "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl",
    +        "4b65538ae22f6fed0ce4874efd317463a7489796a0939fa66824dd542125a192",
         ),
         (
             "pypi__packaging",
    -        "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl",
    -        "b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529",
    +        "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl",
    +        "d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c",
         ),
         (
             "pypi__pep517",
    @@ -61,38 +61,38 @@ _RULE_DEPS = [
         ),
         (
             "pypi__pip",
    -        "https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl",
    -        "bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b",
    +        "https://files.pythonhosted.org/packages/3f/06/3e4420302363fbb71be3c7f35ce042f54bfca330e3e66b3a2e3c4cca579f/pip-26.2.2-py3-none-any.whl",
    +        "fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70",
         ),
         (
             "pypi__pip_tools",
    -        "https://files.pythonhosted.org/packages/6e/74/59906d876c6cb1137f42a137164f2fe683b06283cde84bfcf7f5dd43970b/pip_tools-7.5.3-py3-none-any.whl",
    -        "3aac0c473240ae90db7213c033401f345b05197293ccbdd2704e52e7a783785e",
    +        "https://files.pythonhosted.org/packages/4b/68/f3bd09c53ed3159bb1349e1d5859ad1ea7755b8e4cd50174290e9e8cbb47/pip_tools-7.6.2-py3-none-any.whl",
    +        "f37eb4b736859c2c30230e50977312c61918b7ef931071ff7811fd067715c25f",
         ),
         (
             "pypi__pyproject_hooks",
    -        "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl",
    -        "9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913",
    +        "https://files.pythonhosted.org/packages/85/11/044d1ae1b4ec0d7af88ee5bc91e081be1022533032b906a7bdabdbb60977/pyproject_hooks-1.3.3-py3-none-any.whl",
    +        "5fc53fdac9f7bd63fbcdc868fb5f90b4784d78a53a3d3388cd738b807441a20b",
         ),
         (
             "pypi__setuptools",
    -        "https://files.pythonhosted.org/packages/e1/c6/76dc613121b793286a3f91621d7b75a2b493e0390ddca50f11993eadf192/setuptools-82.0.0-py3-none-any.whl",
    -        "70b18734b607bd1da571d097d236cfcfacaf01de45717d59e6e04b96877532e0",
    +        "https://files.pythonhosted.org/packages/ef/55/6dc6d6bb953bdfc52519a0059592c52b6e3b8ad51cf8256dffceb55b0610/setuptools-84.2.1-py3-none-any.whl",
    +        "ca140b45d5325a9478f880e351484f62fef15f336462e449ca0c03c873d589c2",
         ),
         (
             "pypi__tomli",
    -        "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl",
    -        "1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a",
    +        "https://files.pythonhosted.org/packages/60/3f/3e3f8fd0919249b0200c80fbc4f9a1e70be19f9883da71dfb7f8b9ab8aca/tomli-2.5.0-py3-none-any.whl",
    +        "32a7b79ac57a2e83670ce329ccf675798bc5a2094783a63676866b70503f2e2b",
         ),
         (
             "pypi__wheel",
    -        "https://files.pythonhosted.org/packages/87/22/b76d483683216dde3d67cba61fb2444be8d5be289bf628c13fc0fd90e5f9/wheel-0.46.3-py3-none-any.whl",
    -        "4b399d56c9d9338230118d705d9737a2a468ccca63d5e813e2a4fc7815d8bc4d",
    +        "https://files.pythonhosted.org/packages/2e/29/69cfbb602cd91690c55d38ba9fe53e6a7e76a6fa647bf38f19c138d25449/wheel-0.48.0-py3-none-any.whl",
    +        "3217dcc807155e45db462d7ef2431f5ddda0d7273b700d05a67b271ceb1287ab",
         ),
         (
             "pypi__zipp",
    -        "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl",
    -        "071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e",
    +        "https://files.pythonhosted.org/packages/b8/44/7bd2007260da11cccca29ba2d4c345f1287aa663db38ee7cefeabf6386a5/zipp-4.1.2-py3-none-any.whl",
    +        "b30cb6cd253122169c47de245ca24a86bac2a5d3802ba15bf7ba6414eb9e144d",
         ),
         # END: maintained by 'bazel run //dev/update_deps:update_pip_deps'
     ]
    Minimal diff (only pypi__pip and pypi__pip_tools)
    diff --git a/python/private/pypi/deps.bzl b/python/private/pypi/deps.bzl
    --- a/python/private/pypi/deps.bzl
    +++ b/python/private/pypi/deps.bzl
    @@ -61,13 +61,13 @@ _RULE_DEPS = [
         ),
         (
             "pypi__pip",
    -        "https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl",
    -        "bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b",
    +        "https://files.pythonhosted.org/packages/3f/06/3e4420302363fbb71be3c7f35ce042f54bfca330e3e66b3a2e3c4cca579f/pip-26.2.2-py3-none-any.whl",
    +        "fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70",
         ),
         (
             "pypi__pip_tools",
    -        "https://files.pythonhosted.org/packages/6e/74/59906d876c6cb1137f42a137164f2fe683b06283cde84bfcf7f5dd43970b/pip_tools-7.5.3-py3-none-any.whl",
    -        "3aac0c473240ae90db7213c033401f345b05197293ccbdd2704e52e7a783785e",
    +        "https://files.pythonhosted.org/packages/4b/68/f3bd09c53ed3159bb1349e1d5859ad1ea7755b8e4cd50174290e9e8cbb47/pip_tools-7.6.2-py3-none-any.whl",
    +        "f37eb4b736859c2c30230e50977312c61918b7ef931071ff7811fd067715c25f",
         ),
         (
             "pypi__pyproject_hooks",

    1b. Patch certifi in tools/publish (for <= 2.4.2; already in 2.4.3)

    (rules_python-2.4.2-certifi-2026-10-19.patch)

    This patches tools/publish/requirements_*.txt inside rules_python before the
    pip module extension runs. It both upgrades the default twine environment
    and replaces certifi 2026.7.22 with certifi 2026.10.19 in
    MODULE.bazel.lock.

    Note

    The full commit (711b314bb5809d1ef801b86df9e217052c69f2c6) from PR #4297
    does not apply cleanly to 2.4.2. The diff below contains the relevant parts
    and applies cleanly to 2.4.2.

    Save patches/rules-python-certifi.patch:

    diff --git a/tools/publish/requirements_darwin.txt b/tools/publish/requirements_darwin.txt
    --- a/tools/publish/requirements_darwin.txt
    +++ b/tools/publish/requirements_darwin.txt
    @@ -8,5 +8,5 @@
         # via jaraco-context
    -certifi==2026.7.22 \
    -    --hash=sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775 \
    -    --hash=sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55
    +certifi==2026.10.19 \
    +    --hash=sha256:035c1e85572b141bf1c3a3eff0e33a8eb74917522f2559075ff8d2fea780a1ae \
    +    --hash=sha256:42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b
         # via requests
    diff --git a/tools/publish/requirements_linux.txt b/tools/publish/requirements_linux.txt
    --- a/tools/publish/requirements_linux.txt
    +++ b/tools/publish/requirements_linux.txt
    @@ -8,5 +8,5 @@
         # via jaraco-context
    -certifi==2026.7.22 \
    -    --hash=sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775 \
    -    --hash=sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55
    +certifi==2026.10.19 \
    +    --hash=sha256:035c1e85572b141bf1c3a3eff0e33a8eb74917522f2559075ff8d2fea780a1ae \
    +    --hash=sha256:42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b
         # via requests
    diff --git a/tools/publish/requirements_universal.txt b/tools/publish/requirements_universal.txt
    --- a/tools/publish/requirements_universal.txt
    +++ b/tools/publish/requirements_universal.txt
    @@ -8,5 +8,5 @@
         # via jaraco-context
    -certifi==2026.7.22 \
    -    --hash=sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775 \
    -    --hash=sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55
    +certifi==2026.10.19 \
    +    --hash=sha256:035c1e85572b141bf1c3a3eff0e33a8eb74917522f2559075ff8d2fea780a1ae \
    +    --hash=sha256:42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b
         # via requests
    diff --git a/tools/publish/requirements_windows.txt b/tools/publish/requirements_windows.txt
    --- a/tools/publish/requirements_windows.txt
    +++ b/tools/publish/requirements_windows.txt
    @@ -8,5 +8,5 @@
         # via jaraco-context
    -certifi==2026.7.22 \
    -    --hash=sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775 \
    -    --hash=sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55
    +certifi==2026.10.19 \
    +    --hash=sha256:035c1e85572b141bf1c3a3eff0e33a8eb74917522f2559075ff8d2fea780a1ae \
    +    --hash=sha256:42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b
         # via requests

    2. Apply the patches in MODULE.bazel

    For rules_python 2.4.2 (apply both patches; on 2.4.3, only
    //patches:rules-python-pip.patch is needed):

    bazel_dep(name = "rules_python", version = "2.4.2")
    single_version_override(
        module_name = "rules_python",
        patch_strip = 1,
        patches = [
            "//patches:rules-python-certifi.patch",
            "//patches:rules-python-pip.patch",
        ],
        version = "2.4.2",
    )

    3. Refresh MODULE.bazel.lock (if using a Bazel lockfile)

    If your project tracks MODULE.bazel.lock, update it so the cached facts
    reflect certifi 2026.10.19:

    bazel mod deps --lockfile_mode=update

    Workaround 2: Provide Your Own twine to py_wheel

    If you use py_wheel and its <name>.publish target, you can supply twine
    from your own locked pip.parse hub (where twine and certifi>=2026.10.19
    are locked in your own requirements file) instead of using
    @rules_python//tools/publish:twine.

    Warning

    In py_wheel,
    twine_binary defaults to Label("//tools/publish:twine") when Bzlmod is
    enabled, and if twine_binary: is checked before elif twine:. Therefore,
    you must either override twine_binary directly, or set twine_binary = None
    when passing twine.

    Option A: Override twine_binary with py_console_script_binary

    load("@rules_python//python:packaging.bzl", "py_wheel")
    load(
        "@rules_python//python/entry_points:py_console_script_binary.bzl",
        "py_console_script_binary",
    )
    
    py_console_script_binary(
        name = "twine",
        pkg = "@pypi//twine",
        script = "twine",
    )
    
    py_wheel(
        name = "my_wheel",
        distribution = "my_pkg",
        twine_binary = ":twine",
        version = "0.1.0",
        deps = [":my_lib"],
    )

    Option B: Pass twine (py_library) and clear twine_binary

    load("@rules_python//python:packaging.bzl", "py_wheel")
    
    py_wheel(
        name = "my_wheel",
        distribution = "my_pkg",
        twine = "@pypi//twine",
        twine_binary = None,
        version = "0.1.0",
        deps = [":my_lib"],
    )

    (Note: Workaround 2 only replaces @rules_python//tools/publish:twine during
    wheel publishing; upgrading to 2.4.4 or applying Workaround 1 is required to
    update rules_python's internal pip and remove certifi 2026.7.22 from
    MODULE.bazel.lock.)

  3. aignas commented on Oct 22, 2026

    @aignas
    Collaborator

    Related to this, should we use @pypi//twine so that the override is easier to do? This is similar to what we did for pytest.

  4. rickeylev commented on Oct 22, 2026

    @rickeylev
    Collaborator

    Our twine target is just a thin wrapper, right? Like just the entry point generation? If so, yeah, that would make sense. Though, we'd need some way to provide a default implementation. If @pypi goes back to the user's closure, and they don't have twine, then it'll give an error. Maybe thats OK. It basically pushes the problem of providing dependencies for our tools onto the user and we wouldn't have need to provide the various hard-coded urls for it.

  5. stephanretool commented on Oct 22, 2026

    @stephanretool

    Hi @rickeylev !

    If I understand correctly, only upgrading certifi leaves some gaps where rules_python still trusts the compromised certificates when it uses pip. Full disclosure: I'm not familiar with rules_python internals, and I used AI to trace through the code and run the tests below. I may be misreading how things fit together, so feel free to ignore this if it actually is nothing.

    python/private/pypi/deps.bzl still seems to pin pypi__pip to pip 26.0.1. The discuss.python.org post quoted above lists pip 26.2.2 as a required upgrade. A CPython core developer explains why in the same thread:

    pip always loads the CA certificates from its vendored certifi in addition to the system trust store, and there is no supported way to disable this. REQUESTS_CA_BUNDLE / --cert only add CAs; truststore is used “in addition to certifi” by design. As a result, any pip < 26.2.2 will keep trusting the compromised intermediate CAs regardless of the system trust store, so distrusting them at the OS level is not enough.

    They also say that "Updating pip is the only reliable fix."
    pip 26.0.1 vendors certifi 2026.01.04, which still contains emSign ECC Root CA - G3. So whenever rules_python's pinned pip makes a network request, it still trusts the compromised CAs, even when the host's trust store and the user's own certifi (including the one bumped in rules_python 2.4.3) are up to date.

    If I understand correctly, rules_python's pip reaches the network in a few places:

    1. compile_pip_requirements: pip-tools resolves and downloads through the pinned pip. This seems the most sensitive case, because with --generate-hashes the lockfile would record hashes of whatever was served.
    2. Building sdists in whl_library: in 2.4.3, pip seems to build sdists with build isolation, so it downloads build dependencies (like setuptools) from the index itself. In a separate test with plain pip, those build-dependency downloads weren't hash-checked even in --require-hashes mode.
    3. The pip fallback in pip.parse: when a distribution has no URL from the index metadata (for example via simpleapi_skip), whl_library seems to fall back to pip for the download itself.

    I tried this with a small Bazel 9.3.1 workspace on rules_python 2.4.3, in a Debian trixie container whose OS trust store rejects the eMudhra test host (dv-g3b-emudhra.we-have-a-problem.com):

    • Case 1: --index-url pointing at the test host: pip-tools fetches the page over TLS and only skips it because of its Content-Type.
    • Case 2: building betterproto (sdist-only) logs "Installing build dependencies", so pip goes to the index itself. I couldn't point that index at the test host without also redirecting the Bazel downloader, so I'm assuming it behaves like the other two cases. extra_pip_args = ["--no-index", "--no-build-isolation"], may work as a mitigation for backends that are bundled.
    • Case 3: with six in simpleapi_skip and --index-url pointing at the test host: the TLS handshake succeeds, and pip only fails with "No matching distribution found".

    With a single_version_override patch bumping pypi__pip to 26.2.2, cases 1 and 3 fail with CERTIFICATE_VERIFY_FAILED, as expected. Turns out, with pip 26.2.2, the pinned pip-tools 7.5.3 crashes in compile_pip_requirements. Bumping pypi__pip_tools to 7.6.2 fixed that, and resolution against PyPI worked again.

    The Bazel downloader itself rejected the test host (PKIX path building failed), so the default wheel download path seems unaffected. This only seems to matter where rules_python's own pip goes to the network.

    Would it makes sense to ship a fix that bumps pypi__pip to 26.2.2 (together with pypi__pip_tools 7.6.2) make sense? Users with hashed lockfiles are protected for the package files themselves, but I believe cases 1 and 2 aren't covered by hashes. For what it's worth, I haven't tested if the bumps would affect anything else. It seems like rules_python ships a Python 3.9 toolchain still and pip 26.2.2 requires Python >= 10, so there's a chance of some compatibility issues. No fixed 3.9 pip exists as far as I can tell, though.
    Happy to share the test workspace or the patch.

    Thanks for maintaining this!

  6. thomas-ferchau commented on Oct 22, 2026

    @thomas-ferchau
    Author

    @stephanretool

    Wow! Maybe you should create a new ticket with this text. I guess your contribution would get lost in this closed ticket.

  7. thomas-ferchau commented on Oct 22, 2026

    @thomas-ferchau
    Author

    @rickeylev

    Upgrade to rules_python 2.4.2 to pick up the certifi update, or follow the patch/workarounds in #4299 (comment)
    -- rules_python maintainers

    I think it should be 2.4.3

  8. rickeylev commented on Oct 22, 2026

    @rickeylev
    Collaborator

    Argh, pip, forgot about that. Thanks @stephanretool .

  9. rickeylev commented on Oct 23, 2026

    @rickeylev
    Collaborator

    2.4.4 is released that upgrades pip to 26.2.2

  10. rickeylev commented on Oct 23, 2026

    @rickeylev
    Collaborator

    While talking to some buddies over D&D, one mentioned that uv was also affected by this, so #4329 upgrades the default uv we set as part of the uv extension. It's been released in 2.4.5.

    I also published an advisory in our repo: GHSA-f8vq-jw3w-q789

  11. stephanretool commented on Oct 23, 2026

    @stephanretool

    Thank you, appreciate the quick fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions