The npm pino logger is safe to run in production, and its main security concerns are operational rather than a string of open CVEs: how you redact secrets, how you load transports, and how much you trust the objects you log. Pino is a low-overhead JSON logger for Node.js maintained by Matteo Collina and a small team, and at the time of writing the latest line is 10.x with tens of millions of weekly downloads. Popularity does not equal safety, so this review walks through where pino npm usage actually goes wrong and how to lock it down.
Why pino is a reasonable default
Pino writes newline-delimited JSON and pushes formatting and transport work off the main event loop. That design choice matters for security as much as performance: because the hot path just serializes an object, there is very little parsing logic to get wrong. The package is actively maintained, ships a SECURITY.md with a documented threat model, and has hardened transport loading against prototype pollution in recent releases.
For most teams the honest summary is that pino is a well-run dependency. It is the kind of library you want in your tree because the maintainers treat security reports seriously and cut releases regularly. The risks below are about how you wire it up, not about the library being rotten.
The real risk: logging secrets and PII
The most common security incident involving any logger is not a code execution bug. It is a token, password, or authorization header written to disk or shipped to a log aggregator in plaintext. Pino gives you first-class redaction, and you should use it from day one:
const pino = require('pino')
const logger = pino({
redact: {
paths: [
'req.headers.authorization',
'req.headers.cookie',
'*.password',
'*.token',
'user.ssn'
],
censor: '[REDACTED]'
}
})
logger.info({ req }, 'incoming request')
Redaction paths use a fast-redact syntax, and wildcards like *.password catch the field wherever it appears one level deep. Treat this config as security-critical: review it whenever you add a field that could carry credentials, and prefer redacting broad categories over enumerating every leaf.
Never log entire request or response objects without thinking about what they contain. A logger.info(req) call that dumps raw headers is how bearer tokens end up in a searchable index that half the company can read.
Transports and the child-process boundary
Pino v7 and later run transports in a worker thread or child process. You point pino at a transport module by name, and it loads that module to process log lines. This is convenient, but it is also a place where a compromised or typosquatted transport package would run with your application's privileges.
const transport = pino.transport({
target: 'pino-pretty',
options: { colorize: true }
})
Two practical rules. First, pin transport packages the same way you pin any other dependency, and vet them before adding — pino-pretty is for development, not production. Second, keep the list of installed transports short. Recent pino releases hardened how transport targets are resolved to reduce prototype-pollution exposure, but the smaller your transport surface, the less there is to reason about. An SCA tool such as Safeguard can flag a transitive transport dependency that picks up a known advisory.
Prototype pollution and untrusted input
Prototype pollution is the vulnerability class most relevant to loggers, because loggers merge arbitrary objects. If an attacker controls a key like __proto__ in an object you log, a naive merge can corrupt Object.prototype. Pino's own internals have been hardened against this, but your application code sits upstream of pino.
The defensive move is to avoid passing attacker-controlled objects straight into the logger as the merge object. Log a curated set of fields instead:
// Risky: logs whatever keys the client sent
logger.info(req.body, 'signup')
// Better: log only what you mean to
logger.info({ email: req.body.email, plan: req.body.plan }, 'signup')
This habit also keeps your log volume predictable and stops accidental PII capture, so it pays off twice.
Keeping pino current
Because pino releases often, a version from two years ago misses both features and security hardening. Track the installed version against the published latest and upgrade on a cadence rather than waiting for an advisory. Log libraries rarely have dramatic breaking changes across minor versions, so the upgrade cost is usually small. If you run a monorepo, deduplicate pino so you are not shipping three copies at different patch levels.
Pair the upgrade discipline with dependency scanning. Most pino-related findings you will ever see come from transitive transport or formatting packages, not pino itself, which is exactly the category automated software composition analysis is built to surface.
A short production checklist
Configure redact before your first deploy and review it when models change. Keep transports minimal and pinned. Log curated field objects, never raw request bodies. Set an appropriate level so you are not writing debug detail in production. And upgrade pino on a schedule rather than reactively. None of these are exotic; they are the difference between a logger that quietly helps you and one that leaks credentials into a dashboard.
FAQ
Does npm pino have known critical vulnerabilities?
Pino has no standing critical CVEs of note in its core at the time of writing, and the maintainers have added prototype-pollution hardening and a documented threat model. The practical risks are misconfiguration (logging secrets) and untrusted transport packages, not a broken core.
How do I stop pino from logging passwords and tokens?
Use the redact option with paths like *.password, *.token, and req.headers.authorization, and set a censor value. Log explicit field objects rather than whole request bodies so sensitive keys never reach the serializer in the first place.
Is pino faster and safer than winston?
Pino is generally faster because it defers formatting and transport off the main thread and emits JSON directly. Neither is inherently "safer," but pino's smaller hot path and active maintenance make it a solid choice. Whichever you pick, redaction discipline matters more than the library.
Are pino transports a supply chain risk?
They can be, because a transport is a package pino loads to process your logs. Pin and vet transport packages, keep the list short, and scan your tree so a compromised or typosquatted transport is caught before it ships.