java-topology/docs/tickets/jetty-0001-httpfields-quotedcsv-getvalues-list-contains.md
russell@unturf.com 9934133dcf whitepaper: 312 sites / 151 ecosystems — wave2+3 defect tables and PDF rebuild
Add 88 new defect entries to HIGH and MEDIUM tables:
  HIGH: mysql-0001/0002, mariadb-0001, redis-0001/0002, valkey-0001/0002, openvpn-0001,
        vlc-0001, prometheus-0001, otel-collector-0001, cockroachdb-0001..0004,
        tidb-0001..0008, kubernetes-0001/0002, go-0001, kotlin-0002, scala-0001,
        allegro5-0001, sdl2-0001, grafana-0001, clickhouse-0001, duckdb-0001,
        mongodb-0001, envoy-0001, istio-0001, cilium-0001, linkerd2-0001,
        linux-0001/0002/0003, tor-0002/0003, curl-0001, julia-0001, lua-0001,
        perl5-0001, nats-0001, spring-0003/0004, tomcat-0001, onos-0002, odl-0002

  MEDIUM: helm-0001, mariadb-0002, openssl-0001/0002, memcached-0001,
          cassandra-0001..0004, flink-0001, storm-0001/0002, zookeeper-0001..0003,
          pip-0001, gradle-0001, nginx-0001, haproxy-0001, caddy-0001, varnish-0001,
          ffmpeg-0001, gstreamer-0001, raylib-0001, love2d-0001, php-0001/0002,
          r-source-0001, cpython-0002, ruby-0001, rabbitmq-0003/0004, activemq-0001,
          ovs-0001, onos-0003, odl-0002, jetty-0001

PDF: 976K
2026-03-27 15:23:43 -04:00

2.5 KiB
Raw Permalink Blame History

jetty-0001: HttpFields.formatCsvExcludingExisting — QuotedCSV.getValues() List.contains() O(n²)

Target: Eclipse Jetty File: jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java CWE: CWE-407 — Inefficient Algorithmic Complexity Severity: MEDIUM Status: PATCHED

Description

HttpFields.Mutable.addCSV() (both header and name variants) calls the private helper formatCsvExcludingExisting(QuotedCSV existing, String... values). Inside that helper the loop iterates over all incoming values and calls existing.getValues().contains(unquoted) on each iteration.

QuotedCSV.getValues() returns the internal _values field, which is ArrayList<String> (line 107). Each .contains() call is therefore O(m) where m is the number of existing CSV values. With V values to add and M existing values, the total is O(V × M).

When addCSV() is called per-request (e.g. to add Vary or Cache-Control token lists), V and M grow with the number of directives/values, making this O(n²) under adversarial or large header inputs.

// HttpFields.java  line 1576-1591
private static String formatCsvExcludingExisting(QuotedCSV existing, String... values) {
    boolean add = true;
    if (existing != null && !existing.isEmpty()) {
        add = false;
        for (int i = values.length; i-- > 0; ) {
            String unquoted = QuotedCSV.unquote(values[i]);
            if (existing.getValues().contains(unquoted))   // O(m) scan per value → O(V×M)
                values[i] = null;
            else
                add = true;
        }
    }
    ...
}

// QuotedCSV.java  line 107
private final List<String> _values = new ArrayList<>();   // O(n) contains()

Fix

Convert the existing values to a HashSet<String> once before the loop, then call existingSet.contains(unquoted) at O(1) per lookup.

private static String formatCsvExcludingExisting(QuotedCSV existing, String... values) {
    boolean add = true;
    if (existing != null && !existing.isEmpty()) {
        add = false;
        Set<String> existingSet = new HashSet<>(existing.getValues()); // O(m) once
        for (int i = values.length; i-- > 0; ) {
            String unquoted = QuotedCSV.unquote(values[i]);
            if (existingSet.contains(unquoted))                        // O(1) per lookup
                values[i] = null;
            else
                add = true;
        }
    }
    ...
}

Patch

defects/jetty/patch/jetty-0001.patch

Unit Test

defects/jetty/unit/JettyHttpFieldsCsvTest.java