From 3f1b519f975e06f8f62c18dc5d90307bd161287d Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 17 Jan 2022 15:33:42 +0100 Subject: [PATCH 1/3] Fix path traversal vulnerability --- .../scm/plugin/PathWebResourceLoader.java | 37 ++++++++--------- .../scm/plugin/PathWebResourceLoaderTest.java | 41 ++++++++++++++++--- 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/PathWebResourceLoader.java b/scm-webapp/src/main/java/sonia/scm/plugin/PathWebResourceLoader.java index 8dbd29ef03..fd8889f5b7 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/PathWebResourceLoader.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/PathWebResourceLoader.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.plugin; import org.slf4j.Logger; @@ -38,37 +38,32 @@ import java.nio.file.Path; * @author Sebastian Sdorra * @since 2.0.0 */ -public class PathWebResourceLoader implements WebResourceLoader -{ +public class PathWebResourceLoader implements WebResourceLoader { private static final String SEPARATOR = "/"; + private final Path directory; + /** * the logger for PathWebResourceLoader */ - private static final Logger LOG = - LoggerFactory.getLogger(PathWebResourceLoader.class); + private static final Logger LOG = LoggerFactory.getLogger(PathWebResourceLoader.class); - public PathWebResourceLoader(Path directory) - { - this.directory = directory; + public PathWebResourceLoader(Path directory) { + this.directory = directory.toAbsolutePath().normalize(); } @Override public URL getResource(String path) { URL resource = null; - Path file = directory.resolve(filePath(path)); + Path file = directory.resolve(filePath(path)).toAbsolutePath().normalize(); - if (Files.exists(file) && ! Files.isDirectory(file)) - { + if (isValidPath(file)) { LOG.trace("found path {} at {}", path, file); - try - { + try { resource = file.toUri().toURL(); - } - catch (MalformedURLException ex) - { + } catch (MalformedURLException ex) { LOG.error("could not transform path to url", ex); } } else { @@ -78,6 +73,12 @@ public class PathWebResourceLoader implements WebResourceLoader return resource; } + private boolean isValidPath(Path file) { + return Files.exists(file) + && !Files.isDirectory(file) + && file.startsWith(directory); + } + private String filePath(String path) { if (path.startsWith(SEPARATOR)) { return path.substring(1); @@ -85,8 +86,4 @@ public class PathWebResourceLoader implements WebResourceLoader return path; } - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private final Path directory; } diff --git a/scm-webapp/src/test/java/sonia/scm/plugin/PathWebResourceLoaderTest.java b/scm-webapp/src/test/java/sonia/scm/plugin/PathWebResourceLoaderTest.java index ce9ca8d497..b8075bd2f5 100644 --- a/scm-webapp/src/test/java/sonia/scm/plugin/PathWebResourceLoaderTest.java +++ b/scm-webapp/src/test/java/sonia/scm/plugin/PathWebResourceLoaderTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- @@ -42,11 +42,10 @@ import java.net.URL; * * @author Sebastian Sdorra */ -public class PathWebResourceLoaderTest extends WebResourceLoaderTestBase -{ +public class PathWebResourceLoaderTest extends WebResourceLoaderTestBase { @Test - public void testGetNullForDirectories() throws IOException { + public void shouldReturnNullForDirectories() throws IOException { File directory = temp.newFolder(); assertTrue(new File(directory, "awesome").mkdir()); @@ -56,7 +55,7 @@ public class PathWebResourceLoaderTest extends WebResourceLoaderTestBase @Test - public void testGetResource() throws IOException { + public void shouldReturnResource() throws IOException { File directory = temp.newFolder(); URL url = file(directory, "myresource").toURI().toURL(); @@ -68,4 +67,36 @@ public class PathWebResourceLoaderTest extends WebResourceLoaderTestBase assertNull(resourceLoader.getResource("other")); } + @Test + public void shouldNotReturnPathsWithAbsolutePath() throws IOException { + File base = temp.newFolder(); + + File one = new File(base, "one"); + assertTrue(one.mkdirs()); + File two = new File(base, "two"); + assertTrue(two.mkdirs()); + + File secret = new File(two, "secret"); + assertTrue(secret.createNewFile()); + + WebResourceLoader resourceLoader = new PathWebResourceLoader(one.toPath()); + assertNull(resourceLoader.getResource(secret.getAbsolutePath())); + assertNull(resourceLoader.getResource("/" + secret.getAbsolutePath())); + } + + @Test + public void shouldNotReturnPathsWithPathTraversal() throws IOException { + File base = temp.newFolder(); + + File one = new File(base, "one"); + assertTrue(one.mkdirs()); + File two = new File(base, "two"); + assertTrue(two.mkdirs()); + + File secret = new File(two, "secret"); + assertTrue(secret.createNewFile()); + + WebResourceLoader resourceLoader = new PathWebResourceLoader(one.toPath()); + assertNull(resourceLoader.getResource("../two/secret")); + } } From 335f8a65889a3440161d9213580393175790da5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 17 Jan 2022 16:04:21 +0100 Subject: [PATCH 2/3] Adjust changelog for 2.29.1 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7d2431db0..a8193a6b58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.29.1] - 2022-01-17 +### Fixed +- Path traversal vulnerability + ## [2.29.0] - 2022-01-07 ### Added - CSS variables for plugins ([#1910](https://github.com/scm-manager/scm-manager/pull/1910)) @@ -900,3 +904,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [2.27.4]: https://scm-manager.org/download/2.27.4 [2.28.0]: https://scm-manager.org/download/2.28.0 [2.29.0]: https://scm-manager.org/download/2.29.0 +[2.29.1]: https://scm-manager.org/download/2.29.1 + From d692bf6bffb49ac255e60ccce0cc012acc3225bb Mon Sep 17 00:00:00 2001 From: CES Marvin Date: Mon, 17 Jan 2022 15:12:54 +0000 Subject: [PATCH 3/3] Release version 2.29.1 --- gradle.properties | 2 +- lerna.json | 2 +- scm-plugins/scm-git-plugin/package.json | 4 ++-- scm-plugins/scm-hg-plugin/package.json | 4 ++-- scm-plugins/scm-legacy-plugin/package.json | 4 ++-- scm-plugins/scm-svn-plugin/package.json | 4 ++-- scm-ui/e2e-tests/package.json | 2 +- scm-ui/ui-api/package.json | 4 ++-- scm-ui/ui-components/package.json | 10 +++++----- scm-ui/ui-extensions/package.json | 4 ++-- scm-ui/ui-plugins/package.json | 12 ++++++------ scm-ui/ui-polyfill/package.json | 2 +- scm-ui/ui-scripts/package.json | 2 +- scm-ui/ui-styles/package.json | 2 +- scm-ui/ui-tests/package.json | 2 +- scm-ui/ui-types/package.json | 2 +- scm-ui/ui-webapp/package.json | 10 +++++----- 17 files changed, 36 insertions(+), 36 deletions(-) diff --git a/gradle.properties b/gradle.properties index 4613e7df18..1e314e8f91 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,5 +22,5 @@ # SOFTWARE. # group = sonia.scm -version = 2.29.0 +version = 2.29.1 org.gradle.jvmargs=-Xmx1024M diff --git a/lerna.json b/lerna.json index 410b3ecec8..c83f36339b 100644 --- a/lerna.json +++ b/lerna.json @@ -5,5 +5,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "2.29.0" + "version": "2.29.1" } diff --git a/scm-plugins/scm-git-plugin/package.json b/scm-plugins/scm-git-plugin/package.json index 6af65ad3dd..d759ffe2ba 100644 --- a/scm-plugins/scm-git-plugin/package.json +++ b/scm-plugins/scm-git-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-git-plugin", "private": true, - "version": "2.29.0", + "version": "2.29.1", "license": "MIT", "main": "./src/main/js/index.ts", "scripts": { @@ -11,7 +11,7 @@ "typecheck": "tsc" }, "dependencies": { - "@scm-manager/ui-plugins": "^2.29.0" + "@scm-manager/ui-plugins": "^2.29.1" }, "devDependencies": { "@scm-manager/babel-preset": "^2.12.0", diff --git a/scm-plugins/scm-hg-plugin/package.json b/scm-plugins/scm-hg-plugin/package.json index 7aa96a7b9c..be2bb23e7e 100644 --- a/scm-plugins/scm-hg-plugin/package.json +++ b/scm-plugins/scm-hg-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-hg-plugin", "private": true, - "version": "2.29.0", + "version": "2.29.1", "license": "MIT", "main": "./src/main/js/index.ts", "scripts": { @@ -10,7 +10,7 @@ "typecheck": "tsc" }, "dependencies": { - "@scm-manager/ui-plugins": "^2.29.0" + "@scm-manager/ui-plugins": "^2.29.1" }, "devDependencies": { "@scm-manager/babel-preset": "^2.12.0", diff --git a/scm-plugins/scm-legacy-plugin/package.json b/scm-plugins/scm-legacy-plugin/package.json index 6b97682203..e9432ad3ae 100644 --- a/scm-plugins/scm-legacy-plugin/package.json +++ b/scm-plugins/scm-legacy-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-legacy-plugin", "private": true, - "version": "2.29.0", + "version": "2.29.1", "license": "MIT", "main": "./src/main/js/index.tsx", "scripts": { @@ -10,7 +10,7 @@ "typecheck": "tsc" }, "dependencies": { - "@scm-manager/ui-plugins": "^2.29.0" + "@scm-manager/ui-plugins": "^2.29.1" }, "devDependencies": { "@scm-manager/babel-preset": "^2.12.0", diff --git a/scm-plugins/scm-svn-plugin/package.json b/scm-plugins/scm-svn-plugin/package.json index 855298a8c9..03a834a139 100644 --- a/scm-plugins/scm-svn-plugin/package.json +++ b/scm-plugins/scm-svn-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-svn-plugin", "private": true, - "version": "2.29.0", + "version": "2.29.1", "license": "MIT", "main": "./src/main/js/index.ts", "scripts": { @@ -10,7 +10,7 @@ "typecheck": "tsc" }, "dependencies": { - "@scm-manager/ui-plugins": "^2.29.0" + "@scm-manager/ui-plugins": "^2.29.1" }, "devDependencies": { "@scm-manager/babel-preset": "^2.12.0", diff --git a/scm-ui/e2e-tests/package.json b/scm-ui/e2e-tests/package.json index c5da62731d..07ce776c3b 100644 --- a/scm-ui/e2e-tests/package.json +++ b/scm-ui/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/e2e-tests", - "version": "2.29.0", + "version": "2.29.1", "description": "End to end Tests for SCM-Manager", "main": "index.js", "author": "Eduard Heimbuch ", diff --git a/scm-ui/ui-api/package.json b/scm-ui/ui-api/package.json index 0af279afdd..f360cdfc1f 100644 --- a/scm-ui/ui-api/package.json +++ b/scm-ui/ui-api/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-api", - "version": "2.29.0", + "version": "2.29.1", "description": "React hook api for the SCM-Manager backend", "main": "src/index.ts", "files": [ @@ -25,7 +25,7 @@ "react-test-renderer": "^17.0.1" }, "dependencies": { - "@scm-manager/ui-types": "^2.29.0", + "@scm-manager/ui-types": "^2.29.1", "fetch-mock-jest": "^1.5.1", "gitdiff-parser": "^0.1.2", "query-string": "6.14.1", diff --git a/scm-ui/ui-components/package.json b/scm-ui/ui-components/package.json index 00786552dd..5265621c6c 100644 --- a/scm-ui/ui-components/package.json +++ b/scm-ui/ui-components/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-components", - "version": "2.29.0", + "version": "2.29.1", "description": "UI Components for SCM-Manager and its plugins", "main": "src/index.ts", "files": [ @@ -25,7 +25,7 @@ "@scm-manager/jest-preset": "^2.13.0", "@scm-manager/prettier-config": "^2.10.1", "@scm-manager/tsconfig": "^2.12.0", - "@scm-manager/ui-tests": "^2.29.0", + "@scm-manager/ui-tests": "^2.29.1", "@storybook/addon-actions": "^6.3.12", "@storybook/addon-storyshots": "^6.3.12", "@storybook/builder-webpack5": "^6.3.12", @@ -65,9 +65,9 @@ "worker-plugin": "^3.2.0" }, "dependencies": { - "@scm-manager/ui-api": "^2.29.0", - "@scm-manager/ui-extensions": "^2.29.0", - "@scm-manager/ui-types": "^2.29.0", + "@scm-manager/ui-api": "^2.29.1", + "@scm-manager/ui-extensions": "^2.29.1", + "@scm-manager/ui-types": "^2.29.1", "classnames": "^2.2.6", "date-fns": "^2.4.1", "deepmerge": "^4.2.2", diff --git a/scm-ui/ui-extensions/package.json b/scm-ui/ui-extensions/package.json index 30ea98669e..bf7a9bd07b 100644 --- a/scm-ui/ui-extensions/package.json +++ b/scm-ui/ui-extensions/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-extensions", - "version": "2.29.0", + "version": "2.29.1", "main": "src/index.ts", "license": "MIT", "private": false, @@ -10,7 +10,7 @@ "test": "jest" }, "dependencies": { - "@scm-manager/ui-types": "^2.29.0", + "@scm-manager/ui-types": "^2.29.1", "react": "^17.0.1" }, "devDependencies": { diff --git a/scm-ui/ui-plugins/package.json b/scm-ui/ui-plugins/package.json index e012534362..bf6d052e4a 100644 --- a/scm-ui/ui-plugins/package.json +++ b/scm-ui/ui-plugins/package.json @@ -1,13 +1,13 @@ { "name": "@scm-manager/ui-plugins", - "version": "2.29.0", + "version": "2.29.1", "license": "MIT", "bin": { "ui-plugins": "./bin/ui-plugins.js" }, "dependencies": { - "@scm-manager/ui-components": "^2.29.0", - "@scm-manager/ui-extensions": "^2.29.0", + "@scm-manager/ui-components": "^2.29.1", + "@scm-manager/ui-extensions": "^2.29.1", "classnames": "^2.2.6", "query-string": "6.14.1", "react": "^17.0.1", @@ -25,9 +25,9 @@ "@scm-manager/plugin-scripts": "^1.2.2", "@scm-manager/prettier-config": "^2.10.1", "@scm-manager/tsconfig": "^2.12.0", - "@scm-manager/ui-scripts": "^2.29.0", - "@scm-manager/ui-tests": "^2.29.0", - "@scm-manager/ui-types": "^2.29.0", + "@scm-manager/ui-scripts": "^2.29.1", + "@scm-manager/ui-tests": "^2.29.1", + "@scm-manager/ui-types": "^2.29.1", "@types/classnames": "^2.2.9", "@types/enzyme": "^3.10.3", "@types/fetch-mock": "^7.3.1", diff --git a/scm-ui/ui-polyfill/package.json b/scm-ui/ui-polyfill/package.json index 8cee0d21dc..42decc59a9 100644 --- a/scm-ui/ui-polyfill/package.json +++ b/scm-ui/ui-polyfill/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-polyfill", - "version": "2.29.0", + "version": "2.29.1", "description": "Polyfills for SCM-Manager UI", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/ui-scripts/package.json b/scm-ui/ui-scripts/package.json index 9b76dc750b..591138d6f8 100644 --- a/scm-ui/ui-scripts/package.json +++ b/scm-ui/ui-scripts/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-scripts", - "version": "2.29.0", + "version": "2.29.1", "description": "Build scripts for SCM-Manager", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/ui-styles/package.json b/scm-ui/ui-styles/package.json index 26849d9d73..431c69fcf1 100644 --- a/scm-ui/ui-styles/package.json +++ b/scm-ui/ui-styles/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-styles", - "version": "2.29.0", + "version": "2.29.1", "description": "Styles for SCM-Manager", "main": "src/scm.scss", "license": "MIT", diff --git a/scm-ui/ui-tests/package.json b/scm-ui/ui-tests/package.json index bd566f843c..18f660b9ba 100644 --- a/scm-ui/ui-tests/package.json +++ b/scm-ui/ui-tests/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-tests", - "version": "2.29.0", + "version": "2.29.1", "description": "UI-Tests helpers", "author": "Sebastian Sdorra ", "license": "MIT", diff --git a/scm-ui/ui-types/package.json b/scm-ui/ui-types/package.json index 4a91bbe580..884ae6f773 100644 --- a/scm-ui/ui-types/package.json +++ b/scm-ui/ui-types/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-types", - "version": "2.29.0", + "version": "2.29.1", "description": "Typescript types for SCM-Manager related Objects", "main": "src/index.ts", "files": [ diff --git a/scm-ui/ui-webapp/package.json b/scm-ui/ui-webapp/package.json index 8fd98c0daa..7b4c3bdd86 100644 --- a/scm-ui/ui-webapp/package.json +++ b/scm-ui/ui-webapp/package.json @@ -1,11 +1,11 @@ { "name": "@scm-manager/ui-webapp", - "version": "2.29.0", + "version": "2.29.1", "private": true, "dependencies": { - "@scm-manager/ui-api": "^2.29.0", - "@scm-manager/ui-components": "^2.29.0", - "@scm-manager/ui-extensions": "^2.29.0", + "@scm-manager/ui-api": "^2.29.1", + "@scm-manager/ui-components": "^2.29.1", + "@scm-manager/ui-extensions": "^2.29.1", "classnames": "^2.2.5", "history": "^4.10.1", "i18next": "^19.6.0", @@ -30,7 +30,7 @@ }, "devDependencies": { "@scm-manager/jest-preset": "^2.13.0", - "@scm-manager/ui-tests": "^2.29.0", + "@scm-manager/ui-tests": "^2.29.1", "@types/classnames": "^2.2.9", "@types/enzyme": "^3.10.3", "@types/fetch-mock": "^7.3.1",