Headline
CVE-2023-35947: Merge pull request from GHSA-84mw-qh6q-v842 · gradle/gradle@1096b30
Gradle is a build tool with a focus on build automation and support for multi-language development. In affected versions when unpacking Tar archives, Gradle did not check that files could be written outside of the unpack location. This could lead to important files being overwritten anywhere the Gradle process has write permissions. For a build reading Tar entries from a Tar archive, this issue could allow Gradle to disclose information from sensitive files through an arbitrary file read. To exploit this behavior, an attacker needs to either control the source of an archive already used by the build or modify the build to interact with a malicious archive. It is unlikely that this would go unnoticed. A fix has been released in Gradle 7.6.2 and 8.2 to protect against this vulnerability. Starting from these versions, Gradle will refuse to handle Tar archives which contain path traversal elements in a Tar entry name. Users are advised to upgrade. There are no known workarounds for this vulnerability.
Impact
This is a path traversal vulnerability when Gradle deals with Tar archives, often referenced as TarSlip, a variant of ZipSlip.
- When unpacking Tar archives, Gradle did not check that files could be written outside of the unpack location. This could lead to important files being overwritten anywhere the Gradle process has write permissions.
- For a build reading Tar entries from a Tar archive, this issue could allow Gradle to disclose information from sensitive files through an arbitrary file read.
To exploit this behavior, an attacker needs to either control the source of an archive already used by the build or modify the build to interact with a malicious archive. It is unlikely that this would go unnoticed.
Gradle uses Tar archives for its Build Cache. These archives are safe when created by Gradle. But if an attacker had control of a remote build cache server, they could inject malicious build cache entries that leverage this vulnerability. This attack vector could also be exploited if a man-in-the-middle can be performed between the remote cache and the build.
Patches
A fix has been released in Gradle 7.6.2 and 8.2 to protect against this vulnerability. Starting from these versions, Gradle will refuse to handle Tar archives which contain path traversal elements in a Tar entry name.
It is recommended that users upgrade to a patched version.
Workarounds
There is no workaround.
- If your build deals with Tar archives that you do not fully trust, you need to inspect them to confirm they do not attempt to leverage this vulnerability.
- If you use the Gradle remote build cache, make sure only trusted parties have write access to it and that connections to the remote cache are properly secured.
References
@@ -0,0 +1,72 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the “License”);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an “AS IS” BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gradle.integtests
import org.apache.commons.compress.archivers.tar.TarFile
import org.apache.tools.tar.TarEntry
import org.apache.tools.tar.TarOutputStream
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.test.fixtures.file.TestFile
class TarSlipIntegrationTest extends AbstractIntegrationSpec {
private TestFile getEvilTar() {
file(“evil.tar.bz”)
}
def setup() {
evilTar.withOutputStream {
new TarOutputStream(it).withCloseable { TarOutputStream tos ->
TarEntry entry = new TarEntry(‘…/…/tmp/evil.sh’)
byte[] bytes = 'evil’.getBytes(‘utf-8’)
entry.size = bytes.length
tos.putNextEntry(entry)
tos.write(bytes)
tos.closeEntry()
}
}
}
def “evil tar has path traversal”() {
given:
def entryNames = new TarFile(evilTar).withCloseable {
it.entries.collect { it.name }
}
expect:
entryNames == [‘…/…/tmp/evil.sh’]
}
def “Copy task refuses to unpack evil tar”() {
executer.withStacktraceEnabled()
given:
buildFile << ‘’’
task copyEvilTar(type: Copy) {
from(tarTree(‘evil.tar.bz’))
into(‘.’)
}
‘’’
when:
fails ‘copyEvilTar’
then:
failureDescriptionContains “Execution failed for task ':copyEvilTar’”
failure.assertHasErrorOutput “’…/…/tmp/evil.sh’ is not a safe zip entry name”
}
}