-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SECURITY] Fix Partial Path Traversal Vulnerability #10
[SECURITY] Fix Partial Path Traversal Vulnerability #10
Conversation
This fixes a partial path traversal vulnerability. Replaces `dir.getCanonicalPath().startsWith(parent.getCanonicalPath())`, which is vulnerable to partial path traversal attacks, with the more secure `dir.getCanonicalFile().toPath().startsWith(parent.getCanonicalFile().toPath())`. To demonstrate this vulnerability, consider `"/usr/outnot".startsWith("/usr/out")`. The check is bypassed although `/outnot` is not under the `/out` directory. It's important to understand that the terminating slash may be removed when using various `String` representations of the `File` object. For example, on Linux, `println(new File("/var"))` will print `/var`, but `println(new File("/var", "/")` will print `/var/`; however, `println(new File("/var", "/").getCanonicalPath())` will print `/var`. Weakness: CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') Severity: Medium CVSSS: 6.1 Detection: CodeQL & OpenRewrite (https://public.moderne.io/recipes/org.openrewrite.java.security.PartialPathTraversalVulnerability) Reported-by: Jonathan Leitschuh <[email protected]> Signed-off-by: Jonathan Leitschuh <[email protected]> Bug-tracker: JLLeitschuh/security-research#13 Co-authored-by: Moderne <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the PR and reporting this issue. We are taking path traversal vulnerabilities seriously and have already fixed SAST detected cases in the past. Its for instance mentioned in the release notes of 7.3.8.0 and 8.0.3.0.
We examined this PR and will indeed do a similar change to the code, although we do not deem this a security vulnerability worth creating a CVE. For the if-clause within updatedServerDirectoryPath
and isDirectoryEmpty
the parameter of the startsWith
method by default finishes with a path separator, which eliminates the exploitability. Only unsafe configuration overriding could lead to the partial path traversal vulnerability however just limited to sibling directories, which start with the same name as the last directory name of the configured export path. So for instance if a system administrator would override jahiaExportsDiskPath
to ${jahia.data.dir}/exports
(removing the trailing path separator), then it could happen that a malicious user (only authenticated and authorized users can execute these methods) could let the files be written to lets say ${jahia.data.dir}/exports-by-intruder
. It would lead to unexpected directories being created.
With the forthcoming security hardening change in our jahia-private repository (used for development), we are about to eliminate that possibility by using the here suggested getCanonicalFile().toPath()
.
@@ -2023,7 +2023,7 @@ private String validateZipName(String filename) throws java.io.IOException { | |||
String canonicalPath = new File(filename).getCanonicalPath(); | |||
String canonicalID = new File(".").getCanonicalPath(); | |||
|
|||
if (canonicalPath.startsWith(canonicalID)) { | |||
if (new File(filename).getCanonicalFile().toPath().startsWith(canonicalID)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This case here is a false positive as it is only for verifying file names in the zip and is not really extracting the files to the current working directory.
A security hardening fix has been commited yesterday inspired by this PR here, which IMHO can be closed now. |
Awesome! Thanks! |
Security Vulnerability Fix
This pull request fixes a partial-path traversal vulnerability due to an insufficient path traversal guard.
Even if you deem, as the maintainer of this project, this is not necessarily fixing a security vulnerability, it is still a valid security hardening.
Preamble
Impact
This issue allows a malicious actor to potentially break out of the expected directory. The impact is limited to sibling directories. For example,
userControlled.getCanonicalPath().startsWith("/usr/out")
will allow an attacker to access a directory with a name like/usr/outnot
.Why?
To demonstrate this vulnerability, consider
"/usr/outnot".startsWith("/usr/out")
.The check is bypassed although
/outnot
is not under the/out
directory.It's important to understand that the terminating slash may be removed when using various
String
representations of theFile
object.For example, on Linux,
println(new File("/var"))
will print/var
, butprintln(new File("/var", "/")
will print/var/
;however,
println(new File("/var", "/").getCanonicalPath())
will print/var
.The Fix
Comparing paths with the
java.nio.files.Path#startsWith
will adequately protect againts this vulnerability.For example:
file.getCanonicalFile().toPath().startsWith(BASE_DIRECTORY)
orfile.getCanonicalFile().toPath().startsWith(BASE_DIRECTORY_FILE.getCanonicalFile().toPath())
Other Examples
➡️ Vulnerability Disclosure ⬅️
👋 Vulnerability disclosure is a super important part of the vulnerability handling process and should not be skipped! This may be completely new to you, and that's okay, I'm here to assist!
First question, do we need to perform vulnerability disclosure? It depends!
For partial path traversal, consider if user-supplied input could ever flow to this logic. If user supplied input could reach this conditional, it's insufficient and, as such, most likely a vulnerability.
Vulnerability Disclosure How-To
You have a few options options to perform vulnerability disclosure. However, I'd like to suggest the following 2 options:
JLLeitschuh Disclosure
in the subject of your email so it is not missed.Detecting this and Future Vulnerabilities
You can automatically detect future vulnerabilities like this by enabling the free (for open-source) GitHub Action.
I'm not an employee of GitHub, I'm simply an open-source security researcher.
Source
This contribution was automatically generated with an OpenRewrite refactoring recipe, which was lovingly hand crafted to bring this security fix to your repository.
The source code that generated this PR can be found here:
PartialPathTraversalVulnerability
Why didn't you disclose privately (ie. coordinated disclosure)?
This PR was automatically generated, in-bulk, and sent to this project as well as many others, all at the same time.
This is technically what is called a "Full Disclosure" in vulnerability disclosure, and I agree it's less than ideal. If GitHub offered a way to create private pull requests to submit pull requests, I'd leverage it, but that infrastructure, sadly, doesn't exist yet.
The problem is that as an open source software security researcher, I (exactly like open source maintainers), I only have so much time in a day. I'm able to find vulnerabilities impacting hundreds, or sometimes thousands of open source projects with tools like GitHub Code Search and CodeQL. The problem is that my knowledge of vulnerabilities doesn't scale very well.
Individualized vulnerability disclosure takes time and care. It's a long and tedious process, and I have a significant amount of experience with it (I have over 50 CVEs to my name). Even tracking down the reporting channel (email, Jira, ect..) can take time and isn't automatable. Unfortunately, when facing prblems of this scale, individual reporting doesn't work well either.
Additionally, if I just spam out emails or issues, I'll just overwhelm already over taxed maintainers, I don't want to do this either.
By creating a pull request, I am aiming to provide maintainers something highly actionable to actually fix the identified vulnerability; a pull request.
There's a larger discussion on this topic that can be found here: JLLeitschuh/security-research#12
Opting-Out
If you'd like to opt-out of future automated security vulnerability fixes like this, please consider adding a file called
.github/GH-ROBOTS.txt
to your repository with the line:This bot will respect the ROBOTS.txt format for future contributions.
Alternatively, if this project is no longer actively maintained, consider archiving the repository.
CLA Requirements
This section is only relevant if your project requires contributors to sign a Contributor License Agreement (CLA) for external contributions.
It is unlikely that I'll be able to directly sign CLAs. However, all contributed commits are already automatically signed-off.
If signing your organization's CLA is a strict-requirement for merging this contribution, please feel free to close this PR.
Sponsorship & Support
This contribution is sponsored by HUMAN Security Inc. and the new Dan Kaminsky Fellowship, a fellowship created to celebrate Dan's memory and legacy by funding open-source work that makes the world a better (and more secure) place.
This PR was generated by Moderne, a free-for-open source SaaS offering that uses format-preserving AST transformations to fix bugs, standardize code style, apply best practices, migrate library versions, and fix common security vulnerabilities at scale.
Tracking
All PR's generated as part of this fix are tracked here: JLLeitschuh/security-research#13