Skip to main content

Excessive privileges - Temporary Files

Need

Properly restrict privileges and access modes for temporary files

Context

  • Usage of Scala for building scalable and functional applications
  • Usage of java.io.File for file handling operations in Java
  • Usage of play.api.libs.Files for file handling in Play Framework

Description

Non compliant code

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.

Steps

  • Avoid using hard-coded paths for temporary file creation.
  • Use a secure and unique directory for storing temporary files.
  • Set appropriate file permissions for the temporary files.
  • Delete the temporary files after they are no longer needed.
  • Implement proper error handling and logging for file operations.

Compliant code

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.

References