CVE-2024-25715 (C, published 2024-02-11T03:15Z)
Description: value: Glewlwyd SSO server 2.x through 2.7.6 allows open redirection via redirect_uri.
Severity: nan (CVSS v3 base score: 6.1)
Weakness: CWE-601 \u2014 URL Redirection to Untrusted Site ('Open Redirect')
A web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a Redirect. This simplifies phishing attacks.
Repository: https://github.com/babelouest/glewlwyd
Files changed:
src/plugin/protocol_oauth2.c
Commit message: Fix PKCE downgrade and open redirection issues

Thanks to Pieter Philippaerts


Vulnerable code:
  int uri_found, authorization_type_enabled;
  if (check_result_value(j_client, G_OK)) {
        uri_found = 0;
      } else {
        uri_found = 1;
static int validate_code_challenge(json_t * j_result_code, const char * code_verifier) {
  if (!json_string_null_or_empty(json_object_get(j_result_code, "code_challenge"))) {
            y_log_message(Y_LOG_LEVEL_ERROR, "validate_code_challenge - Error o_base64url_encode");
          y_log_message(Y_LOG_LEVEL_ERROR, "validate_code_challenge - Error gnutls_fingerprint");
          ret = G_ERROR_PARAM;
      ret = G_ERROR_PARAM;
  } else {
    ret = G_OK;
          if ((res = validate_code_challenge(json_array_get(j_result, 0), code_verifier)) == G_OK) {
    if (u_map_has_key(request->map_url, "g_continue")) {
      if (!o_strnullempty(u_map_get(request->map_url, "scope"))) {
        // Scope is not allowed for this user
        y_log_message(Y_LOG_LEVEL_DEBUG, "check_auth_type_auth_code_grant - oauth2 - scope list is missing or empty, origin: %s", ip_source);
        response->status = 302;
        redirect_url = msprintf("%s%serror=invalid_scope%s", u_map_get(request->map_url, "redirect_uri"), (o_strchr(u_map_get(request->map_url, "redirect_uri"), '?')!=NULL?"&":"?"), state_param);
      // Redirect to login page
      redirect_url = get_login_url(config, request, "auth", u_map_get(request->map_url, "client_id"), u_map_get(request->map_url, "scope"), NULL);
      ulfius_add_header_to_response(response, "Location", redirect_url);
      o_free(redirect_url);
      response->status = 302;
    response->status = 302;
    redirect_url = msprintf("%s%serror=unauthorized_client%s%s", u_map_get(request->map_url, "redirect_uri"), (o_strchr(u_map_get(request->map_url, "redirect_uri"), '?')!=NULL?"&":"?"), (u_map_get(request->map_url, "state")!=NULL?"&state=":""), (u_map_get(request->map_url, "state")!=NULL?u_map_get(request->map_url, "state"):""));
    ulfius_add_header_to_response(response, "Location", redirect_url);
    o_free(redirect_url);
    if (u_map_has_key(request->map_url, "g_continue")) {
      if (!o_strnullempty(u_map_get(request->map_url, "scope"))) {
        // Empty scope is not allowed
        response->status = 302;
        redirect_url = msprintf("%s%serror=invalid_scope%s", u_map_get(request->map_url, "redirect_uri"), (o_strchr(u_map_get(request->map_url, "redirect_uri"), '?')!=NULL?"&":"?"), state_param);
      // Redirect to login page
      redirect_url = get_login_url(config, request, "auth", u_map_get(request->map_url, "client_id"), u_map_get(request->map_url, "scope"), NULL);
      ulfius_add_header_to_response(response, "Location", redirect_url);
      o_free(redirect_url);
      response->status = 302;
    response->status = 302;
    redirect_url = msprintf("%s%serror=unauthorized_client%s%s", u_map_get(request->map_url, "redirect_uri"), (o_strchr(u_map_get(request->map_url, "redirect_uri"), '?')!=NULL?"&":"?"), (u_map_get(request->map_url, "state")!=NULL?"&state=":""), (u_map_get(request->map_url, "state")!=NULL?u_map_get(request->map_url, "state"):""));
    ulfius_add_header_to_response(response, "Location", redirect_url);
    o_free(redirect_url);
  char * redirect_url, * state_encoded = NULL, * state_param = NULL;
      if (u_map_get(request->map_url, "redirect_uri") != NULL) {
        response->status = 302;
        redirect_url = msprintf("%s#error=unsupported_response_type%s", u_map_get(request->map_url, "redirect_uri"), state_param);
        ulfius_add_header_to_response(response, "Location", redirect_url);
        o_free(redirect_url);
      } else {
        response->status = 403;
      }
    } else {
      if (u_map_get(request->map_url, "redirect_uri") != NULL) {
        response->status = 302;
        redirect_url = msprintf("%s#error=unsupported_response_type%s", u_map_get(request->map_url, "redirect_uri"), state_param);
        ulfius_add_header_to_response(response, "Location", redirect_url);
        o_free(redirect_url);
      } else {
        response->status = 403;
      }
    }
  } else {
    if (u_map_get(request->map_url, "redirect_uri") != NULL) {
      response->status = 302;
      redirect_url = msprintf("%s#error=unsupported_response_type%s", u_map_get(request->map_url, "redirect_uri"), state_param);
      ulfius_add_header_to_response(response, "Location", redirect_url);
      o_free(redirect_url);

Fixed code:
  int uri_found = 0, authorization_type_enabled;
  if (check_result_value(j_client, G_OK) && json_object_get(json_object_get(j_client, "client"), "enabled") == json_true()) {
static int validate_code_challenge(struct _oauth2_config * config, json_t * j_result_code, const char * code_verifier) {
  if (json_object_get(config->j_params, "pkce-allowed") != json_true()) {
    if (o_strnullempty(code_verifier)) {
      ret = G_OK;
    } else {
      y_log_message(Y_LOG_LEVEL_DEBUG, "oidc validate_code_challenge - code_verifier unauthorized");
      ret = G_ERROR_UNAUTHORIZED;
    }
  } else if ((!o_strnullempty(code_verifier) && json_string_null_or_empty(json_object_get(j_result_code, "code_challenge"))) || (o_strnullempty(code_verifier) && !json_string_null_or_empty(json_object_get(j_result_code, "code_challenge")))) {
    y_log_message(Y_LOG_LEVEL_DEBUG, "oidc validate_code_challenge - Invalid code_challenge or code_verifier");
    ret = G_ERROR_UNAUTHORIZED;
  } else {
              y_log_message(Y_LOG_LEVEL_DEBUG, "oidc validate_code_challenge - Invalid code_challenge value");
            y_log_message(Y_LOG_LEVEL_ERROR, "oidc validate_code_challenge - Error o_base64url_encode");
          y_log_message(Y_LOG_LEVEL_ERROR, "oidc validate_code_challenge - Error gnutls_fingerprint");
          y_log_message(Y_LOG_LEVEL_DEBUG, "oidc validate_code_challenge - Invalid code_challenge value");
          ret = G_ERROR_UNAUTHORIZED;
      y_log_message(Y_LOG_LEVEL_DEBUG, "oidc validate_code_challenge - Invalid code_challenge character set");
      ret = G_ERROR_UNAUTHORIZED;
          if ((res = validate_code_challenge(config, json_array_get(j_result, 0), code_verifier)) == G_OK) {
    if (!o_strnullempty(u_map_get(request->map_url, "scope"))) {
      if (u_map_has_key(request->map_url, "g_continue")) {
        // Redirect to login page
        redirect_url = get_login_url(config, request, "auth", u_map_get(request->map_url, "client_id"), u_map_get(request->map_url, "scope"), NULL);
        response->status = 302;
      // Scope is not allowed for this user
      y_log_message(Y_LOG_LEVEL_DEBUG, "check_auth_type_auth_code_grant - oauth2 - scope list is missing or empty, origin: %s", ip_source);
      response->status = 403;
    response->status = 403;
    if (!o_strnullempty(u_map_get(request->map_url, "scope"))) {
      if (u_map_has_key(request->map_url, "g_continue")) {
        // Redirect to login page
        redirect_url = get_login_url(config, request, "auth", u_map_get(request->map_url, "client_id"), u_map_get(request->map_url, "scope"), NULL);
        response->status = 302;
      // Empty scope is not allowed
      response->status = 403;
    response->status = 403;
  char * state_encoded = NULL, * state_param = NULL;

      response->status = 403;
  } else {
    response->status = 403;