)]}'
{
  "commit": "72a4e93f8890f11b7973cf21b348ae509a463ed3",
  "tree": "3e18b5d5f1a1bdc88da55694be677147ebde8db8",
  "parents": [
    "5696ae9a5543da7149036dda45af84310c3ce822"
  ],
  "author": {
    "name": "Luca Milanesio",
    "email": "luca.milanesio@gmail.com",
    "time": "Thu Jun 11 14:45:32 2026 +0100"
  },
  "committer": {
    "name": "Luca Milanesio",
    "email": "luca.milanesio@gmail.com",
    "time": "Mon Jun 15 10:43:10 2026 +0100"
  },
  "message": "Introduce auth.httpTrustedProxyNetworks for securing HTTP auth\n\nWhen using auth\u003dHTTP or auth\u003dHTTP_LDAP, Gerrit relies on receiving the\nincoming username from an HTTP header. When misusing this configuration\nwith a remote proxy and having Gerrit listening to an external interface\nover plain HTTP without firewalls, the security of the incoming username\nis subject to HTTP header spoofing.\n\nHighlight the risk in the documentation and also add a mitigation of the\nproblem with a new auth.httpTrustedProxyNetworks that would restrict the\nfetching of the username from HTTP to a subset of CIDRs.\n\nThe solution is similar to the mitigation adopted in other projects with\na similar vulnerability.\n\nThe parsing of the auth.httpTrustedProxyNetworks is expensive because it\ninvolves the creation of a SubnetUtils object and the string-based\nparsing of CIDRs. As a mitigation of the computational costs, parse and\nstore the subnets in the RemoteUserUtil during the singleton\ninstantiation, so that incoming HTTP calls can reuse the SubnetUtils\nobjects and reduce the runtime memory and CPU footprint.\n\nAlso, with regard to the subnet matching, differentiate between\nindividual IP matching (CIDRs ending with /32) and full networking\naddress matching with SubnetUtils. The individual IP matching is a\nsimple O(1) independently of the number of entries; however, the full\nCIDRs matching will loop through all the networks and check the netmasks\nagainst the IP, with an O(N) complexity.\n\nThe detection of the proxy-IP is quite complex because it also involves\nthe wrapping of the X-Forwarded* headers management by Jetty, which\noverwrites the socket remote IP address with the original client IP\nforwarded by the proxy in between. It is necessary to wrap the concept\nof the extraction of the address into a generic interface, which can be\noverridden by actual implementations, with a default fallback to the\nstandard servlet mechanism.\n\nThe auth path in RemoteUserUtil needs exactly one piece of information\nthat the servlet API does not give it directly: the pre-X-Forwarded-*\nTCP peer address.\n\n- RemoteUserUtil declares a public PROXY_REMOTE_ADDRESS_ATTR\n  constant. Its javadoc documents the contract: any HTTP layer that\n  wants its requests evaluated against auth.httpTrustedProxyNetworks\n  sets this attribute to the pre-rewrite peer address. If unset,\n  RemoteUserUtil falls back to HttpServletRequest.getRemoteAddr().\n\n- JettyServer writes the attribute (one line) before delegating to\n  the parent ForwardedRequestCustomizer, which is where Jetty rewrites\n  getRemoteAddr() with the X-Forwarded-For value.\n\nBeyond the smaller surface, this design generalizes to non-Jetty HTTP\nlayers without any new class hierarchy. A Tomcat valve, an embedded\nNetty pipeline stage, or a plain servlet filter installed before the\nauth filter can opt into the trusted-proxy check by setting the same\nattribute on the request. No subclass of ProxyAddressProvider, no module\noverride, no Guice rebinding -- the contract is the constant plus its\njavadoc.\n\nIn the case of JettyServer, we need to extend the\nForwardedRequestCustomizer to remember what the original IP was before\nthe wrapping and store into a request attribute. The runtime filter then\naccesses the attribute transparently and, if present, uses the proxy IP\ninstead of the wrapped client IP. This also protects from malicious\nattackers trying to fake their client IP by spoofing the X-Forwarded*\nheader values.\n\nCo-Author: David Ostrovsky \u003cdavid.ostrovsky@gmail.com\u003e\nBug: Issue 520369774\nRelease-Notes: Introduce auth.httpTrustedProxyNetworks for mitigating the vulnerability of auth\u003dHTTP or auth\u003dHTTP_LDAP on external IPs\nChange-Id: If9809ff092520aa467fa108b4179b7b75afe0a85\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "efd083e546334e66eeb9870ab2d2359bdd43bc7c",
      "old_mode": 33188,
      "old_path": "Documentation/config-gerrit.txt",
      "new_id": "911eb56c5c8e740e7ad19f89e08cf3fa308eb4bf",
      "new_mode": 33188,
      "new_path": "Documentation/config-gerrit.txt"
    },
    {
      "type": "modify",
      "old_id": "01420315e5784e2cee5c3b930e93404885531dc3",
      "old_mode": 33188,
      "old_path": "java/com/google/gerrit/httpd/BUILD",
      "new_id": "18334aa81f8b505d9308660002694cdbeea4bcaf",
      "new_mode": 33188,
      "new_path": "java/com/google/gerrit/httpd/BUILD"
    },
    {
      "type": "modify",
      "old_id": "72947363c8b824b42766a35e8e3a7caf9c3d937c",
      "old_mode": 33188,
      "old_path": "java/com/google/gerrit/httpd/RemoteUserUtil.java",
      "new_id": "8856f914607c13b69b9aac0975368c9b3e2210e2",
      "new_mode": 33188,
      "new_path": "java/com/google/gerrit/httpd/RemoteUserUtil.java"
    },
    {
      "type": "modify",
      "old_id": "5a00e99a075d85523c1665dd5b1b2614b5230233",
      "old_mode": 33188,
      "old_path": "java/com/google/gerrit/pgm/http/jetty/JettyServer.java",
      "new_id": "bea4fb427532ff6abd46fe28f52957a22d683577",
      "new_mode": 33188,
      "new_path": "java/com/google/gerrit/pgm/http/jetty/JettyServer.java"
    },
    {
      "type": "modify",
      "old_id": "1e7fa6ac1664602ef3f2d6886192df4a99b30edf",
      "old_mode": 33188,
      "old_path": "java/com/google/gerrit/server/config/AuthConfig.java",
      "new_id": "996ec71b732d1c5ebfa3fbaf36386bd62b343466",
      "new_mode": 33188,
      "new_path": "java/com/google/gerrit/server/config/AuthConfig.java"
    },
    {
      "type": "modify",
      "old_id": "f012ee34ac6e3393ef0cdfaeccb5247e642e7739",
      "old_mode": 33188,
      "old_path": "javatests/com/google/gerrit/httpd/RemoteUserUtilTest.java",
      "new_id": "ab464e8c18870e9db62d19873792faab2d711ad4",
      "new_mode": 33188,
      "new_path": "javatests/com/google/gerrit/httpd/RemoteUserUtilTest.java"
    }
  ]
}
