Skip to content

Commit 2e170b1

Browse files
Merge pull request #1979 from miguelpruivo/feature/path-traversal-vulnerability-in-file-name-handling
fix(android): mitigate CWE-22 path traversal vulnerability in FileUtils
2 parents cbe1fd4 + 7404fe1 commit 2e170b1

5 files changed

Lines changed: 49 additions & 63 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
.atom/
33
.idea/
44
.vscode/
5+
.project
6+
.classpath
7+
.settings/
58

69
.packages
710
.pub/

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
## 11.0.2
2+
### Android
3+
- Fixed a Path Traversal vulnerability (CWE-22) when resolving file paths from external content providers. [#1967](https://github.com/miguelpruivo/flutter_file_picker/issues/1967)
4+
25
### Linux
36
- Fixed "Cannot add to a fixed-length list" crash when opening or saving files with an initial directory on Linux. [#1976](https://github.com/miguelpruivo/flutter_file_picker/issues/1976)
47

android/.classpath

Lines changed: 0 additions & 6 deletions
This file was deleted.

android/.project

Lines changed: 0 additions & 23 deletions
This file was deleted.

android/src/main/kotlin/com/mr/flutter/plugin/filepicker/FileUtils.kt

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -63,48 +63,52 @@ object FileUtils {
6363

6464
val files = mutableListOf<FileInfo>()
6565

66-
when {
67-
data.clipData != null -> {
68-
for (i in 0 until data.clipData!!.itemCount) {
69-
var uri = data.clipData!!.getItemAt(i).uri
70-
uri = processUri(activity, uri, compressionQuality)
71-
addFile(activity, uri, loadDataToMemory, files)
66+
try {
67+
when {
68+
data.clipData != null -> {
69+
for (i in 0 until data.clipData!!.itemCount) {
70+
var uri = data.clipData!!.getItemAt(i).uri
71+
uri = processUri(activity, uri, compressionQuality)
72+
addFile(activity, uri, loadDataToMemory, files)
73+
}
74+
finishWithSuccess(files)
7275
}
73-
finishWithSuccess(files)
74-
}
7576

76-
data.data != null -> {
77-
var uri = processUri(activity, data.data!!, compressionQuality)
78-
79-
if (type == "dir") {
80-
uri = DocumentsContract.buildDocumentUriUsingTree(
81-
uri,
82-
DocumentsContract.getTreeDocumentId(uri)
83-
)
84-
val dirPath = getFullPathFromTreeUri(uri, activity)
85-
if (dirPath != null) {
86-
finishWithSuccess(dirPath)
77+
data.data != null -> {
78+
var uri = processUri(activity, data.data!!, compressionQuality)
79+
80+
if (type == "dir") {
81+
uri = DocumentsContract.buildDocumentUriUsingTree(
82+
uri,
83+
DocumentsContract.getTreeDocumentId(uri)
84+
)
85+
val dirPath = getFullPathFromTreeUri(uri, activity)
86+
if (dirPath != null) {
87+
finishWithSuccess(dirPath)
88+
} else {
89+
finishWithError("unknown_path", "Failed to retrieve directory path.")
90+
}
8791
} else {
88-
finishWithError("unknown_path", "Failed to retrieve directory path.")
92+
addFile(activity, uri, loadDataToMemory, files)
93+
handleFileResult(files)
8994
}
90-
} else {
91-
addFile(activity, uri, loadDataToMemory, files)
92-
handleFileResult(files)
9395
}
94-
}
9596

96-
data.extras?.containsKey("selectedItems") == true -> {
97-
val fileUris = getSelectedItems(data.extras!!)
98-
fileUris?.filterIsInstance<Uri>()?.forEach { uri ->
99-
addFile(activity, uri, loadDataToMemory, files)
97+
data.extras?.containsKey("selectedItems") == true -> {
98+
val fileUris = getSelectedItems(data.extras!!)
99+
fileUris?.filterIsInstance<Uri>()?.forEach { uri ->
100+
addFile(activity, uri, loadDataToMemory, files)
101+
}
102+
finishWithSuccess(files)
100103
}
101-
finishWithSuccess(files)
102-
}
103104

104-
else -> finishWithError(
105-
"unknown_activity",
106-
"Unknown activity error, please fill an issue."
107-
)
105+
else -> finishWithError(
106+
"unknown_activity",
107+
"Unknown activity error, please fill an issue."
108+
)
109+
}
110+
} catch (e: Exception) {
111+
finishWithError("file_picker_error", e.message ?: "Unknown error")
108112
}
109113
}
110114
}
@@ -536,6 +540,11 @@ object FileUtils {
536540
?: "unamed")
537541

538542
val file = File(path)
543+
544+
val safeDir = File(context.cacheDir.absolutePath + "/file_picker/").canonicalPath
545+
if (!file.canonicalPath.startsWith(safeDir)) {
546+
throw SecurityException("Path traversal detected. Escaping the intended cache directory is not allowed.")
547+
}
539548

540549
if (!file.exists()) {
541550
try {

0 commit comments

Comments
 (0)