CVE-2024-29887: Insufficient Information (NVD-CWE-noinfo)
value: Serverpod is an app and web server, built for the Flutter and Dart ecosystem. This bug bypassed the validation of TSL certificates on all none web HTTP clients in the `serverpod_client` package. Making them susceptible to a man in the middle attack against encrypted traffic between the client device and the server. An attacker would need to be able to intercept the traffic and highjack the connection to the server for this vulnerability to be used. Upgrading to version `1.2.6` resolves this issue.


CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-03-27T19:15Z
Repository: https://github.com/serverpod/serverpod
Language: Other
Files changed: packages/serverpod_client/lib/src/serverpod_client_io.dart, tests/serverpod_test_server/test_e2e/tsl_client_test.dart
Commit date: 2024-03-22 15:28:28 +0100
Commit message: fix: Remove faulty certificate check. (#2041)


Diff: diff --git a/packages/serverpod_client/lib/src/serverpod_client_io.dart b/packages/serverpod_client/lib/src/serverpod_client_io.dart
index 988326ca..d87107c6 100644
--- a/packages/serverpod_client/lib/src/serverpod_client_io.dart
+++ b/packages/serverpod_client/lib/src/serverpod_client_io.dart
@@ -33,25 +33,10 @@ abstract class ServerpodClient extends ServerpodClientShared {
         'Context must be of type SecurityContext');
 
     // Setup client
     _httpClient = HttpClient(context: securityContext);
     _httpClient.connectionTimeout = connectionTimeout;
-
-    // TODO: Generate working certificates
-    _httpClient.badCertificateCallback =
-        ((X509Certificate cert, String host, int port) {
-//      print('Failed to verify server certificate');
-//      print('pem: ${cert.pem}');
-//      print('subject: ${cert.subject}');
-//      print('issuer: ${cert.issuer}');
-//      print('valid from: ${cert.startValidity}');
-//      print('valid to: ${cert.endValidity}');
-//      print('host: $host');
-//      print('port: $port');
-//      return false;
-      return true;
-    });
   }
 
   Future<void> _initialize() async {
     _initialized = true;
   }
diff --git a/tests/serverpod_test_server/test_e2e/tsl_client_test.dart b/tests/serverpod_test_server/test_e2e/tsl_client_test.dart
new file mode 100644
index 00000000..2ec903cf
--- /dev/null
+++ b/tests/serverpod_test_server/test_e2e/tsl_client_test.dart
@@ -0,0 +1,31 @@
+import 'dart:io';
+
+import 'package:serverpod_service_client/serverpod_service_client.dart';
+import 'package:test/test.dart';
+
+void main() {
+  test(
+      'Given valid certificates when a call to the health endpoint of a service with a valid certificate then the requests completes successfully.',
+      () async {
+    var client = Client('https://api.serverpod.app/');
+
+    expectLater(
+      client.callServerEndpoint<void>('', '', {}),
+      completes,
+    );
+  });
+
+  test(
+      'Given no valid certificates when a call to the health endpoint of a service then the requests is rejected with a handshake exception.',
+      () async {
+    var client = Client(
+      'https://api.serverpod.app/',
+      securityContext: SecurityContext(withTrustedRoots: false),
+    );
+
+    expectLater(
+      client.callServerEndpoint<void>('', '', {}),
+      throwsA(isA<HandshakeException>()),
+    );
+  });
+}

Vulnerable code: 
    // TODO: Generate working certificates
    _httpClient.badCertificateCallback =
        ((X509Certificate cert, String host, int port) {
//      print('Failed to verify server certificate');
//      print('pem: ${cert.pem}');
//      print('subject: ${cert.subject}');
//      print('issuer: ${cert.issuer}');
//      print('valid from: ${cert.startValidity}');
//      print('valid to: ${cert.endValidity}');
//      print('host: $host');
//      print('port: $port');
//      return false;
      return true;
    });
Fixed code: import 'dart:io';

import 'package:serverpod_service_client/serverpod_service_client.dart';
import 'package:test/test.dart';

void main() {
  test(
      'Given valid certificates when a call to the health endpoint of a service with a valid certificate then the requests completes successfully.',
      () async {
    var client = Client('https://api.serverpod.app/');

    expectLater(
      client.callServerEndpoint<void>('', '', {}),
      completes,
    );
  });

  test(
      'Given no valid certificates when a call to the health endpoint of a service then the requests is rejected with a handshake exception.',
      () async {
    var client = Client(
      'https://api.serverpod.app/',
      securityContext: SecurityContext(withTrustedRoots: false),
    );

    expectLater(
      client.callServerEndpoint<void>('', '', {}),
      throwsA(isA<HandshakeException>()),
    );
  });
}