Skip to content

startTls() ignores the result of stream_socket_enable_crypto(), so LOGIN can go out in plain text #192

Closed

Description

@SingHar

Environment

  • PHP version: 8.4.26 (OpenSSL 3.0.13)
  • ImapEngine version: v1.25.6 (master has the same startTls() on 24/10/2026)
  • IMAP server: a local test server that answers OK to STARTTLS and then does not speak TLS (script below). Any server or proxy in the middle can do the same.

IMAP logs

With 'debug' => '/tmp/imap.log':

2026-10-24 13:26:48: << * OK ready
2026-10-24 13:26:48: >> TAG1 STARTTLS
2026-10-24 13:26:48: << TAG1 OK Begin TLS
2026-10-24 13:26:48: >> TAG2 LOGIN "u" "p"
2026-10-24 13:26:48: << ls at all
2026-10-24 13:26:51: >> TAG3 LOGOUT

PHP also prints stream_socket_enable_crypto(): SSL operation failed with code 1 ... wrong version number, and the client keeps going. The server receives TAG2 LOGIN "u" "p" in plain text.

What happens

ImapConnection::startTls() sends STARTTLS, checks the tagged OK, then calls $this->stream->setSocketSetCrypto(true, STREAM_CRYPTO_METHOD_TLS_CLIENT). The return value is thrown away. When the handshake fails, stream_socket_enable_crypto() returns false, the socket stays plain TCP, and Mailbox::connect() sends LOGIN with the password.

Reproduce

Server:

$s = stream_socket_server('tcp://127.0.0.1:19143');
$c = stream_socket_accept($s, 10);
fwrite($c, "* OK ready\r\n");
$tag = strtok(fgets($c), ' ');
fwrite($c, "$tag OK Begin TLS\r\nnot tls at all\r\n");
stream_set_timeout($c, 3);
while (($l = fgets($c)) !== false) echo $l;

Client:

$mailbox = new Mailbox([
    'host' => '127.0.0.1', 'port' => 19143,
    'username' => 'u', 'password' => 'p',
    'encryption' => 'starttls', 'validate_cert' => false,
    'debug' => '/tmp/imap.log',
]);
$mailbox->connect();

Suggested fix

if ($this->stream->setSocketSetCrypto(true, STREAM_CRYPTO_METHOD_TLS_CLIENT) !== true) {
    $this->stream->close();

    throw new ImapConnectionFailedException('The TLS upgrade after STARTTLS failed.');
}

We run this in a subclass of ImapConnection for now. With it, the server above sees no LOGIN line. Happy to send it as a PR if you want one.

Activity

  1. stevebauman commented on Oct 24, 2026

    @stevebauman
    Member

    Patched, thanks @SingHar! Released in v1.25.7.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions