Lack of data validation - Non Sanitized Variables - TypeScript

Lack of data validation - Non Sanitized Variables - TypeScript

Need

Implementation of proper input validation and sanitization

Context

  • Usage of Node.js v14.0.0 for server-side JavaScript development
  • Usage of Express for building web applications and APIs
  • Usage of child_process for executing external commands and processes

Description

Non compliant code

        import express from 'express';
import { exec } from 'child_process';

const app = express();
const port = 3000;

app.get('/execute', (req, res) => {
  const command = req.query.command;
  exec(command, (error, stdout, stderr) => {
    if (error) {
      console.error(`Error executing command: ${error}`);
      return res.status(500).send('Error executing command');
    }
    console.log(`Command executed successfully: ${stdout}`);
    res.send(stdout);
  });
});

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});
        
        

The vulnerability in this code is a lack of data validation, specifically the lack of sanitization of the command variable obtained from the req.query object.

In the code, the command variable is directly passed to the exec() function from the child_process module without any validation or sanitization. This means that any value provided as the command parameter can be executed as a system command on the server.

This can be exploited by an attacker to execute unauthorized scripts or commands on the server. For example, an attacker could pass a malicious command that deletes files or compromises the server's security.

To fix this vulnerability, it is recommended to implement proper data validation and sanitization. One approach is to use whitelists or identifiers that are transformed into static inputs to the exec() function. This ensures that only allowed commands can be executed and prevents any unauthorized or malicious commands from being executed.

Steps

  • Validate and sanitize the input received from the user.
  • Use a whitelist or identifier to ensure that only allowed commands can be executed.
  • Transform the input into a static value before passing it to the 'exec' function.
  • Handle any potential errors that may occur during command execution.
  • Avoid displaying sensitive information in error messages.
  • Consider implementing authentication and authorization mechanisms to restrict access to the '/execute' endpoint.

Compliant code

        import express from 'express';
import { exec } from 'child_process';

const app = express();
const port = 3000;

app.get('/execute', (req, res) => {
  const allowedCommands = ['command1', 'command2', 'command3'];
  const command = req.query.command;

  if (!allowedCommands.includes(command)) {
    console.error(`Invalid command: ${command}`);
    return res.status(400).send('Invalid command');
  }

  const sanitizedCommand = transformToStaticValue(command);

  exec(sanitizedCommand, (error, stdout, stderr) => {
    if (error) {
      console.error(`Error executing command: ${error}`);
      return res.status(500).send('Error executing command');
    }
    console.log(`Command executed successfully: ${stdout}`);
    res.send(stdout);
  });
});

function transformToStaticValue(input: string): string {
  // Perform any necessary transformations on the input
  // to ensure it becomes a static value
  return input;
}

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});
        
        

The fixed code addresses the vulnerability by implementing data validation and sanitization techniques. Here's an explanation of the changes made:

1. The code imports the necessary modules, including the exec function from the child_process module, which is used to execute system commands.

2. The code creates an instance of the Express application and sets the port to 3000.

3. The code defines a route handler for the /execute endpoint using the app.get method. This endpoint expects a query parameter called command.

4. The code defines an array called allowedCommands that contains the list of commands that are allowed to be executed.

5. The code retrieves the value of the command query parameter from the request.

6. The code checks if the command value is included in the allowedCommands array using the includes method. If the command is not allowed, an error message is logged, and a response with a status code of 400 and an error message is sent back to the client.

7. The code calls the transformToStaticValue function, passing the command value as an argument, to sanitize and transform the input into a static value.

8. The code uses the exec function to execute the sanitized command. It provides a callback function that handles the result of the command execution.

9. Inside the callback function, if an error occurs during command execution, an error message is logged, and a response with a status code of 500 and an error message is sent back to the client.

10. If the command execution is successful, the standard output of the command is logged, and the response with the command output is sent back to the client.

11. The code defines the transformToStaticValue function, which takes an input string and performs any necessary transformations to ensure it becomes a static value. In this example, the function is left empty, but you can add any necessary logic to sanitize and transform the input.

12. The code starts the Express application and listens on the specified port. A message is logged to indicate that the server is running.

By implementing data validation, using a whitelist approach, and sanitizing the input before executing the command, the fixed code mitigates the vulnerability and ensures that only allowed commands can be executed.

References