CVE-2024-32888 (Java, published 2024-05-15T03:15Z)
Description: value: The Amazon JDBC Driver for Redshift is a Type 4 JDBC driver that provides database connectivity through the standard JDBC application program interfaces (APIs) available in the Java Platform, Enterprise Editions. Prior to version 2.1.0.28, SQL injection is possible when using the non-default connection property `preferQueryMode=simple` in combination with application code which has a vulnerable SQL that negates a parameter value. There is no vulnerability in the driver when using the default, extended query mode. Note that `preferQueryMode` is not a supported parameter in Redshift JDBC driver, and is inherited code from Postgres JDBC driver. Users who do not override default settings to utilize this unsupported query mode are not affected. This issue is patched in driver version 2.1.0.28. As a workaround, do not use the connection property `preferQueryMode=simple`. (NOTE: Those who do not explicitly specify a query mode use the default of extended query mode and are not affected by this issue.)
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/aws/amazon-redshift-jdbc-driver
Files changed:
src/main/java/com/amazon/redshift/core/v3/SimpleParameterList.java
Commit message: Security improvements.


Vulnerable code:
    } else if ((flags[index] & BINARY) == BINARY) {

          return Short.toString(s);
          return Integer.toString(i);
          return Long.toString(l);
          return Float.toString(f);
          return Double.toString(d);
          String uuid =
          return "'" + uuid + "'::uuid";
          return "'" + pgPoint.toString() + "'::point";
          return "'" + pgBox.toString() + "'::box";
      return "?";
      String param = paramValues[index].toString();

      // add room for quotes + potential escaping.
      StringBuilder p = new StringBuilder(3 + (param.length() + 10) / 10 * 11);

      // No E'..' here since escapeLiteral escapes all things and it does not use \123 kind of
      // escape codes
      p.append('\'');
      try {
        p = Utils.escapeLiteral(p, param, standardConformingStrings);
      } catch (SQLException sqle) {
        // This should only happen if we have an embedded null
        // and there's not much we can do if we do hit one.
        //
        // The goal of toString isn't to be sent to the server,
        // so we aren't 100% accurate (see StreamWrapper), put
        // the unescaped version of the data.
        //
        p.append(param);
      }
      p.append('\'');
        p.append("::timestamp");
        p.append("::timestamp with time zone");
        p.append("::time");
        p.append("::time with time zone");
        p.append("::date");
        p.append("::interval");
        p.append("::interval year to month");
        p.append("::interval day to second");
        p.append("::numeric");
      return p.toString();

Fixed code:
  private static String quoteAndCast(String text, String type, boolean standardConformingStrings)
  {
    StringBuilder sb = new StringBuilder((text.length() + 10) / 10 * 11); // Add 10% for escaping.
    sb.append("('");
    try {
      Utils.escapeLiteral(sb, text, standardConformingStrings);
    } catch (SQLException e) {
      // This should only happen if we have an embedded null
      // and there's not much we can do if we do hit one.
      //
      // To force a server side failure, we deliberately include
      // a zero byte character in the literal to force the server
      // to reject the command.
      sb.append('\u0000');
    }
    sb.append("'");
    if (type != null) {
      sb.append("::");
      sb.append(type);
    }
    sb.append(")");
    return sb.toString();
  }

    }
    String textValue;
    String type;
    if ((flags[index] & BINARY) == BINARY) {
          textValue = Short.toString(s);
          type = "int2";
          break;
          textValue = Integer.toString(i);
          type = "int4";
          break;
          textValue = Long.toString(l);
          type = "int8";
          break;
          textValue = Float.toString(f);
          type = "real";
          break;
          textValue = Double.toString(d);
          type = "double precision";
          break;
          textValue =
          type = "uuid";
          break;
          textValue = pgPoint.toString();
          type = "point";
          break;
          textValue = pgBox.toString();
          type = "box";
          break;

        default:
          return "?";
      textValue = paramValues[index].toString();

        type = "timestamp";
        type = "timestamp with time zone";
        type = "time";
        type = "time with time zone";
        type = "date";
        type = "interval";
        type = "interval year to month";
        type = "interval day to second";
        type = "numeric";
      }
      else {
        type = null;
    return quoteAndCast(textValue, type, standardConformingStrings);