Skip to content

Commit e10bf39

Browse files
mykauldkropachev
authored andcommitted
Fix CQL injection in Connection.set_keyspace_blocking and set_keyspace_async
Escape double quotes in keyspace names when constructing USE statements to prevent CQL injection. A keyspace name containing '"' would produce malformed or injectable CQL (e.g., USE "foo"bar"). This is the Python equivalent of the vulnerability fixed in the Go driver (gocql#783). The fix escapes '"' as '""' per CQL quoted-identifier rules, matching the existing escape_name() function in cassandra/metadata.py.
1 parent caa98b6 commit e10bf39

2 files changed

Lines changed: 40 additions & 3 deletions

File tree

cassandra/connection.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,7 +1658,8 @@ def set_keyspace_blocking(self, keyspace):
16581658
if not keyspace or keyspace == self.keyspace:
16591659
return
16601660

1661-
query = QueryMessage(query='USE "%s"' % (keyspace,),
1661+
from cassandra.metadata import escape_name
1662+
query = QueryMessage(query='USE %s' % (escape_name(keyspace),),
16621663
consistency_level=ConsistencyLevel.ONE)
16631664
try:
16641665
result = self.wait_for_response(query)
@@ -1712,7 +1713,8 @@ def set_keyspace_async(self, keyspace, callback):
17121713
callback(self, None)
17131714
return
17141715

1715-
query = QueryMessage(query='USE "%s"' % (keyspace,),
1716+
from cassandra.metadata import escape_name
1717+
query = QueryMessage(query='USE %s' % (escape_name(keyspace),),
17161718
consistency_level=ConsistencyLevel.ONE)
17171719

17181720
def process_result(result):

tests/unit/test_connection.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
ConnectionException, ConnectionShutdown, DefaultEndPoint, ShardAwarePortGenerator)
2626
from cassandra.marshal import uint8_pack, uint32_pack, int32_pack
2727
from cassandra.protocol import (write_stringmultimap, write_int, write_string,
28-
SupportedMessage, ProtocolHandler)
28+
SupportedMessage, ProtocolHandler, ResultMessage,
29+
RESULT_KIND_SET_KEYSPACE)
2930

3031
from tests.util import wait_until, assertRegex
3132
import pytest
@@ -256,6 +257,40 @@ def test_set_keyspace_blocking(self):
256257
c.set_keyspace_blocking('ks')
257258
assert c.keyspace == 'ks'
258259

260+
def test_set_keyspace_blocking_escapes_quotes(self):
261+
"""
262+
Test that set_keyspace_blocking properly escapes double quotes in
263+
keyspace names to prevent CQL injection. This is the Python equivalent
264+
of the vulnerability fixed in the Go driver:
265+
https://github.com/scylladb/gocql/pull/783
266+
"""
267+
c = self.make_connection()
268+
c.wait_for_response = Mock(return_value=ResultMessage(kind=RESULT_KIND_SET_KEYSPACE))
269+
270+
c.set_keyspace_blocking('my"ks')
271+
query_msg = c.wait_for_response.call_args[0][0]
272+
assert query_msg.query == 'USE "my""ks"', (
273+
"Double quotes in keyspace name must be escaped as double-double quotes")
274+
275+
def test_set_keyspace_async_escapes_quotes(self):
276+
"""
277+
Test that set_keyspace_async properly escapes double quotes in
278+
keyspace names to prevent CQL injection.
279+
"""
280+
c = self.make_connection()
281+
c.lock = Lock()
282+
c.in_flight = 0
283+
c.max_request_id = 100
284+
c.get_request_id = Mock(return_value=1)
285+
c.send_msg = Mock()
286+
287+
callback = Mock()
288+
c.set_keyspace_async('my"ks', callback)
289+
290+
query_msg = c.send_msg.call_args[0][0]
291+
assert query_msg.query == 'USE "my""ks"', (
292+
"Double quotes in keyspace name must be escaped as double-double quotes")
293+
259294
def test_set_connection_class(self):
260295
cluster = Cluster(connection_class='test')
261296
assert 'test' == cluster.connection_class

0 commit comments

Comments
 (0)