CVE-2023-36812 (Java, published 2023-06-30T23:15Z)
Description: value: OpenTSDB is a open source, distributed, scalable Time Series Database (TSDB). OpenTSDB is vulnerable to Remote Code Execution vulnerability by writing user-controlled input to Gnuplot configuration file and running Gnuplot with the generated configuration. This issue has been patched in  commit `07c4641471c` and further refined in commit `fa88d3e4b`. These patches are available in the `2.4.2` release. Users are advised to upgrade. User unable to upgrade may disable Gunuplot via the config option`tsd.core.enable_ui = true` and remove the shell files `mygnuplot.bat` and `mygnuplot.sh`.
Severity: nan (CVSS v3 base score: 9.8)
Weakness: CWE-74 \u2014 Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.
Repository: https://github.com/OpenTSDB/opentsdb
Files changed:
src/tsd/HttpQuery.java
test/tsd/TestHttpQuery.java
test/tsd/TestQueryRpc.java
Commit message: Fix for #2269 and #2267 XSS vulnerability.
Escaping the user supplied input when outputing the HTML for the old BadRequest
HTML handlers should help. Thanks to the reporters.
Fixes CVE-2018-13003.


Vulnerable code:
                         + pretty_exc
                         + exception.getMessage()
    assertTrue(json.contains("No such name for 'foo': 'metrics'"));
    assertTrue(json.contains("No such name for 'foo': 'metrics'"));

Fixed code:
import com.google.common.html.HtmlEscapers;
      String response = "";
      if (pretty_exc != null) {
        response = HtmlEscapers.htmlEscaper().escape(pretty_exc);
      }
                         + response
      String response = "";
      if (exception.getMessage() != null) {
        response = HtmlEscapers.htmlEscaper().escape(exception.getMessage());
      }
                         + response

  @Test
  public void internalErrorDeprecatedHTMLEscaped() {
    HttpQuery query = NettyMocks.getQuery(tsdb, "");
    query.internalError(new Exception("<script>alert(document.cookie)</script>"));

    assertEquals(HttpResponseStatus.INTERNAL_SERVER_ERROR,
        query.response().getStatus());
    assertTrue(query.response().getContent().toString(Charset.forName("UTF-8")).contains(
        "&lt;script&gt;alert(document.cookie)&lt;/script&gt;"
    ));
  }

  @Test
  public void badRequestDeprecatedHTMLEscaped() {
    HttpQuery query = NettyMocks.getQuery(tsdb, "/");
    query.badRequest(new BadRequestException("<script>alert(document.cookie)</script>"));

    assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
    assertTrue(query.response().getContent().toString(Charset.forName("UTF-8")).contains(
        "The reason provided was:<blockquote>&lt;script&gt;alert(document.cookie)&lt;/script&gt;"
    ));
  }
    assertTrue(json.contains("No such name for &#39;foo&#39;: &#39;metrics&#39;"));
    assertTrue(json.contains("No such name for &#39;foo&#39;: &#39;metrics&#39;"));