Fixed CRLF command smuggling and node misrouting in AbstractAggregateConnection::write() and CommandInterface::deserializeCommand() (#1728)

* Fixed CRLF command injection / smuggling in AbstractAggregateConnection::write()

* Revert "Fixed CRLF command injection / smuggling in AbstractAggregateConnection::write()"

This reverts commit a4720b03ee.

* Fixed CRLF command smuggling and node misrouting in AbstractAggregateConnection::write() and CommandInterface::deserializeCommand()

* Revert change
This commit is contained in:
Vladyslav Vildanov
2026-09-16 10:01:26 +03:00
committed by GitHub
parent 37490865cc
commit 3edc442e55
10 changed files with 421 additions and 37 deletions
@@ -1496,6 +1496,69 @@ repl_backlog_histlen:12978
$replication->write($command1->serializeCommand() . $command2->serializeCommand() . $command3->serializeCommand());
}
/**
* Regression guard for GHSA-w6f5-v2h6-g786 (CWE-93): a CRLF embedded in a
* bulk string's own value must not be mistaken for a command boundary
* (splitting one command into a smuggled extra command).
*
* @group disconnected
*/
public function testWriteHandlesCRLFEmbeddedInBulkStringValue(): void
{
$command = new Command\Redis\SET();
$command->setArguments(['victim-key', "PAD\r\n*1\r\n\$7\r\nFLUSHDB"]);
$master = $this->getMockConnection('tcp://127.0.0.1:6379?role=master');
$slave1 = $this->getMockConnection('tcp://127.0.0.1:6380?role=slave');
$slave1
->expects($this->never())
->method('write');
$master
->expects($this->once())
->method('write')
->with($command->serializeCommand());
$replication = new MasterSlaveReplication();
$replication->add($master);
$replication->add($slave1);
$replication->write($command->serializeCommand());
}
/**
* Regression guard for GHSA-w6f5-v2h6-g786 (CWE-93): a CRLF embedded in a
* bulk string KEY must not corrupt the argument list used to pick the
* target connection, which would silently route the command to the
* wrong node.
*
* @group disconnected
*/
public function testWriteHandlesCRLFEmbeddedInBulkStringKey(): void
{
$command = new Command\Redis\SET();
$command->setArguments(["victim\r\n*1\r\n\$4\r\nEVIL", 'somevalue']);
$master = $this->getMockConnection('tcp://127.0.0.1:6379?role=master');
$slave1 = $this->getMockConnection('tcp://127.0.0.1:6380?role=slave');
$slave1
->expects($this->never())
->method('write');
$master
->expects($this->once())
->method('write')
->with($command->serializeCommand());
$replication = new MasterSlaveReplication();
$replication->add($master);
$replication->add($slave1);
$replication->write($command->serializeCommand());
}
/**
* @medium
* @group disconnected