Security context
High· 7.4GHSA-rx4r-gxpc-h85x CVE-2016-3726CWE-601Published May 14, 2022

Jenkins affected by Open Redirect Vulnerability

Research this vulnerability

Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.

Affected versions

1.652 → fixed in 2.30 → fixed in 1.651.2

Details

Multiple open redirect vulnerabilities in Jenkins before 2.3 and LTS before 1.651.2 allow remote attackers to redirect users to arbitrary web sites and conduct phishing attacks via unspecified vectors related to "scheme-relative" URLs.

The fix

[FIX SECURITY-276] Don't allow open redirect using

Daniel Beck· Apr 25, 2016, 05:50 PM+1732ed0c046df
core/src/main/java/hudson/Util.java+14 0
@@ -77,6 +77,8 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.codec.digest.DigestUtils;
+import org.kohsuke.accmod.Restricted;
+import org.kohsuke.accmod.restrictions.NoExternalUse;
/**
* Various utility methods that don't have more proper home.
@@ -1454,7 +1456,12 @@ public static String intern(@CheckForNull String s) {
* The same algorithm can be seen in {@link URI}, but
* implementing this by ourselves allow it to be more lenient about
* escaping of URI.
+ *
+ * @deprecated Use {@code isAbsoluteOrSchemeRelativeUri} instead if your goal is to prevent open redirects
*/
+ @Deprecated
+ @RestrictedSince("1.651.2 / 2.TODO")
+ @Restricted(NoExternalUse.class)
public static boolean isAbsoluteUri(@Nonnull String uri) {
int idx = uri.indexOf(':');
if (idx<0) return false; // no ':'. can't be absolute
@@ -1463,6 +1470,13 @@ public static boolean isAbsoluteUri(@Nonnull String uri) {
return idx<_indexOf(uri, '#') && idx<_indexOf(uri,'?') && idx<_indexOf(uri,'/');
}
+ /**
+ * Return true iff the parameter denotes an absolute URI, or a scheme-relative URI.
+ */
+ public static boolean isAbsoluteOrSchemeRelativeUri(@Nonnull String uri) {
+ return isAbsoluteUri(uri) || uri.startsWith("//");
+ }
+
/**
* Works like {@link String#indexOf(int)} but 'not found' is returned as s.length(), not -1.
* This enables more straight-forward comparison.
core/src/main/java/hudson/model/DirectoryBrowserSupport.java+1 1
@@ -158,7 +158,7 @@ private void serveFile(StaplerRequest req, StaplerResponse rsp, VirtualFile root
String pattern = req.getParameter("pattern");
if(pattern==null)
pattern = req.getParameter("path"); // compatibility with Hudson<1.129
- if(pattern!=null && !Util.isAbsoluteUri(pattern)) {// avoid open redirect
+ if(pattern!=null && !Util.isAbsoluteOrSchemeRelativeUri(pattern)) {// avoid open redirect
rsp.sendRedirect2(pattern);
return;
}
core/src/main/java/hudson/model/ParametersDefinitionProperty.java+1 1
@@ -158,7 +158,7 @@ public void _doBuild(StaplerRequest req, StaplerResponse rsp, @QueryParameter Ti
getJob(), delay.getTime(), new ParametersAction(values), new CauseAction(new Cause.UserIdCause()));
if (item!=null) {
String url = formData.optString("redirectTo");
- if (url==null || Util.isAbsoluteUri(url)) // avoid open redirect
+ if (url==null || Util.isAbsoluteOrSchemeRelativeUri(url)) // avoid open redirect
url = req.getContextPath()+'/'+item.getUrl();
rsp.sendRedirect(formData.optInt("statusCode",SC_CREATED), url);
} else
core/src/main/java/hudson/security/AuthenticationProcessingFilter2.java+1 1
@@ -53,7 +53,7 @@ protected String determineTargetUrl(HttpServletRequest request) {
if (targetUrl == null)
return getDefaultTargetUrl();
- if (Util.isAbsoluteUri(targetUrl))
+ if (Util.isAbsoluteOrSchemeRelativeUri(targetUrl))
return "."; // avoid open redirect
// URL returned from determineTargetUrl() is resolved against the context path,

References