1. Prototype pollution
JavaScript's prototype chain is a fundamental language feature that becomes a critical vulnerability when attacker-controlled data reaches a deep merge or clone operation. The exploit payload modifies Object.prototype, injecting properties onto every object created in the application process:
// Prototype pollution payload in a request body
{
"name": "test",
"__proto__": {
"isAdmin": true
}
} If your Express app uses a vulnerable deep merge utility (lodash versions before 4.17.12, hoek, or custom recursive merge functions) to merge request bodies into internal objects, any subsequent check like if (user.isAdmin) returns true for every user object, not just admins. We test every deep merge call path in your application.
2. MongoDB NoSQL injection
MongoDB's query language accepts JSON objects as operators. If your Express application passes user-controlled JSON directly into a Mongoose query without sanitization, an attacker can inject query operators to bypass authentication or extract unauthorized data:
// VULNERABLE Express route: passes req.body.email directly to Mongoose
app.post('/api/login', async (req, res) => {
const user = await User.findOne({ email: req.body.email, password: req.body.password });
// Attacker sends: { "email": {"$gt": ""}, "password": {"$gt": ""} }
// MongoDB evaluates: find users where email > "" AND password > "" (matches first user)
if (user) return res.json({ token: generateToken(user) });
}); 3. npm dependency audit and supply chain analysis
The average Node.js application has hundreds of transitive dependencies. We run npm audit as a baseline, then manually review high and critical findings in the context of your application to determine exploitability. Beyond known CVEs, we look for: packages that make outbound network connections at install time, packages with overly broad filesystem access, and packages that have been recently transferred to new maintainers (a common precursor to supply chain attacks).
4. JWT implementation flaws
Node.js JWT libraries have a history of implementation vulnerabilities. We test for the algorithm confusion attack (where a server configured for RS256 accepts a token signed with the public key using HS256), the none algorithm bypass (where the signature is stripped entirely), and token replay after logout (if tokens are not invalidated in a server-side blacklist on logout).
5. Event loop blocking and Denial of Service
Node.js runs on a single-threaded event loop. A single synchronous operation that blocks the loop (such as a ReDoS-vulnerable regular expression, a large JSON.parse() call, or a synchronous filesystem read) starves all concurrent requests. We test your API endpoints for input that triggers these blocking operations to confirm your application's resilience to targeted DoS attacks.
Prototype pollution bypassing role check in Express middleware
During a security assessment of a Nigerian B2B SaaS platform, we identified a custom deep merge function used to combine user preferences with application defaults in an Express middleware. By sending a POST body containing a __proto__ key, we set isAdmin: true on Object.prototype. Every subsequent request from our session passed the admin role check in the authorization middleware, giving us access to the complete admin API surface including user management, billing overrides, and audit log access. Fix priority: critical. Remediated by replacing the custom merge function with a prototype-safe alternative and validating the request body against a strict JSON schema before merging.
Running a Node.js backend in production in Nigeria? Book a security assessment.
Book a Node.js PentestFrequently asked questions
What is prototype pollution in Node.js and how is it exploited?
Prototype pollution occurs when attacker-controlled input modifies Object.prototype properties. In Express apps, this can manifest through deep merge utilities or query string parsers that allow keys like __proto__[isAdmin]=true to set properties on every object in the application, bypassing authorization checks that test for those properties.
How do you test for MongoDB injection in Node.js apps?
MongoDB injection occurs when query operators ($where, $gt, $regex) are passed as JSON keys in request bodies and reach Mongoose or the native MongoDB driver without sanitization. We test by submitting objects instead of strings in query parameters to check if the database executes the operator logic.
What npm packages are most often the source of security vulnerabilities?
The highest-risk categories are HTTP request libraries that follow redirects unsafely (SSRF), template engines that allow expression evaluation, YAML parsers with unsafe load options, and serialization libraries with known gadget chains. We audit your package.json and package-lock.json for known CVEs and unsafe transitive dependencies.
Related reading
Blog: Securing Node Express APIs · NestJS penetration testing · JWT implementation flaws
Services: Penetration testing · API security testing