Skip to main content

Server-Side JavaScript Injection SSJI

Server-Side JavaScript Injection, also called SSJI, is a security vulnerability where user-provided input gets executed as JavaScript code on the server.

This is dangerous because if attacker-controlled code runs on the server, it may interact with the server environment, file system, or other internal resources.

What It Is

SSJI happens when the server evaluates user input as JavaScript code.

Simple meaning:

User sends input

Server treats input like JavaScript code

Code gets executed on the server

Attacker may run malicious logic

The main problem is not just bad input. The problem is that the server executes that input.

Why It Matters

SSJI can be very dangerous because server-side code usually has more power than browser-side code.

If attacker-controlled JavaScript runs on the server, it may lead to:

RiskMeaning
Arbitrary code executionAttacker may execute unwanted JavaScript
File system accessMalicious code may interact with server files
Server compromiseThe host system may be affected
Data leakageInternal data may be exposed
Global exceptionsBad execution flow can crash or damage server behavior

In simple terms:

Client-side code affects the browser.
Server-side injected code can affect the actual server.

Core Flow

A typical SSJI flow looks like this:

Attacker sends malicious JavaScript input

Server accepts the input

Server uses eval/new Function/timer execution/deserialization unsafely

Input becomes executable code

Attacker gains control over server-side behavior

Main Causes

The PDF highlights these major causes of SSJI:

CauseMeaning
Inadequate input validationUser input is accepted without proper checks
Direct execution of user-provided codeServer runs code received from the user
Dangerous JavaScript functionsFunctions like eval() and Function() can execute strings as code
Unsafe timer usagesetTimeout() or setInterval() can cause issues if misused
Insecure deserializationSerialized data is processed without proper validation

Dangerous JavaScript Functions

Some JavaScript functions can be exploited when they are used with user-controlled input.

The PDF mentions these functions:

eval()
setTimeout()
setInterval()
Function()
new Function()

These functions become risky when user input is passed into them.

Risky example:

const userCode = req.body.code;

// Dangerous: directly executing user-provided code
eval(userCode);

Another risky example:

const userCode = req.body.code;

// Dangerous: creating a function from user input
const fn = new Function(userCode);
fn();

Safer idea:

const userCode = req.body.code;

// Do not directly execute user-provided code
// Validate input and use predefined actions instead

Mental model:

User input should be data, not executable code.

Inadequate Input Validation

Inadequate input validation means the server accepts input without checking whether it is safe and expected.

Risky flow:

Request body contains input

Server accepts it directly

Input reaches sensitive logic

Attack becomes possible

Safer approach:

const userInput = req.body.input;

if (!isValidInput(userInput)) {
return res.status(400).send("Invalid input");
}

function isValidInput(input) {
const regex = /^[a-zA-Z0-9\s]+$/;
return regex.test(input);
}

This example allows only letters, numbers, and spaces.

Important rule:

Always validate user input before using it in server-side logic.

Direct Execution of User-Provided Code

Direct execution of user-provided code is one of the clearest SSJI risks.

Risky example:

const userCode = req.body.code;

// Issue: directly executing user-provided JavaScript code
eval(userCode);

Safer approach:

const userCode = req.body.code;

// Mitigation:
// Do not directly execute user-provided JavaScript code

Instead of executing user input, use predefined operations.

Example:

const allowedActions = {
uppercase: (value) => value.toUpperCase(),
lowercase: (value) => value.toLowerCase(),
};

function runAction(action, value) {
if (!allowedActions[action]) {
throw new Error("Invalid action");
}

return allowedActions[action](value);
}

Flow:

User selects action

Server checks allowed action list

Server runs predefined safe function

Using Dangerous Functions

Using new Function() with user-provided code is dangerous because it creates executable JavaScript from a string.

Risky example:

const userCode = req.body.code;

// Issue: using new Function with user input
const func = new Function(userCode);
func();

Safer approach:

const userCode = req.body.code;

// Avoid using dangerous functions with user-provided code

Functions like eval() and new Function() should not be used with untrusted input.

Simple mental model:

If a function turns a string into code,
do not feed it user input.

