logo

Server side template injection - Typescript


Need

Prevention of server-side template injection attacks


Context

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

Description

Insecure Code Example

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

const app = express();

app.get('/template', (req, res) => {
  const template = req.query.template; // User-controlled input

  // Vulnerable code: directly injecting user input into the template
  const command = `echo ${template}`;

  exec(command, (error, stdout, stderr) => {
    if (error) {
      console.error(`Error executing command: ${error}`);
      return res.status(500).send('Internal Server Error');
    }

    res.send(stdout);
  });
});

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

The vulnerability in this code is a server-side template injection. It occurs because the user-controlled input from the `template` query parameter is directly injected into the command template without proper sanitization. In the vulnerable code, the user input is assigned to the `template` variable. Then, the `exec` function from the `child_process` module is used to execute a command. The command is constructed by directly injecting the user input into the template using string interpolation. This means that an attacker can manipulate the `template` query parameter to inject malicious code that will be executed on the server side. The impact of this vulnerability can be severe, as it allows the attacker to execute commands remotely, view sensitive files, obtain sensitive information, read system files, and cause strange behavior on the server. To fix this vulnerability, it is important to properly sanitize user-controlled inputs before using them in command templates. Additionally, it is recommended to use sandboxing techniques to limit the capabilities of the executed commands and mitigate the potential impact of an exploitation.

Steps

  1. Sanitize user-controlled input to prevent any malicious code injection.
  2. Use parameterized queries or prepared statements when constructing commands or queries that involve user-controlled input.
  3. Avoid directly injecting user input into command templates or queries.
  4. Implement proper input validation and filtering to ensure that only expected values are accepted.
  5. Encourage the use of sandboxing techniques to limit the impact of any potential code injection.
  6. Regularly update and patch dependencies to mitigate any known vulnerabilities.

Secure Code Example

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

const app = express();

app.get('/template', (req, res) => {
  const template = sanitizeInput(req.query.template); // Sanitize user-controlled input

  // Construct the command using parameterized queries or prepared statements
  const command = `echo ${template}`;

  exec(command, (error, stdout, stderr) => {
    if (error) {
      console.error(`Error executing command: ${error}`);
      return res.status(500).send('Internal Server Error');
    }

    res.send(stdout);
  });
});

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

function sanitizeInput(input: string): string {
  // Implement proper input validation and filtering
  // Sanitize the input to prevent any malicious code injection
  // You can use a library or custom logic to sanitize the input
  // Example: return input.replace(/[^\\w\\s]/gi, '');
  return input;
}

The fixed code addresses the vulnerability by implementing proper input sanitization and using parameterized queries or prepared statements to construct the command. Here's how the code works: 1. The code imports the necessary modules, including the `express` framework and the `exec` function from the `child_process` module. 2. An instance of the `express` application is created. 3. The code defines a route handler for the `/template` endpoint using the `app.get` method. This endpoint expects a query parameter called `template`. 4. The `sanitizeInput` function is called to sanitize the user-controlled input received in the `template` query parameter. This function should implement proper input validation and filtering to prevent any malicious code injection. In this example, it simply returns the input as is, but you should replace this with your own sanitization logic. 5. The command is constructed using the sanitized `template` value. It is important to note that this code is just an example and should not be used in production. In a real-world scenario, you should use parameterized queries or prepared statements to construct the command, which helps prevent code injection vulnerabilities. 6. The `exec` function is called with the constructed command. This function executes the command on the server-side. 7. In the callback function of the `exec` function, any errors that occur during command execution are logged to the console, and an appropriate error response is sent if an error occurs. 8. If the command executes successfully, the response containing the output of the command is sent back to the client. 9. The `app.listen` method is called to start the server on port 3000. Overall, the fixed code demonstrates the importance of properly sanitizing user-controlled inputs and using secure methods to construct commands to mitigate the risk of server-side template injection vulnerabilities.


References

  • 422 - Server side template injection

  • Last updated

    2023/09/18