Properly restrict privileges and access modes for temporary files
import java.io.File
import play.api.libs.Files
def createTempFile() = Action(parse.temporaryFile) { request =>
val tempFile = request.body
val file = new File("/tmp/" + tempFile.uuid)
tempFile.moveTo(file)
Ok("File has been created at: " + file.getAbsolutePath)
}
This Scala function
createTempFile()
in the Play Framework application is vulnerable due to excessive privileges in temporary file creation.
The
createTempFile()
function handles a request to create a temporary file. It uses the
parse.temporaryFile
parser to handle the file in the request body. The temporary file is then moved to a new location, "/tmp/" + tempFile.uuid, using the
moveTo()
method.
The vulnerability here is that the temporary file is created without properly restricting its privileges or access modes. Any user or process on the system can read, write, or delete this file because it's created in the "/tmp/" directory with default permissions. This could allow an attacker to manipulate the file in ways that the developer did not intend, potentially leading to information disclosure, data corruption, or even remote code execution if the file is used in an insecure manner later in the application.
In addition, the file name is generated using the
uuid
of the temporary file, which might be predictable or controllable by an attacker, leading to further potential for attacks such as the symbolic link following vulnerability, where an attacker could trick the application into overwriting or reading a file that they should not have access to.
The code should be fixed to properly manage the access modes and privileges of the temporary file during its creation.
import java.io.File
import java.nio.file.{Files, Path, Paths, StandardOpenOption}
import play.api.mvc.{Action, Controller, MultipartFormData}
class TempFileController extends Controller {
def createTempFile() = Action(parse.temporaryFile) { request =>
val tempFile = request.body
val tempDir = Files.createTempDirectory("secureTemp")
val file = Paths.get(tempDir.toString, tempFile.uuid).toFile
tempFile.moveTo(file, replace = true)
file.setReadable(false, false)
file.setWritable(false, false)
file.setExecutable(false, false)
file.setReadable(true, true)
file.setWritable(true, true)
Ok("File has been created at: " + file.getAbsolutePath)
if(file.exists()) file.delete()
}
}
The updated code creates a secure temporary directory using
Files.createTempDirectory("secureTemp")
. This ensures that the directory is unique and not hard-coded, reducing the risk of an attacker predicting the directory's location.
The temporary file is then moved to this secure directory with
tempFile.moveTo(file, replace = true)
. The
replace = true
option ensures that if a file with the same name already exists in the directory, it will be replaced, preventing potential conflicts or errors.
Next, the code sets the file permissions using
file.setReadable()
,
file.setWritable()
, and
file.setExecutable()
. The first argument to these methods is a boolean indicating whether to allow the operation (read, write, execute), and the second argument is another boolean indicating whether to apply this permission to all users (
false
) or only the owner (
true
). In this case, all permissions are denied to all users, then read and write permissions are granted only to the owner. This restricts access to the file, reducing the risk of unauthorized access or modification.
Finally, after the file's location is returned in the response, the file is deleted with
if(file.exists()) file.delete()
. This ensures that the temporary file is not left lingering after it is no longer needed, reducing the risk of it being discovered and exploited by an attacker.
Error handling and logging are not shown in this code snippet, but should be implemented in a real-world application to catch and record any issues that occur during file operations.