diff --git a/backport-CVE-2025-62611.patch b/backport-CVE-2025-62611.patch new file mode 100644 index 0000000000000000000000000000000000000000..2f3aaba1df18ec73723f99afc25e1dea176e8586 --- /dev/null +++ b/backport-CVE-2025-62611.patch @@ -0,0 +1,141 @@ +From aa9849480d7b3bcc6182a5bfe43045cd87b2b131 Mon Sep 17 00:00:00 2001 +From: KonstantAnxiety +Date: Tue, 9 Sep 2025 17:07:11 +0300 +Subject: [PATCH 1/3] check local_infile option when receiving a LOAD_LOCAL + packet + +--- + CHANGES.txt | 5 +++++ + aiomysql/connection.py | 7 ++++++- + docs/connection.rst | 11 ++++++++--- + tests/test_load_local.py | 32 ++++++++++++++++++++++++++++++++ + 4 files changed, 51 insertions(+), 4 deletions(-) + +diff --git a/CHANGES.txt b/CHANGES.txt +index e7fe223..87ef348 100644 +--- a/CHANGES.txt ++++ b/CHANGES.txt +@@ -1,6 +1,11 @@ + Changes + ------- + ++* | Properly check whether loading of local files is enabled #1044 ++ | Loading local data now requires using the `local_infile` parameter, passing just the client flag through `client_flag` is no longer supported. ++ | Fixes `GHSA-r397-ff8c-wv2g `_ ++ | Thanks to @KonstantAnxiety for reporting this. ++ + 0.2.0 (2023-06-11) + ^^^^^^^^^^^^^^^^^^ + +diff --git a/aiomysql/connection.py b/aiomysql/connection.py +index 3520dfc..43ed7b4 100644 +--- a/aiomysql/connection.py ++++ b/aiomysql/connection.py +@@ -246,7 +246,8 @@ class Connection: + + self._encoding = charset_by_name(self._charset).encoding + +- if local_infile: ++ self._local_infile = bool(local_infile) ++ if self._local_infile: + client_flag |= CLIENT.LOCAL_FILES + + client_flag |= CLIENT.CAPABILITIES +@@ -1204,6 +1205,10 @@ class MySQLResult: + self.has_next = ok_packet.has_next + + async def _read_load_local_packet(self, first_packet): ++ if not self.connection._local_infile: ++ raise RuntimeError( ++ "**WARN**: Received LOAD_LOCAL packet but local_infile option is false." ++ ) + load_packet = LoadLocalPacketWrapper(first_packet) + sender = LoadLocalFile(load_packet.filename, self.connection) + try: +diff --git a/docs/connection.rst b/docs/connection.rst +index 49936e0..9c48762 100644 +--- a/docs/connection.rst ++++ b/docs/connection.rst +@@ -46,8 +46,8 @@ Example:: + client_flag=0, cursorclass=Cursor, init_command=None, + connect_timeout=None, read_default_group=None, + autocommit=False, echo=False +- ssl=None, auth_plugin='', program_name='', +- server_public_key=None, loop=None) ++ local_infile=False, loop=None, ssl=None, auth_plugin='', ++ program_name='', server_public_key=None) + + A :ref:`coroutine ` that connects to MySQL. + +@@ -71,7 +71,8 @@ Example:: + See `pymysql.converters`. + :param use_unicode: whether or not to default to unicode strings. + :param client_flag: custom flags to send to MySQL. Find +- potential values in `pymysql.constants.CLIENT`. ++ potential values in `pymysql.constants.CLIENT`. Refer to the ++ `local_infile` parameter for enabling loading of local data. + :param cursorclass: custom cursor class to use. + :param str init_command: initial SQL statement to run when connection is + established. +@@ -81,6 +82,10 @@ Example:: + file. + :param autocommit: Autocommit mode. None means use server default. + (default: ``False``) ++ :param local_infile: Boolean to enable the use of `LOAD DATA LOCAL` ++ command. This also enables the corresponding `client_flag`. aiomysql ++ does not perform any validation of files requested by the server. Do ++ not use this with untrusted servers. (default: ``False``) + :param ssl: Optional SSL Context to force SSL + :param auth_plugin: String to manually specify the authentication + plugin to use, i.e you will want to use mysql_clear_password +diff --git a/tests/test_load_local.py b/tests/test_load_local.py +index 637515b..a0a26d5 100644 +--- a/tests/test_load_local.py ++++ b/tests/test_load_local.py +@@ -2,7 +2,9 @@ import builtins + import os + from unittest.mock import patch, MagicMock + ++import aiomysql + import pytest ++from pymysql.constants import CLIENT + from pymysql.err import OperationalError + + +@@ -81,3 +83,33 @@ async def test_load_warnings(cursor, table_local_file): + with warnings.catch_warnings(record=True) as w: + await cursor.execute(sql) + assert "Incorrect integer value" in str(w[-1].message) ++ ++ ++@pytest.mark.run_loop ++async def test_load_local_disabled(mysql_params, table_local_file): ++ # By setting the client flag, the server will be informed that we support ++ # loading local files. This validates that the client side check catches ++ # the server attempting to read files from us without having this ++ # explicitly enabled on the connection. The local_infile parameter sets ++ # the client flag, but not the other way round. ++ params = mysql_params.copy() ++ params["local_infile"] = False ++ if "client_flag" in params: ++ params["client_flag"] |= CLIENT.LOCAL_FILES ++ else: ++ params["client_flag"] = CLIENT.LOCAL_FILES ++ ++ async with aiomysql.connect(**params) as conn: ++ async with conn.cursor() as cursor: ++ # Test load local infile with a valid file ++ filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), ++ 'fixtures', ++ 'load_local_data.txt') ++ with pytest.raises( ++ RuntimeError, ++ match="Received LOAD_LOCAL packet but local_infile option is false", ++ ): ++ await cursor.execute( ++ ("LOAD DATA LOCAL INFILE '{0}' INTO TABLE " + ++ "test_load_local FIELDS TERMINATED BY ','").format(filename) ++ ) +-- +2.33.0 + diff --git a/python-aiomysql.spec b/python-aiomysql.spec index 0a70749319e372316666d65b0b52e62c35875a8b..78a21d49920e7ce785979dcfc8440ea7b5a05a14 100644 --- a/python-aiomysql.spec +++ b/python-aiomysql.spec @@ -1,11 +1,12 @@ %global _empty_manifest_terminate_build 0 Name: python-aiomysql Version: 0.2.0 -Release: 1 +Release: 2 Summary: MySQL driver for asyncio. License: MIT URL: https://github.com/aio-libs/aiomysql Source0: https://files.pythonhosted.org/packages/67/76/2c5b55e4406a1957ffdfd933a94c2517455291c97d2b81cec6813754791a/aiomysql-0.2.0.tar.gz +Patch6000: backport-CVE-2025-62611.patch BuildArch: noarch @@ -62,6 +63,9 @@ if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi %{_docdir}/* %changelog +* Thu Oct 23 2025 yujingbo - 0.2.0-2 +- fix CVE-2025-62611 + * Wed Jun 21 2023 jiangxinyu - 0.2.0-1 - Update package to 0.2.0