Index: wp-includes/functions.php
===================================================================
--- wp-includes/functions.php	(Revision 46553)
+++ wp-includes/functions.php	(Arbeitskopie)
@@ -2289,7 +2289,11 @@
 		$dir = WP_CONTENT_DIR . '/uploads';
 	} elseif ( 0 !== strpos( $upload_path, ABSPATH ) ) {
 		// $dir is absolute, $upload_path is (maybe) relative to ABSPATH
-		$dir = path_join( ABSPATH, $upload_path );
+		if ( path_is_absolute( $upload_path ) ) {
+			$dir = $upload_path;
+		} else {
+			$dir = _wp_merge_trusted_paths( ABSPATH, $upload_path );
+		}
 	} else {
 		$dir = $upload_path;
 	}
@@ -2299,7 +2303,7 @@
 		if ( empty( $upload_path ) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) ) {
 			$url = WP_CONTENT_URL . '/uploads';
 		} else {
-			$url = trailingslashit( $siteurl ) . $upload_path;
+			$url = _wp_merge_trusted_paths( $siteurl, $upload_path );
 		}
 	}
 
@@ -2308,8 +2312,8 @@
 	 * We also sometimes obey UPLOADS when rewriting is enabled -- see the next block.
 	 */
 	if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) {
-		$dir = ABSPATH . UPLOADS;
-		$url = trailingslashit( $siteurl ) . UPLOADS;
+		$dir = _wp_merge_trusted_paths( ABSPATH, UPLOADS );
+		$url = _wp_merge_trusted_paths( $siteurl, UPLOADS );
 	}
 
 	// If multisite (and if not the main site in a post-MU network)
@@ -2352,7 +2356,7 @@
 			if ( defined( 'BLOGUPLOADDIR' ) ) {
 				$dir = untrailingslashit( BLOGUPLOADDIR );
 			} else {
-				$dir = ABSPATH . UPLOADS;
+				$dir = _wp_merge_trusted_paths( ABSPATH, UPLOADS );
 			}
 			$url = trailingslashit( $siteurl ) . 'files';
 		}
@@ -2386,6 +2390,32 @@
 }
 
 /**
+ * Get an absolute path/directory/url of an absolute and a relative part
+ *
+ * Not to be used on untrusted input, as security checks rely on presence of '../' to detect unwanted path traversal.
+ *
+ * @param string $absolute_base absolute part
+ * @param string $relative_part relative part (may begin with '../')
+ * @return string  path/directory/url, absolute, merged
+ */
+function _wp_merge_trusted_paths( $absolute_base, $relative_part ) {
+	$one_parts = explode( '/', rtrim( $absolute_base, '/' ) );
+	while ( substr( $relative_part, 0, 3 ) == '../' ) {
+		$popped = array_pop( $one_parts );
+		if ( $popped === '' ) {
+			// merge doesn't work. return $absolute_base instead
+			return $absolute_base;
+		}
+		$relative_part = substr( $relative_part, 3 );
+	}
+	$absolute_base = implode( '/', $one_parts );
+	$relative_part = ltrim( $relative_part, '/' );
+	$all           = $absolute_base . '/' . $relative_part;
+
+	return $all;
+}
+
+/**
  * Get a filename that is sanitized and unique for the given directory.
  *
  * If the filename is not unique, then a number will be added to the filename
