NodeJS Express
Quick Fingerprinting
Useful Express indicators during recon:
X-Powered-By: Expressor stack traces mentioningexpress,body-parser,qs,cookie-parser,express-session, orfinalhandler- Cookies prefixed with
s:(signed cookie) orj:(JSON cookie) - Session cookies such as
connect.sid - Hidden form fields or query parameters such as
_method=PUT/_method=DELETE - Error pages leaking
Cannot GET /path,Cannot POST /path,Unexpected tokeninbody-parser, orURIErrorduring query parsing
When you confirm Express, focus on the middleware chain, because most interesting bugs come from parsers, proxy trust, session handling, and method-tunneling rather than from the framework core itself.
Cookie Signature
The cookie-monster tool automates testing candidate Express.js cookie secrets and re-signing cookie values once a secret is known.[3]
Express commonly exposes two useful cookie formats:
s:<value>.<sig>signed cookies handled bycookie-parserorexpress-sessionj:<json>JSON cookies that are automatically parsed bycookie-parser
If cookie-parser receives a signed cookie and its signature is invalid, the unsigned value becomes false rather than the attacker-supplied string. When the application supplies an array of secrets, verification tries each secret in order, so retained rotation keys continue to validate old signatures.[4]
Single cookie with a specific name
cookie-monster -c eyJmb28iOiJiYXIifQ== -s LVMVxSNPdU_G8S3mkjlShUD78s4 -n session
Custom wordlist
cookie-monster -c eyJmb28iOiJiYXIifQ== -s LVMVxSNPdU_G8S3mkjlShUD78s4 -w custom.lst
Test multiple cookies using batch mode
cookie-monster -b -f cookies.json
Test multiple cookies using batch mode with a custom wordlist
cookie-monster -b -f cookies.json -w custom.lst
Encode and sign a new cookie
If you know the secret you can sign the cookie.
cookie-monster -e -f new_cookie.json -k secret
Query String and URL-Encoded Parser Abuse
Express targets often become interesting when they parse attacker-controlled keys into nested objects.
req.querycan be configured with different parsers, includingqsexpress.urlencoded({ extended: true })usesqs-style parsing forapplication/x-www-form-urlencoded- Nested parsing unlocks object injection, mass assignment, NoSQL injection, and prototype pollution chains if the parsed object is merged into application state[2]
Practical payloads to try:
# Mass assignment style probe
curl 'https://target.example/profile?role=admin&isAdmin=true'
# Nested object / qs syntax
curl 'https://target.example/search?user[role]=admin&filters[name][$ne]=x'
# URL-encoded body against express.urlencoded({ extended: true })
curl -X POST 'https://target.example/api/update' -H 'Content-Type: application/x-www-form-urlencoded' --data 'profile[role]=admin&filters[$ne]=x'
If the app reflects or persists the resulting object, pivot into the dedicated pages for exploitation details:
Express Prototype Pollution Gadgets
Extra tests that are worth sending against Express specifically:
- Deep nesting to look for parser limits, timeouts, or 400/413 differences
- Duplicate keys to see whether the app keeps the first value, the last one, or an array
- Bracket syntax such as
a[b][c]=1, dotted syntax such asa.b=1, and__proto__/constructor[prototype]payloads
trust proxy Abuse
If the app uses app.set("trust proxy", true) or trusts too many hops, Express will derive security-relevant values from forwarding headers. If the reverse proxy does not overwrite them, a client can spoof them directly.[1]
That affects:
req.hostnameviaX-Forwarded-Hostreq.protocolviaX-Forwarded-Protoreq.ip/req.ipsviaX-Forwarded-For
This is useful for:
- Password reset poisoning and absolute URL poisoning
- Bypassing IP-based allowlists, rate limits, or audit trails
- Influencing
securecookie handling and HTTPS-only logic in apps that key offreq.protocol - Poisoning redirects or cacheable responses when the app templates absolute links with forwarded host/proto headers
POST /reset-password HTTP/1.1
Host: target.example
X-Forwarded-Host: attacker.example
X-Forwarded-Proto: https
X-Forwarded-For: 127.0.0.1
Content-Type: application/json
{"email":"victim@target.example"}
Check whether generated links, redirect locations, logs, or access-control decisions now use attacker-supplied values.
Related pages:
express-session Testing Notes
Common Express deployments use express-session, which signs the session identifier cookie but stores the real state server-side.
Useful checks:
- Session fixation: authenticate with a pre-login cookie and verify whether the SID stays the same after login
- Weak secret rotation: some deployments verify cookies with an array of old secrets, so previously valid signatures may continue to work
saveUninitialized: true: the application stores new but unmodified sessions, increasing anonymous session volume. It does not create fixation by itself, but it supplies pre-authentication SIDs that make a failure to rotate the SID easier to test.MemoryStoreis intentionally unsuitable for production: it leaks memory under many workloads, does not scale beyond one process, and loses sessions on restart.[5]
A practical fixation workflow:
- Obtain an anonymous session cookie from the target.
- Send that cookie to a victim or authenticate with it yourself.
- Check whether login binds the authenticated state to the existing SID.
- If it does, replay the same cookie in a separate browser session.
If the application does not rotate or regenerate the session after authentication, test whether authenticated state remains bound to a SID chosen or learned before login. req.session.regenerate() is the middleware’s built-in rotation primitive.[5]
Method Override Tunneling
Some Express apps use method-override to tunnel verbs that HTML forms cannot send natively. When enabled, always test whether you can smuggle dangerous methods through a route that the front-end, WAF, or CSRF logic assumed was only POST.
Typical probes:
POST /users/42 HTTP/1.1
Host: target.example
X-HTTP-Method-Override: DELETE
Content-Type: application/x-www-form-urlencoded
confirm=yes
POST /users/42?_method=PUT HTTP/1.1
Host: target.example
Content-Type: application/x-www-form-urlencoded
role=admin
Interesting impacts:
- Reaching hidden
PUT/PATCH/DELETEroutes through aPOST-only edge control - Bypassing route-specific middleware that only checks
req.method - Triggering state-changing handlers via CSRF when the application validates only the outer request method
The official method-override middleware checks only original POST requests by default (options.methods: ['POST']), so prioritize POST requests with header, body, and query-string override values.[6]
References
- [1] Express behind proxies - Express.js
- [2] Server-side prototype pollution: Black-box detection without the DoS - PortSwigger Research
- [3] DigitalInterruption/cookie-monster
- [4] Express.js - cookie-parser middleware
- [5] Express.js - express-session middleware
- [6] Express.js - method-override middleware