From 84d1d7196cf5a9ecc977bfffec6a06fc829971fb Mon Sep 17 00:00:00 2001 From: splitsec2 <35583321+splitsec2@users.noreply.github.com> Date: Mon, 19 Oct 2026 23:09:26 -0600 Subject: [PATCH] fix(irc): pin the TLS context to TLS 1.2 or newer (#1455) CodeQL on my fork flagged `ssl.create_default_context()` in the IRC client as allowing TLS 1.0 and 1.1 (`py/insecure-protocol`, rated high). In practice the shipped image is already fine. Python 3.10+ sets a TLS 1.2 floor on the default context, and on the current image (Python 3.14.7, OpenSSL 3.5.7) `minimum_version` comes back as TLS 1.2. An OpenSSL config on the host can still lower that floor, so this pins it with one line, `context.minimum_version = ssl.TLSVersion.TLSv1_2`. Added `tests/irc/test_client_tls.py`. It drops the floor to the minimum before `connect()` runs, then checks that `connect()` raised it back to 1.2. It fails without the change. Certificate and hostname verification are still off (`CERT_NONE`). I left that alone because of the comment about self-signed certs on IRC servers. Turning verification on, or making it a setting, would be the bigger fix, but that is ultimately a call for @calibrain if you want a PR for it. --- shelfmark/release_sources/irc/client.py | 2 ++ tests/irc/test_client_tls.py | 33 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 tests/irc/test_client_tls.py diff --git a/shelfmark/release_sources/irc/client.py b/shelfmark/release_sources/irc/client.py index dcea156e..5cc71249 100644 --- a/shelfmark/release_sources/irc/client.py +++ b/shelfmark/release_sources/irc/client.py @@ -123,6 +123,8 @@ class IRCClient: # Wrap with TLS if needed if self.use_tls: context = ssl.create_default_context() + # Python already defaults to TLS 1.2; pin it so an OpenSSL config cannot lower it + context.minimum_version = ssl.TLSVersion.TLSv1_2 # Skip verification for self-signed certs common on IRC servers context.check_hostname = False context.verify_mode = ssl.CERT_NONE diff --git a/tests/irc/test_client_tls.py b/tests/irc/test_client_tls.py new file mode 100644 index 00000000..fa102190 --- /dev/null +++ b/tests/irc/test_client_tls.py @@ -0,0 +1,33 @@ +"""The IRC TLS context must not allow anything older than TLS 1.2.""" + +import ssl + +import pytest + +from shelfmark.release_sources.irc.client import IRCClient, IRCConnectionError + + +def test_tls_context_refuses_tls_1_0_and_1_1(monkeypatch: pytest.MonkeyPatch) -> None: + contexts: list[ssl.SSLContext] = [] + real_create = ssl.create_default_context + + def capture(*args, **kwargs) -> ssl.SSLContext: + context = real_create(*args, **kwargs) + # Allow everything first, so the test fails if connect() does not raise the floor + context.minimum_version = ssl.TLSVersion.MINIMUM_SUPPORTED + + def refuse(*_args, **_kwargs): + raise OSError("no network in tests") + + context.wrap_socket = refuse # type: ignore[method-assign] + contexts.append(context) + return context + + monkeypatch.setattr(ssl, "create_default_context", capture) + client = IRCClient(nick="reader", server="irc.example.test", port=6697, use_tls=True) + + with pytest.raises(IRCConnectionError): + client.connect() + + assert len(contexts) == 1 + assert contexts[0].minimum_version == ssl.TLSVersion.TLSv1_2