{"id":"CVE-2020-6858","aliases":["EUVD-2020-0336","GHSA-6v7p-v754-j89v"],"status":"published","title":"HTTP Response Splitting in Styx","description":"Hotels Styx through 1.0.0.beta8 allows HTTP response splitting due to CRLF Injection. This is exploitable if untrusted user input can appear in a response header.","severity":{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N","level":"medium","assessor":"primary","from":"nvd"},"epss":{"day":"2026-11-10","score":0.01162,"percentile":0.67469,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-74"],"published":"2020-03-03T15:32:03Z","modified":"2026-10-20T10:54:30Z","fixes":[{"ecosystem":"Maven","package":"com.hotels.styx:styx-api","fixed_in":["1.0.0-rc1"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Maven","package":"com.hotels.styx:styx-api","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"1.0.0.beta8"},{"fixed":"1.0.0-rc1"}]}]},{"source":"osv","ecosystem":"Maven","package":"com.hotels.styx:styx-api","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.0.0-rc1"}]}],"versions":["0.0.1.beta6","0.7.10","0.7.3","0.7.4","0.7.5","0.7.6","0.7.7","0.7.8","0.7.9","styx-1.0.0.beta2","v0.0.5"]}],"products":[{"vendor":"hotels","product":"styx"}],"references":[{"url":"https://twitter.com/JLLeitschuh","tags":["x_refsource_MISC","x_transferred","Third Party Advisory","advisory","web"]},{"url":"https://github.com/HotelsDotCom/styx/security/advisories/GHSA-6v7p-v754-j89v","tags":["x_refsource_MISC","x_transferred","Exploit","Third Party Advisory","evidence","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2020-6858","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-6v7p-v754-j89v"}],"sources":{"cve":[{"id":"CVE-2020-6858","description":"Hotels Styx through 1.0.0.beta8 allows HTTP response splitting due to CRLF Injection. This is exploitable if untrusted user input can appear in a response header.","status":"published","published":"2020-03-12T13:38:58Z","modified":"2024-08-04T09:11:05.162Z","updated_at":"2026-11-02T14:35:52.268457Z"}],"euvd":[{"id":"EUVD-2020-0336","description":"Hotels Styx through 1.0.0.beta8 allows HTTP response splitting due to CRLF Injection. This is exploitable if untrusted user input can appear in a response header.","status":"published","published":"2020-03-12T13:38:58Z","modified":"2024-08-04T09:11:05Z","updated_at":"2026-11-03T03:08:01.566283Z"}],"ghsa":[{"id":"GHSA-6v7p-v754-j89v","title":"HTTP Response Splitting in Styx","description":"# Vulnerability\nStyx is vulnerable to CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers (\u0026#39;HTTP Response Splitting\u0026#39;).\n\n# Vulnerable Component\nThe vulnerable component is the `com.hotels.styx.api.HttpHeaders.Builder` due to disabling the HTTP Header validation built into Netty in these locations:\n\nhttps://github.com/HotelsDotCom/styx/blob/e1d578e9b9c38df9cd19c21dc2eb9b949d85b558/components/api/src/main/java/com/hotels/styx/api/HttpHeaders.java#L145\n\nhttps://github.com/HotelsDotCom/styx/blob/e1d578e9b9c38df9cd19c21dc2eb9b949d85b558/components/api/src/main/java/com/hotels/styx/api/HttpHeaders.java#L145\n\n`new DefaultHttpHeaders(false)` disables the built-in validation in Netty. Either use the default constructor or `new DefaultHttpHeaders(true`  instead.\n\nAdditionally, another vulnerable component is the StyxToNettyResponseTranslator due to also disabling the HTTP Header validation built into netty in this location.\n\nhttps://github.com/HotelsDotCom/styx/blob/8d60e5493e65d0d536afc0b350dcb02d24e0f7a7/components/server/src/main/java/com/hotels/styx/server/netty/connectors/StyxToNettyResponseTranslator.java#L30\n\n `DefaultHttpResponse nettyResponse = new DefaultHttpResponse(version, httpResponseStatus, false); `\n`new DefaultHttpResponse(version, httpResponseStatus, false);` disables the built-in validation in Netty. Please use the constructor `new DefaultHttpResponse(version, httpResponseStatus, true);`\n\n# Proof of Concept\nThe following test plugin proves that there is no header validation occurring.\n\n```java\n    static class VulnerablePlugin implements Plugin {\n\n        @Override\n        public Eventual\u0026lt;LiveHttpResponse\u0026gt; intercept(LiveHttpRequest request, Chain chain) {\n            String header = request.queryParam(\u0026quot;header-value\u0026quot;).get();\n            LiveHttpRequest newRequest = request.newBuilder()\n                .header(\u0026quot;myRequestHeader\u0026quot;, header)\n                .build();\n            return chain.proceed(newRequest).map(response -\u0026gt;\n                response.newBuilder().header(\u0026quot;myResponseHeader\u0026quot;, header).build()\n            ) ;\n        }\n\n    }\n\n    @Test\n    public void simpleHeaderInjectionVulnerabilityPOC() {\n        Plugin vulnerablePlugin = new VulnerablePlugin();\n        // a simple way to mock the downstream system\n        HttpInterceptor.Chain chain = request -\u0026gt; {\n            assertThat(request.header(\u0026quot;myRequestHeader\u0026quot;).orElse(null), is(\u0026quot;test\\r\\nAnother: CRLF_Injection\u0026quot;));\n            return Eventual.of(response(OK).build());\n        };\n\n        // an example request you expect your plugin to receive\n        String encodedGet = URLEncoder.encode(\u0026quot;test\\r\\nAnother: CRLF_Injection\u0026quot;);\n        LiveHttpRequest request = get(\u0026quot;/foo?header-value=\u0026quot; + encodedGet)\n            .build();\n\n        // since this is a test, we want to wait for the response\n        LiveHttpResponse response = Mono.from(vulnerablePlugin.intercept(request, chain)).block();\n\n        assertThat(response.header(\u0026quot;myResponseHeader\u0026quot;).orElse(null), is(\u0026quot;test\\r\\nAnother: CRLF_Injection\u0026quot;));\n    }\n```\nAdditionally, if you run this LiveHttpResponse from this test through the `StyxToNettyResponseTranslator::toNettyResponse`, ideally, it would have caused an exception to be thrown. In its current state, it does not.\n\n# Similar Vulnerabilities\nThere have been reports of similar vulnerabilities in other popular libraries.\n\nGHSA-35fr-h7jr-hh86 -\u0026gt; CVE-2019-16771\nGHSA-mvqp-q37c-wf9j -\u0026gt; CVE-2019-17513\n\n\n# Finding\nThis vulnerability was found due to this query that [Jonathan Leitschuh](https://twitter.com/jlleitschuh) contributed to the Semmle QL project.\nhttps://lgtm.com/rules/1510696449842/alerts/","status":"published","published":"2020-03-03T15:32:03Z","modified":"2023-01-09T05:02:13Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N","level":"medium"}],"cwes":["CWE-74"],"updated_at":"2026-11-02T14:36:03.040255Z"}],"nvd":[{"id":"CVE-2020-6858","description":"Hotels Styx through 1.0.0.beta8 allows HTTP response splitting due to CRLF Injection. This is exploitable if untrusted user input can appear in a response header.","status":"published","published":"2020-03-12T14:15:21.487Z","modified":"2026-06-17T03:23:55.943Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N","level":"medium","assessor":"primary"},{"version":"2.0","score":4.3,"vector":"AV:N/AC:M/Au:N/C:N/I:P/A:N","level":"medium","assessor":"primary"}],"cwes":["CWE-74"],"updated_at":"2026-11-02T14:05:55.32877Z"}],"osv":[{"id":"CVE-2020-6858","description":"Hotels Styx through 1.0.0.beta8 allows HTTP response splitting due to CRLF Injection. This is exploitable if untrusted user input can appear in a response header.","status":"published","published":"2020-03-12T14:15:21.487Z","modified":"2026-10-20T10:54:30.973609984Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N","level":"medium"}],"updated_at":"2026-11-02T15:44:17.34531Z"},{"id":"GHSA-6v7p-v754-j89v","title":"HTTP Response Splitting in Styx","description":"# Vulnerability\nStyx is vulnerable to CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers (\u0026#39;HTTP Response Splitting\u0026#39;).\n\n# Vulnerable Component\nThe vulnerable component is the `com.hotels.styx.api.HttpHeaders.Builder` due to disabling the HTTP Header validation built into Netty in these locations:\n\nhttps://github.com/HotelsDotCom/styx/blob/e1d578e9b9c38df9cd19c21dc2eb9b949d85b558/components/api/src/main/java/com/hotels/styx/api/HttpHeaders.java#L145\n\nhttps://github.com/HotelsDotCom/styx/blob/e1d578e9b9c38df9cd19c21dc2eb9b949d85b558/components/api/src/main/java/com/hotels/styx/api/HttpHeaders.java#L145\n\n`new DefaultHttpHeaders(false)` disables the built-in validation in Netty. Either use the default constructor or `new DefaultHttpHeaders(true`  instead.\n\nAdditionally, another vulnerable component is the StyxToNettyResponseTranslator due to also disabling the HTTP Header validation built into netty in this location.\n\nhttps://github.com/HotelsDotCom/styx/blob/8d60e5493e65d0d536afc0b350dcb02d24e0f7a7/components/server/src/main/java/com/hotels/styx/server/netty/connectors/StyxToNettyResponseTranslator.java#L30\n\n `DefaultHttpResponse nettyResponse = new DefaultHttpResponse(version, httpResponseStatus, false); `\n`new DefaultHttpResponse(version, httpResponseStatus, false);` disables the built-in validation in Netty. Please use the constructor `new DefaultHttpResponse(version, httpResponseStatus, true);`\n\n# Proof of Concept\nThe following test plugin proves that there is no header validation occurring.\n\n```java\n    static class VulnerablePlugin implements Plugin {\n\n        @Override\n        public Eventual\u0026lt;LiveHttpResponse\u0026gt; intercept(LiveHttpRequest request, Chain chain) {\n            String header = request.queryParam(\u0026quot;header-value\u0026quot;).get();\n            LiveHttpRequest newRequest = request.newBuilder()\n                .header(\u0026quot;myRequestHeader\u0026quot;, header)\n                .build();\n            return chain.proceed(newRequest).map(response -\u0026gt;\n                response.newBuilder().header(\u0026quot;myResponseHeader\u0026quot;, header).build()\n            ) ;\n        }\n\n    }\n\n    @Test\n    public void simpleHeaderInjectionVulnerabilityPOC() {\n        Plugin vulnerablePlugin = new VulnerablePlugin();\n        // a simple way to mock the downstream system\n        HttpInterceptor.Chain chain = request -\u0026gt; {\n            assertThat(request.header(\u0026quot;myRequestHeader\u0026quot;).orElse(null), is(\u0026quot;test\\r\\nAnother: CRLF_Injection\u0026quot;));\n            return Eventual.of(response(OK).build());\n        };\n\n        // an example request you expect your plugin to receive\n        String encodedGet = URLEncoder.encode(\u0026quot;test\\r\\nAnother: CRLF_Injection\u0026quot;);\n        LiveHttpRequest request = get(\u0026quot;/foo?header-value=\u0026quot; + encodedGet)\n            .build();\n\n        // since this is a test, we want to wait for the response\n        LiveHttpResponse response = Mono.from(vulnerablePlugin.intercept(request, chain)).block();\n\n        assertThat(response.header(\u0026quot;myResponseHeader\u0026quot;).orElse(null), is(\u0026quot;test\\r\\nAnother: CRLF_Injection\u0026quot;));\n    }\n```\nAdditionally, if you run this LiveHttpResponse from this test through the `StyxToNettyResponseTranslator::toNettyResponse`, ideally, it would have caused an exception to be thrown. In its current state, it does not.\n\n# Similar Vulnerabilities\nThere have been reports of similar vulnerabilities in other popular libraries.\n\nGHSA-35fr-h7jr-hh86 -\u0026gt; CVE-2019-16771\nGHSA-mvqp-q37c-wf9j -\u0026gt; CVE-2019-17513\n\n\n# Finding\nThis vulnerability was found due to this query that [Jonathan Leitschuh](https://twitter.com/jlleitschuh) contributed to the Semmle QL project.\nhttps://lgtm.com/rules/1510696449842/alerts/","status":"published","published":"2020-03-03T15:32:03Z","modified":"2026-07-08T06:00:59.240256745Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N","level":"medium"}],"cwes":["CWE-74"],"updated_at":"2026-11-02T15:46:39.965326Z"}]}}
