Skip to content

Commit 6fafe05

Browse files
committed
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 efdc08a commit 6fafe05

2 files changed

Lines changed: 39 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+
escaped_keyspace = keyspace.replace('"', '""')
1662+
query = QueryMessage(query='USE "%s"' % (escaped_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+
escaped_keyspace = keyspace.replace('"', '""')
1717+
query = QueryMessage(query='USE "%s"' % (escaped_keyspace,),
17161718
consistency_level=ConsistencyLevel.ONE)
17171719

17181720
def process_result(result):

tests/unit/test_connection.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
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)
2929

3030
from tests.util import wait_until, assertRegex
3131
import pytest
@@ -256,6 +256,40 @@ def test_set_keyspace_blocking(self):
256256
c.set_keyspace_blocking('ks')
257257
assert c.keyspace == 'ks'
258258

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

0 commit comments

Comments
 (0)