[Android] Remote access: fix path traversal guard, streaming upload, and request handling in subtitle upload
Nicolas Pomepuy
git at videolan.org
Wed Sep 9 06:43:37 UTC 2026
vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Thu Sep 3 14:47:24 2026 +0200| [7dd999225c2389a1011e4d16fa99721a88b351bc] | committer: Duncan McNamara
Remote access: fix path traversal guard, streaming upload, and request handling in subtitle upload
> https://code.videolan.org/videolan/vlc-android/commit/7dd999225c2389a1011e4d16fa99721a88b351bc
---
.../vlc/remoteaccessserver/RemoteAccessRouting.kt | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/application/remote-access-server/src/main/java/org/videolan/vlc/remoteaccessserver/RemoteAccessRouting.kt b/application/remote-access-server/src/main/java/org/videolan/vlc/remoteaccessserver/RemoteAccessRouting.kt
index 3a53728f97..a4080f9aa3 100644
--- a/application/remote-access-server/src/main/java/org/videolan/vlc/remoteaccessserver/RemoteAccessRouting.kt
+++ b/application/remote-access-server/src/main/java/org/videolan/vlc/remoteaccessserver/RemoteAccessRouting.kt
@@ -258,7 +258,7 @@ fun Route.setupRouting(appContext: Context, scope: CoroutineScope) {
call.respond(HttpStatusCode.Forbidden)
return at post
}
- var fileName: String
+ var uploaded = false
val multipartData = call.receiveMultipart()
multipartData.forEachPart { part ->
@@ -266,14 +266,18 @@ fun Route.setupRouting(appContext: Context, scope: CoroutineScope) {
is PartData.FileItem -> {
val uploadDir = File("${AndroidDevices.MediaFolders.EXTERNAL_PUBLIC_DOWNLOAD_DIRECTORY_URI.path}/subtitles")
uploadDir.mkdirs()
- fileName = part.originalFileName ?: "subtitle.srt"
+ val fileName = part.originalFileName?.let { File(it).name } ?: "subtitle.srt"
val file = File(uploadDir, fileName)
- if (file.canonicalFile.parent?.startsWith(uploadDir.absolutePath) != true) {
+ if (!file.canonicalFile.canonicalPath.startsWith(uploadDir.canonicalPath + File.separator)) {
call.respond(HttpStatusCode.Unauthorized)
throw (IllegalStateException("${file.canonicalFile.parent} is not a valid path"))
}
- val fileBytes = part.streamProvider().readBytes()
- file.writeBytes(fileBytes)
+ part.streamProvider().use { input ->
+ file.outputStream().use { output ->
+ input.copyTo(output)
+ }
+ }
+ uploaded = true
val service = RemoteAccessServer.getInstance(appContext).service
if (service?.isPlaying == true) {
@@ -287,7 +291,11 @@ fun Route.setupRouting(appContext: Context, scope: CoroutineScope) {
else -> {}
}
}
- call.respond(HttpStatusCode.OK)
+ if (uploaded) {
+ call.respond(HttpStatusCode.OK)
+ } else {
+ call.respond(HttpStatusCode.BadRequest)
+ }
}
// Download a log file
get("/download-logfile") {
More information about the Android
mailing list