If the file upload feature is implemented without proper folder restriction, it will result in an implicit trust violation within the server, as trusted files will be implicitly stored alongside third-party files that should be considered untrusted.
This can allow an attacker to disrupt the security of an internal server process or the running application.
After discovering this vulnerability, attackers may attempt to upload as many different file types as possible, such as javascript files, bash scripts, malware, or malicious configuration files targeting potential processes.
Below are some real-world scenarios that illustrate the potential impact of an attacker exploiting the vulnerability.
In the worst-case scenario, the attackers succeed in uploading a file recognized by in an internal tool, triggering code execution.
Depending on the attacker, code execution can be used with different intentions:
By repeatedly uploading large files, an attacker can consume excessive server resources, resulting in a denial of service.
If the component affected by this vulnerability is not a bottleneck that acts as a single point of failure (SPOF) within the application, the denial of service can only affect the attacker who caused it.
Even though a denial of service might have little direct impact, it can have secondary impact in architectures that use containers and container orchestrators. For example, it can cause unexpected container failures or overuse of resources.
In some cases, it is also possible to force the product to "fail open" when resources are exhausted, which means that some security features are disabled in an emergency.
These threats are particularly insidious if the attacked organization does not maintain a disaster recovery plan (DRP).
const Formidable = require('formidable');
const form = new Formidable(); // Noncompliant
form.uploadDir = "/tmp/";
form.keepExtensions = true;
const Formidable = require('formidable');
const form = new Formidable();
form.uploadDir = "/uploads/";
form.keepExtensions = false;
Create a special folder where untrusted data should be stored. This folder should be classified as untrusted and have the following characteristics:
This folder should not be located in /tmp, /var/tmp or in the Windows directory %TEMP%.
These folders
are usually "world-writable", can be manipulated, and can be accidentally deleted by the system.
Also, the original file names and extensions should be changed to controlled strings to prevent unwanted code from being executed based on the file names.
The following code sample is vulnerable because it implicitly uses /tmp or /var/tmp as upload directory.
const crypto = require('node:crypto');
const multer = require('multer');
let diskStorage = multer.diskStorage({
filename: (req, file, cb) => {
const buf = crypto.randomBytes(20);
cb(null, buf.toString('hex'))
}
}); // Noncompliant
let diskUpload = multer({
storage: diskStorage,
});
const multer = require('multer');
let diskStorage = multer.diskStorage({
filename: (req, file, cb) => {
const buf = crypto.randomBytes(20);
cb(null, buf.toString('hex'))
},
destination: (req, file, cb) => {
cb(null, '/uploads/')
}
});
let diskUpload = multer({
storage: diskStorage,
});
Create a special folder where untrusted data should be stored. This folder should be classified as untrusted and have the following characteristics:
This folder should not be located in /tmp, /var/tmp or in the Windows directory %TEMP%.
These folders
are usually "world-writable", can be manipulated, and can be accidentally deleted by the system.
Also, the original file names and extensions should be changed to controlled strings to prevent unwanted code from being executed based on the file names.