HPP - HTTP Parameter Pollution Protection
`hpp` is an Express middleware designed to protect web applications from HTTP Parameter Pollution (HPP) attacks. HPP exploits how web frameworks handle multiple parameters with the same name in a single request. This library, currently at version 0.2.3, mitigates this by identifying array parameters in `req.query` and `req.body` (specifically for `application/x-www-form-urlencoded` requests) and assigning only the *last* parameter value to the main `req.query` or `req.body` object. The original, potentially polluted array of values is moved to `req.queryPolluted` or `req.bodyPolluted` for inspection. This ensures that downstream middleware or route handlers only receive a single, consistent value for each parameter, preventing attackers from bypassing input validation or causing unexpected application behavior. It's a low-level security utility, likely in maintenance mode given its stable version and specific scope, and integrates directly into the Express middleware chain.
Common errors
-
TypeError: app.use() requires a middleware function but got a undefined
cause The `hpp` module was not correctly imported or required, resulting in `hpp()` being called on an undefined value.fixEnsure you have `const hpp = require('hpp');` or `import hpp from 'hpp';` at the top of your file and `hpp` is correctly installed via `npm install hpp`. -
Parameters in req.body are not being filtered by HPP.
cause The `hpp` middleware is placed *before* `body-parser` middleware, or the request body is not `application/x-www-form-urlencoded`.fixVerify that `app.use(hpp())` is called after `app.use(bodyParser.urlencoded({ extended: true }))`. Also, confirm the client is sending `Content-Type: application/x-www-form-urlencoded` for the body to be processed by `hpp`.
Warnings
- gotcha The `hpp` middleware must be placed *after* any `body-parser` middleware in your Express application's chain to correctly process `req.body` parameters. If placed before, `req.body` will not be parsed yet, and `hpp` will not be able to mitigate pollution for POST/PUT requests.
- gotcha `hpp`'s protection for `req.body` parameters is only effective for `application/x-www-form-urlencoded` request bodies. It does not parse or protect `application/json` or `multipart/form-data` bodies. For JSON bodies, ensure your JSON parser and subsequent logic handle potential array inputs appropriately.
- gotcha `hpp` does not completely remove polluted parameters; it moves them to `req.queryPolluted` and `req.bodyPolluted`. While `req.query` and `req.body` receive the last safe value, applications should be aware that the original polluted values are still accessible on the `req` object. Sensitive information should not be processed directly from `req.queryPolluted` or `req.bodyPolluted` without strict validation.
Install
-
npm install hpp -
yarn add hpp -
pnpm add hpp
Imports
- hpp
import hpp from 'hpp';
const hpp = require('hpp'); - hpp
import { hpp } from 'hpp';import hpp from 'hpp';
- Request
import { Request } from 'express';
Quickstart
import express from 'express';
import hpp from 'hpp';
import bodyParser from 'body-parser';
const app = express();
const port = 3000;
// Make sure body-parser is used BEFORE hpp to allow hpp to process req.body.
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json()); // Optional, but common. HPP only checks urlencoded for body.
// Add the HPP middleware. This secures all routes by default.
// It will move polluted parameters from req.query and req.body to req.queryPolluted and req.bodyPolluted.
app.use(hpp());
// Example route to demonstrate HPP's effect
app.get('/search', (req: express.Request, res: express.Response) => {
console.log('Original req.query (after HPP):', req.query);
console.log('Polluted req.query (if any):', req.queryPolluted);
res.send(`Search results for: ${req.query.q || 'N/A'}. Polluted: ${JSON.stringify(req.queryPolluted || {})}`);
});
app.post('/submit', (req: express.Request, res: express.Response) => {
console.log('Original req.body (after HPP):', req.body);
console.log('Polluted req.body (if any):', req.bodyPolluted);
res.send(`Submitted: ${req.body.item || 'N/A'}. Polluted: ${JSON.stringify(req.bodyPolluted || {})}`);
});
// Whitelisting example (as per README suggestion)
// If a specific route requires array parameters, apply HPP with a whitelist option.
app.get('/multi-select', hpp({ whitelist: ['selectedIds'] }), (req: express.Request, res: express.Response) => {
// For /multi-select?selectedIds=1&selectedIds=2
// req.query.selectedIds will be ['1', '2'] because of the whitelist here.
console.log('Multi-select req.query:', req.query);
res.send(`Selected IDs: ${req.query.selectedIds}`);
});
app.listen(port, () => {
console.log(`Server listening at http://localhost:${port}`);
console.log(`Test with:`);
console.log(`GET http://localhost:${port}/search?q=item1&q=item2`);
console.log(`POST http://localhost:${port}/submit -d "item=val1&item=val2" -H "Content-Type: application/x-www-form-urlencoded"`);
console.log(`GET http://localhost:${port}/multi-select?selectedIds=100&selectedIds=200`);
});