setTimeout and setInterval Risks

The PDF mentions that issues in setTimeout() or setInterval() can lead to global exceptions.

If global exceptions are not handled properly, they can cause serious damage.

Risky idea:

const userCode = req.body.code;

// Dangerous if user-controlled code is passed
setTimeout(userCode, 1000);

Safer idea:

setTimeout(() => {
// Run only predefined safe logic
runScheduledTask();
}, 1000);

Important rule:

Timers should run predefined functions,
not user-provided code.

Insecure Deserialization

Deserialization means converting serialized data back into an object or usable data format.

The PDF explains that sometimes JSON data comes in and the application deserializes it without proper checking.

Risky flow:

User sends serialized data

Server deserializes it directly

Unexpected or malicious structure is processed

Security issue may occur

Risky example:

const serializedData = req.body.data;

// Issue: insecure deserialization
const deserializedObject = deserialize(serializedData);

Safer approach:

const serializedData = req.body.data;

try {
const deserializedObject = JSON.parse(serializedData);

if (!isValidData(deserializedObject)) {
return res.status(400).send("Invalid data");
}

// Process the validated object
} catch (error) {
return res.status(500).send("Error while deserializing data");
}

function isValidData(data) {
// Add validation logic for expected structure
return data && typeof data === "object";
}

Important rule:

Do not deserialize and trust data immediately.
Parse it, validate it, then process it.

Other Injection and Parsing Risks

The PDF also shows examples around unsafe input being used in different contexts.

SQL or NoSQL Injection Style Risk

Unsafe input may be directly inserted into a query.

Risky pattern:

const userInput = '{"username":"admin","password":{"$ne":null}}';

const query = `SELECT * FROM users WHERE data = '${userInput}'`;

Problem:

User input is directly mixed with query logic.

Resource Exhaustion

Large input can create resource exhaustion, similar to a denial-of-service style issue.

Example:

const userInput = '{"data":"' + "A".repeat(1000000) + '"}';
const data = JSON.parse(userInput);

Problem:

Huge input can consume server memory or processing power.

Deserialization Vulnerability

Example pattern:

const userInput = '{"type":"Buffer","data":[72,101,108,108,111]}';

const buffer = JSON.parse(userInput);
const text = Buffer.from(buffer).toString();

Problem:

Parsed data should still be validated before being trusted.

Prevention Summary

To reduce SSJI risk:

Do not execute user input

Avoid dangerous functions

Validate input strictly

Deserialize safely

Handle global exceptions

Limit input size

Basic Checklist

Use this checklist to prevent SSJI:

  • Do not pass user input into eval().
  • Do not pass user input into new Function().
  • Do not execute user-provided JavaScript code directly.
  • Avoid using string-based logic in setTimeout() and setInterval().
  • Validate all request body input.
  • Use whitelist-style validation for allowed characters, actions, or values.
  • Parse JSON safely using try/catch.
  • Validate deserialized data before processing it.
  • Check input size to avoid resource exhaustion.
  • Avoid directly mixing user input into query logic.
  • Handle global exceptions properly.
  • Treat user input as data, not code.

Interview Style Answer

Server-Side JavaScript Injection, or SSJI, is a vulnerability where user-provided input is executed as JavaScript on the server. This can happen when dangerous functions like eval(), Function(), setTimeout(), or setInterval() are used with untrusted input.

It is dangerous because the injected code runs in the context of the server and may interact with the file system or internal server resources. Common causes include inadequate input validation, direct execution of user-provided code, use of dangerous functions, and insecure deserialization.

To prevent SSJI, we should never execute user input as code, avoid dangerous functions with untrusted data, validate input strictly, use predefined allowed actions, safely parse and validate JSON, limit input size, and handle global exceptions properly.

One-Line Summary

SSJI happens when user input is treated as executable JavaScript on the server.

Final Mental Model

User Input + Server-Side Code Execution = SSJI Risk

Remember it like this:

Input should be data, not code.
Validate before use.
Never eval user input.
Never create functions from user input.
Deserialize safely.
Handle exceptions properly.