npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

http-hpp

v1.0.0

Published

A lightweight, zero-dependency middleware to prevent HTTP Parameter Pollution (HPP) by collapsing repeated query/body parameters to their last occurrence. Designed to work with raw Node.js `http` as well as popular frameworks like Express, Fastify, and Ko

Readme

http-hpp

A lightweight, zero-dependency middleware to prevent HTTP Parameter Pollution (HPP) by collapsing repeated query/body parameters to their last occurrence. Designed to work with raw Node.js http as well as popular frameworks like Express, Fastify, and Koa without changing your existing logic.


Installation

npm install http-hpp
# or
yarn add http-hpp

Quickstart (raw Node.js)

import http from 'node:http';
import hpp from 'http-hpp';

const server = http.createServer((req, res) => {
  // wrap URL-encoded parser if needed, e.g. custom body collector
  hpp({ checkQuery: true, checkBody: false })(req, res, () => {
    // req.query is now de-duplicated
    console.log(req.query);
    res.end('OK');
  });
});

server.listen(3000);

API

import type { IncomingMessage, ServerResponse } from 'node:http';
import hpp, { HppOptions } from 'http-hpp';

hpp(options?: HppOptions): (req, res, next) => void

| Option | Type | Default | Description | | ------------- | ----------------------- | --------------------------------------- | ----------------------------------------------------------------------------- | | checkQuery | boolean | true | Enable HPP protection on req.query. | | checkBody | boolean | false | Enable HPP protection on req.body (form‑urlencoded only). | | accessQuery | <T>(req: T) => string | default: extracts req.url search part | Function to retrieve raw query string. | | accessBody | <T>(req: T) => string | default: extracts req.url search part | Function to retrieve raw body string (useful when framework buffers for you). |

The middleware will parse the raw string with new URLSearchParams(str) and assign the last value for each duplicate key. No arrays or extra storage are kept.


Examples

Express.js

Recommended

import express from 'express';
import hpp from 'http-hpp';

const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.use(hpp({ checkQuery: true, checkBody: false }));

app.post('/submit', (req, res) => {
  res.json({ query: req.query, body: req.body });
});

URL-encoded forms

import express from 'express';
import hpp from 'http-hpp';

const app = express();
app.use(express.urlencoded({ extended: false, limit: '100kb' }));
app.use(hpp({ checkQuery: true, checkBody: true }));

app.post('/submit', (req, res) => {
  // req.query and req.body have no duplicate arrays
  res.json({ query: req.query, body: req.body });
});

JSON bodies (no HPP needed)

import express from 'express';
import hpp from 'http-hpp';

const app = express();
app.use(express.json({ limit: '100kb' }));
// JSON parsers pick last‑wins for duplicate keys by default
app.use(hpp({ checkQuery: true, checkBody: false }));

Multipart forms (via multer)

import express from 'express';
import multer from 'multer';
import hpp from 'http-hpp';

const upload = multer();
const app = express();
app.use(hpp({ checkQuery: true, checkBody: false }));
app.post('/upload', upload.any(), (req, res) => {
  // req.files and req.body (parsed by multer) are safe
  res.send('Uploaded');
});

Fastify

import Fastify from 'fastify';
import hpp from 'http-hpp';

const app = Fastify();

app.addHook('preHandler', (req, reply, done) => {
  hpp({ checkQuery: true, checkBody: false })(req.raw, reply.raw, done);
});

app.get('/', (req, reply) => {
  reply.send({ query: req.query });
});

app.listen(3000);

Koa

import Koa from 'koa';
import koaBody from 'koa-body';
import hpp from 'http-hpp';

const app = new Koa();

app.use(async (ctx, next) => {
  await new Promise((resolve) => hpp({ checkQuery: true, checkBody: true })(ctx.req, ctx.res, resolve));
  await next();
});
app.use(koaBody({ multipart: true, urlencoded: true }));

app.use(ctx => {
  ctx.body = { query: ctx.req.query, body: ctx.req.body };
});

Request Types & Recommendations

| Type | Parser | HPP Options | Notes | | ----------------------------------- | ------------------------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------- | | application/json | express.json() / native JSON parser | { checkQuery: true } | JSON parsers already pick last value; no need for checkBody. | | application/x-www-form-urlencoded | express.urlencoded() / koa-body | { checkQuery: true, checkBody: true } | Enforce limit on body size to avoid DoS. | | multipart/form-data | multer / koa-body | { checkQuery: true } | Files handled by parser; HPP only applies to text fields in req.body. | | custom raw form | custom stream buffer + HPP | { checkQuery: true, checkBody: true, accessBody: yourAccessor } | Provide accessBody to read raw body string. |


Security & Best Practices

  1. Schema Validation: Always follow HPP with a strict schema validator (Zod, Joi, Yup, etc.) to enforce types, ranges, and required fields.
  2. Size Limits: For body parsing, set a maximum payload size (limit) to prevent memory exhaustion attacks.
  3. Content-Type Normalization: Use the built-in isFormUrlencoded to robustly detect form bodies (handles ; charset= suffixes).
  4. Parameter Whitelisting: Optionally filter req.query / req.body by an allow-list of known keys to guard against mass assignment.
  5. Rate Limiting & Logging: Pair with a rate-limiter or WAF and log suspicious parameter patterns for defense-in-depth.

Development & Testing

npm test       # runs your test suite
npm run build   # compile CJS & ESM bundles via TypeScript

License

MIT © Rayen Boussayed