CVE-2023-31136 (Swift, published 2023-05-09T14:15Z)
Description: value: PostgresNIO is a Swift client for PostgreSQL. Any user of PostgresNIO prior to version 1.14.2 connecting to servers with TLS enabled is vulnerable to a man-in-the-middle attacker injecting false responses to the client's first few queries, despite the use of TLS certificate verification and encryption. The vulnerability is addressed in PostgresNIO versions starting from 1.14.2. There are no known workarounds for unpatched users.
Severity: nan (CVSS v3 base score: 5.9)
Weakness: CWE-522 \u2014 Insufficiently Protected Credentials
The product transmits or stores authentication credentials, but it uses an insecure method that is susceptible to unauthorized interception and/or retrieval.
Repository: https://github.com/vapor/postgres-nio
Files changed:
Package.swift
Sources/PostgresNIO/New/Connection State Machine/ConnectionStateMachine.swift	
Sources/PostgresNIO/New/PSQLError.swift
Sources/PostgresNIO/New/PostgresChannelHandler.swift
Sources/PostgresNIO/Postgres+PSQLCompat.swift
Tests/PostgresNIOTests/New/Connection State Machine/ConnectionStateMachineTests.swift	
Tests/PostgresNIOTests/New/PostgresChannelHandlerTests.swift
Commit message: Merge pull request from GHSA-9cfh-vx93-84vv

* Ensure empty incoming buffer when TLS negotiation starts

* cleanup

* Use real nio version

Vulnerable code:
        .package(url: "https://github.com/apple/swift-nio.git", from: "2.51.1"),
    mutating func sslSupportedReceived() -> ConnectionAction {
        case .sslUnsupported:
            return true
        case .failedToAddSSLHandler:
        case .messageDecodingFailure:
            return true
        case .unexpectedBackendMessage:
            return true
        case .unsupportedAuthMechanism:
            return true
        case .authMechanismRequiresPassword:
            return true
        case .saslError:
            return true
        case .tooManyParameters:
            return true
        case .invalidCommandTag:
            return true
        case .connectionError:
            return true
        case .uncleanShutdown:
            return true
                    action = self.state.sslSupportedReceived()
        XCTAssertEqual(state.sslSupportedReceived(), .establishSSLConnection)
    
        XCTAssertEqual(state.sslSupportedReceived(), .establishSSLConnection)
    

Fixed code:
        .package(url: "https://github.com/apple/swift-nio.git", from: "2.52.0"),
    mutating func sslSupportedReceived(unprocessedBytes: Int) -> ConnectionAction {
            if unprocessedBytes > 0 {
                return self.closeConnectionAndCleanup(.receivedUnencryptedDataAfterSSLRequest)
            }
        case .failedToAddSSLHandler,
             .receivedUnencryptedDataAfterSSLRequest,
             .sslUnsupported,
             .messageDecodingFailure,
             .unexpectedBackendMessage,
             .unsupportedAuthMechanism,
             .authMechanismRequiresPassword,
             .saslError,
             .tooManyParameters,
             .invalidCommandTag,
             .connectionError,
             .uncleanShutdown:
            case receivedUnencryptedDataAfterSSLRequest
        public static let receivedUnencryptedDataAfterSSLRequest = Self(.receivedUnencryptedDataAfterSSLRequest)
            case .receivedUnencryptedDataAfterSSLRequest:
                return "receivedUnencryptedDataAfterSSLRequest"
    static var receivedUnencryptedDataAfterSSLRequest: PSQLError { PSQLError(code: .receivedUnencryptedDataAfterSSLRequest) }

                    action = self.state.sslSupportedReceived(unprocessedBytes: self.decoder.unprocessedBytes)
        case .receivedUnencryptedDataAfterSSLRequest:
            return PostgresError.protocol("Received unencrypted data after SSL request")
        XCTAssertEqual(state.sslSupportedReceived(unprocessedBytes: 0), .establishSSLConnection)

    func testSSLStartupFailureTooManyBytesRemaining() {
        var state = ConnectionStateMachine(requireBackendKeyData: true)
        XCTAssertEqual(state.connected(tls: .require), .sendSSLRequest)
        let failError = PSQLError.receivedUnencryptedDataAfterSSLRequest
        XCTAssertEqual(state.sslSupportedReceived(unprocessedBytes: 1), .closeConnectionAndCleanup(.init(action: .close, tasks: [], error: failError, closePromise: nil)))
    }

        XCTAssertEqual(state.sslSupportedReceived(unprocessedBytes: 0), .establishSSLConnection)

    func testEstablishSSLCallbackIsNotCalledIfSSLIsSupportedButAnotherMEssageIsSentAsWell() {
        var config = self.testConnectionConfiguration()
        XCTAssertNoThrow(config.tls = .require(try NIOSSLContext(configuration: .makeClientConfiguration())))
        var addSSLCallbackIsHit = false
        let handler = PostgresChannelHandler(configuration: config) { channel in
            addSSLCallbackIsHit = true
        }
        let eventHandler = TestEventHandler()
        let embedded = EmbeddedChannel(handlers: [
            ReverseByteToMessageHandler(PSQLFrontendMessageDecoder()),
            handler,
            eventHandler
        ])

        var maybeMessage: PostgresFrontendMessage?
        XCTAssertNoThrow(embedded.connect(to: try .init(ipAddress: "0.0.0.0", port: 5432), promise: nil))
        XCTAssertNoThrow(maybeMessage = try embedded.readOutbound(as: PostgresFrontendMessage.self))
        guard case .sslRequest(let request) = maybeMessage else {
            return XCTFail("Unexpected message")
        }

        XCTAssertEqual(request.code, 80877103)

        var responseBuffer = ByteBuffer()
        responseBuffer.writeInteger(UInt8(ascii: "S"))
        responseBuffer.writeInteger(UInt8(ascii: "1"))
        XCTAssertNoThrow(try embedded.writeInbound(responseBuffer))

        XCTAssertFalse(addSSLCallbackIsHit)

        // the event handler should have seen an error
        XCTAssertEqual(eventHandler.errors.count, 1)

        // the connections should be closed
        XCTAssertFalse(embedded.isActive)
    }