Superior HTTP Parameter Pollution protection middleware with modern TypeScript, robust sanitizer, and extensive tests.
npm install hppxreq.query, req.body, and req.params, blocks prototype-pollution keys, supports nested whitelists, multiple merge strategies, and plays nicely with stacked middlewares.
keepFirst, keepLast (default), combine
__proto__, prototype, constructor
queryPolluted, bodyPolluted, paramsPolluted)
maxDepth, maxKeys, maxArrayLength, maxKeyLength
sanitize)
bash
npm install hppx
`
Usage
$3
`typescript
import express from "express";
import hppx from "hppx";
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(
hppx({
whitelist: ["tags", "user.roles", "ids"],
mergeStrategy: "keepLast",
sources: ["query", "body"],
}),
);
app.get("/search", (req, res) => {
res.json({
query: req.query,
queryPolluted: req.queryPolluted ?? {},
body: req.body ?? {},
bodyPolluted: req.bodyPolluted ?? {},
});
});
`
$3
`javascript
const express = require("express");
const hppx = require("hppx");
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(
hppx({
whitelist: ["tags", "user.roles", "ids"],
mergeStrategy: "keepLast",
sources: ["query", "body"],
}),
);
app.get("/search", (req, res) => {
res.json({
query: req.query,
queryPolluted: req.queryPolluted ?? {},
body: req.body ?? {},
bodyPolluted: req.bodyPolluted ?? {},
});
});
`
API
$3
Creates an Express-compatible middleware. Applies sanitization to each selected source and exposes *.Polluted objects.
#### Key Options
Whitelist & Strategy:
- whitelist?: string[] ā keys allowed as arrays; supports dot-notation; leaf matches too
- mergeStrategy?: 'keepFirst'|'keepLast'|'combine' ā how to reduce arrays when not whitelisted
Source Selection:
- sources?: Array<'query'|'body'|'params'> ā which request parts to sanitize (default: all)
- checkBodyContentType?: 'urlencoded'|'any'|'none' ā when to process req.body (default: urlencoded)
- excludePaths?: string[] ā exclude specific paths (supports * wildcard suffix)
Security Limits (DoS Protection):
- maxDepth?: number ā maximum object nesting depth (default: 20, max: 100)
- maxKeys?: number ā maximum number of keys to process (default: 5000)
- maxArrayLength?: number ā maximum array length (default: 1000)
- maxKeyLength?: number ā maximum key string length (default: 200, max: 1000)
Additional Options:
- trimValues?: boolean ā trim string values (default: false)
- preserveNull?: boolean ā preserve null values (default: true)
- strict?: boolean ā if pollution detected, immediately respond with 400 error
- onPollutionDetected?: (req, info) => void ā callback on pollution detection
- logger?: (err: Error | string) => void ā custom logger for errors and pollution warnings
- logPollution?: boolean ā enable automatic logging when pollution is detected (default: true)
$3
Sanitize an arbitrary object using the same rules as the middleware. Useful for manual usage.
Advanced usage
$3
`typescript
app.use(hppx({ strict: true }));
`
$3
`typescript
app.use(express.json());
app.use(hppx({ checkBodyContentType: "any" }));
`
$3
`typescript
app.use(hppx({ excludePaths: ["/public", "/assets*"] }));
`
$3
`typescript
// Use your application's logger
app.use(
hppx({
logger: (message) => {
if (typeof message === "string") {
myLogger.warn(message); // Pollution warnings
} else {
myLogger.error(message); // Errors
}
},
}),
);
// Disable automatic pollution logging
app.use(hppx({ logPollution: false }));
`
$3
`typescript
import { sanitize } from "hppx";
const clean = sanitize(payload, {
whitelist: ["user.tags"],
mergeStrategy: "keepFirst",
});
`
CommonJS:
`javascript
const { sanitize } = require("hppx");
const clean = sanitize(payload, {
whitelist: ["user.tags"],
mergeStrategy: "keepFirst",
});
`
Security Best Practices
$3
Always combine HPP protection with additional input validation:
- Use schema validation libraries (e.g., Joi, Yup, Zod)
- Validate data types and ranges after sanitization
- Never trust user input, even after sanitization
$3
For production environments, consider these settings:
`ts
app.use(
hppx({
maxDepth: 10, // Lower depth for typical use cases
maxKeys: 1000, // Reasonable limit for most requests
maxArrayLength: 100, // Prevent large array attacks
maxKeyLength: 100, // Shorter keys for most applications
strict: true, // Return 400 on pollution attempts
onPollutionDetected: (req, info) => {
// Log security events for monitoring
securityLogger.warn("HPP detected", {
ip: req.ip,
path: req.path,
pollutedKeys: info.pollutedKeys,
});
},
}),
);
`
$3
- Parameter pollution: Duplicate parameters causing unexpected behavior
- Prototype pollution: Attacks via __proto__, constructor, prototype
- DoS attacks: Excessive nesting, too many keys, huge arrays
- Null-byte injection: Keys containing null characters (\u0000`)