July 21, 2026
Session Hijacking & Injection
Not every security vulnerability requires advanced hacking skills.

By Shofa
8 min read
Sometimes, all it takes is an application that trusts user input more than it should.
That's exactly why SQL Injection (SQLi) remains one of the most common and impactful web security vulnerabilities, even after decades.
In this article, I break down:
- Privilege Escalation
- Session Hijacking
- SQL Injections & How to defend yourself
- Parameter Injection & How to defend yourself
- Other types of Injections
Whether you're learning web security or building web applications, understanding SQL Injection is fundamental.
Privilege Escalation
A Type of security Exploit where an attacker gains elevated access to resources that normally protected from an application or user.
How Privilege Escalation it works.
- Initial Access: The attacker gains limited access to the application or system.
- Discovering Weaknesses: The attacker identifies misconfigurations or vulnerabilities that can be exploited.
- Exploiting Vulnerabilities: They then use these weaknesses to gain higher privileges than originally intended.
- Gaining Control: With escalated privileges, they can access sensitive data or execute unauthorized actions.
This is called a bug-bounty hunting
Session Hijacking
Using a cookie value in an attempt to try to trick the server into thinking that you're someone that you're not.
Privilege Escalation is Broader Than You Think
- Usually, people think privilege escalation only means a regular user magically turning themselves into a "Super Admin." While that is true, it includes any unauthorized action.
- Vertical Escalation: Gaining higher privileges (e.g., User → Admin).
- Horizontal Escalation: Accessing resources belonging to another user with the same privilege level (e.g., User A accessing User B's private account details).
Attackers "Feel Around" Before Striking
- Security vulnerabilities are rarely exploited in a single, blind attempt. notes that attackers engage in reconnaissance:
- They analyze API responses for telltale leaks or patterns.
- They look for subtle misconfigurations.
- niche example of using CSS injection rather than JavaScript. An attacker might inject CSS that requests a background image from their own server only if a specific element (like
<div id="administrator">) exists on the page. If the attacker's server receives that image request, they successfully mapped out the page's structure and know an admin panel exists.
Session Hijacking vs. The Server's Trust
- If an attacker cannot guess a signed, random cookie through brute force, they will shift their strategy to stealing or tricking the system into giving them an existing valid cookie.
- If they can steal your active cookie, they don't need to break your password the server already trusts that cookie and will completely hand over control of your session to them.
Man-in-the-Middle (MitM) is Harder Now
A Man-in-the-Middle attack, where an attacker intercepts data moving over the network between the browser and the server.
- because of modern HTTPS (SSL/TLS), network traffic is encrypted.
- Even if someone intercepts the packet in transit, it just looks like gibberish unless the server is using a severely outdated, weak encryption algorithm that can be cracked. Because of this, attackers prefer targeting application-level flaws (like session hijacking) over network sniffing.
Injection Attacks
1) SQL Injection Attack
How it works
The root cause is failing to separate data from code. When user input gets dropped straight into a query through string interpolation (e.g. SELECT * FROM users WHERE email = "${input}"), the database can't tell the difference between a legitimate value and an instruction.
Bypassing login
Submitting a password like ' OR 1=1-- turns the intended query:
SELECT * FROM users WHERE email = 'someone@example.com' AND password = '' OR 1=1--'SELECT * FROM users WHERE email = 'someone@example.com' AND password = '' OR 1=1--'Since 1=1 is always true, the query succeeds and the attacker is logged in without ever knowing a real password and from there, gets a valid session token.
Extracting data with UNION SELECT
Once basic injection works, attackers escalate using UNION SELECT to pull columns from other tables through an endpoint that was only meant to return one type of data:
- Padding with
NULLlets the attacker match column counts on tables likeproducts. - This technique can expose plaintext passwords, credit card numbers, CVVs, and session IDs.
Stealing sessions
A UNION SELECT sessionId FROM sessions style query can dump every active session ID in the system. An attacker can then literally swap their own cookie for someone else's session and impersonate that user directly no password needed.
The fix: parameterized queries / prepared statements
Replace string interpolation with placeholders (?). The database compiles the query structure first, with no data in it, then binds user input separately as a literal value never as executable code.
app.get('/users', async (req, res) => {
const name = req.query.name;
try {
const users = await db.all(`SELECT * FROM users WHERE name = ?`, [name]);
res.json(users);
} catch (err) {
res.status(500).json({ error: err.message });
}
});app.get('/users', async (req, res) => {
const name = req.query.name;
try {
const users = await db.all(`SELECT * FROM users WHERE name = ?`, [name]);
res.json(users);
} catch (err) {
res.status(500).json({ error: err.message });
}
});Going a step further with prepared statements:
const usersQuery = await db.prepare(`SELECT * FROM users WHERE name = ?`);
const users = await usersQuery.all(name);const usersQuery = await db.prepare(`SELECT * FROM users WHERE name = ?`);
const users = await usersQuery.all(name);Even if someone passes in DROP TABLE Students; as the parameter, the database just searches for a row whose name is literally that string it never executes it.
Library safeguards: well-built DB drivers (e.g. sqlite3's db.all / db.get) often block multi-statement execution by design, which stops attackers from tacking destructive trailing commands onto an injected query.
2. Privilege Escalation (Mass Assignment)
How it works
This isn't about breaking a database it's about sneaking extra fields into a request that the backend blindly accepts.
Conceptually, it's the dangerous version of an innocent JS pattern:
Parameter Injection
You can do this in mongodb, couchdb, any nosql db because it uses json under the hood
const updated = {
...user,
admin: true,
};const updated = {
...user,
admin: true,
};In practice, an attacker can:
- Add a hidden form field:
<input type="hidden" name="admin" value="true" /> - Or just craft the request directly:
curl 'http://localhost:4007/profile' \
-X 'PATCH' \
-H 'Content-Type: application/json' \
-H 'Cookie: session=987292f04aaca60af0c3c56b93326da9' \
--data-raw '{"admin":true}'curl 'http://localhost:4007/profile' \
-X 'PATCH' \
-H 'Content-Type: application/json' \
-H 'Cookie: session=987292f04aaca60af0c3c56b93326da9' \
--data-raw '{"admin":true}'If the server does something like db.update(req.body) without checking which fields it's actually allowed to update, it'll happily promote the attacker to admin.
The fix
Explicitly destructure and whitelist only the fields you intend to accept:
const { name, email, password /* etc */ } = req.body;
const fields = toParamsAndValues({ name, email, password });const { name, email, password /* etc */ } = req.body;
const fields = toParamsAndValues({ name, email, password });3. Information Disclosure
Attackers rarely get an exploit right on the first attempt they spend most of their time mapping out the tech stack so they know what to target.
- Stack traces: raw error pages that leak file paths, framework names, or database type (e.g. SQLite vs. MongoDB) hand attackers a free blueprint for their next move.
- Framework headers: headers like
X-Powered-By: Expressbroadcast the stack to automated scanners hunting for known unpatched vulnerabilities in specific legacy versions (e.g. Rails 4.2).
The fix: disable or strip these identifying headers and generic error pages in production configs.
4. Beyond SQL: Other Injection Variants
The same core idea sliding input into a place it doesn't belong shows up in a few other forms:
Variant Where the payload lands SQL Injection Database query engine Command Injection OS shell (e.g. Bash) Remote Code Execution (RCE) The application runtime itself (e.g. JavaScript, Ruby)
5. Timing Attacks
Security operations (hashing, signature verification) cost CPU cycles and that cost is measurable, which means it can leak information even when the actual error message is identical.
Account enumeration example:
- A fake/random username → instant "user not found," ~5ms.
- A real username → server fetches the user, then runs the password through a heavy de-hashing function before failing, ~25ms.
- Even with an identical generic "Invalid credentials" message on both, that ~20ms gap reveals the account exists.
This is why response timing needs to be considered a side channel, not just an implementation detail.
6. Code Architecture as a Security Control
Scattering raw database queries across dozens of files makes a codebase very hard to patch quickly during an active incident.
- Abstraction as defense: centralizing data access into wrapper functions (e.g.
getUserFromSessionId()) means a bad or insecure query written by one engineer can be fixed in one place instead of audited across the entire codebase. - Why vulnerabilities really happen: rarely from negligence — usually from teams that are tired, multitasking, or rushing out an emergency fix at 2am.
7. Standing on the Shoulders of Giants
Abstractions, ORMs, and managed services (e.g. Stripe for payments) can occasionally have their own vulnerabilities but relying on battle-tested, widely-used tools is still much safer than rolling a custom driver or auth system from scratch.
When a major library or cloud provider has a critical flaw, the entire industry mobilizes to patch it. A homemade vulnerability, by contrast, gets discovered and fixed by exactly one team, working alone.
For example: Making payment by taking segments of card numbers and storing it somewhere and responsible for encryption
ORRRR
just use stripe 🙂
8. Logging and Alerting as a Primary Defense
Logging should be treated as a core security control, not a "fast follow" nice-to-have.
- Proactive value: logs capture failed attack attempts, revealing what attackers are probing for before they succeed.
- Reactive value: if a breach does happen, logs are the only reliable source of truth for figuring out exactly what was compromised and how to close the gap.
Other Types of Attacks And Injections
Command Injection
Vulnerability Overview:
- A type of security vulnerability where an attacker can execute arbitrary commands on the host operating system via a vulnerable application.
How it works:
- Target: Applications that pass unsafe user inputs directly to system shell commands.
- User Input: The application receives structural input parameters from an external user.
- Unsanitized Input: The user input is concatenated with a system command string in an unsafe way that allows additional system commands to be executed concurrently.
- Shell Execution: The combined command string is processed directly inside the system command shell execution thread.
- Malicious Payload: Attackers inject malicious commands, effectively piggybacking on legitimate system execution pathways.
- Insecure Code Implementation Example:
- A somewhat silly example that fits on a slide:
import { exec } from 'child_process';
app.get('/files', (req, res) => {
// Unsafe string interpolation mapping input data directly to a system shell call
const command = `ls ${req.body}`;
exec(command, (error, stdout, stderr) => {
if (error) {
return res.status(500).send(error.message);
}
if (stderr) {
res.status(500).send(stderr);
}
res.send(stdout);
});
});import { exec } from 'child_process';
app.get('/files', (req, res) => {
// Unsafe string interpolation mapping input data directly to a system shell call
const command = `ls ${req.body}`;
exec(command, (error, stdout, stderr) => {
if (error) {
return res.status(500).send(error.message);
}
if (stderr) {
res.status(500).send(stderr);
}
res.send(stdout);
});
});The Destructive Payload Example: test.txt; rm -rf /
Remediation & Mitigation Strategy:
- First: Just don't do it.
- Second: Use a language-native built-in Node module (e.g.,
fs) if you really need to perform file system operations. - Third: Fall back on
execFileif you really need to execute binary pathways with distinct parameter mapping. - Fourth: Rigorously sanitize parameters, implement strict execution allowlists, and enforce the Principle of Least Privilege if system commands are absolutely necessary.
File Upload Vulnerabilities
Vulnerability Definition:
- A class of security flaws that occur when a web application improperly or insecurely handles the uploading and storage of incoming user files.
- PSA: If you are uploading an image, It might not be an image, you have to make sure that the file is Media you are uploading.
- Make sure that payload not malicious, not contain malicious data pixels.
Remote Code Execution (RCE)
- Vulnerability Overview:
- This one kind of does what it says on the tin. Remote Code Execution (RCE) is a high-severity vulnerability that allows an attacker to execute arbitrary code blocks directly on a remote host system.
How it works:
- Injection: RCE typically occurs when the user input parameters are not properly sanitized or validated at the application boundary.
- Processing: The malicious input is parsed by the server through vulnerable pathways such as native
eval()functions, un-sanitized inputs passed to shell commands, or unsafe object deserialization mechanisms. - Execution: Malicious code executes inside the server environment context, providing the attacker with total runtime control over system resources.
Steps to Prevent Bad Things From Happening:
- Input Validation: Always validate and sanitize user inputs. Use strict data types and structural constraints.
- Don't Do Dangerous Stuff: Avoid using
eval(),Function(),exec(), and other potentially dangerous Node.js execution functions entirely. - Use Security Libraries: Utilize proven mitigation libraries such as
DOMPurifyfor sanitizing raw HTML content. Use sandboxed virtual environments (likeVM2) for isolating untrusted code paths. - Principle of Least Privilege: Run background services with minimal required system permissions. Never run your core application server as a
rootuser. - Update Your Stuff: Keep Node.js and all package dependencies up-to-date to quickly mitigate known zero-day vulnerabilities.
Further Reading
- MDN: SQL Injection
- PortSwigger: SQL Injection
- OWASP: SQL Injection
- OWASP: SQL Injection