safe-inflight
v2.0.0
Published
Security fork of [email protected] with the CWE-772 memory leak fixed: queued callbacks are no longer dropped when one throws, and the in-flight entry is always released. Version 2.x deliberately sits ABOVE upstream's highest published version (1.0.6) so SCA
Maintainers
Readme
safe-inflight
Security fork of [email protected] with the
CWE-772 resource-leak fixed. Drop-in replacement via npm alias.
Why this exists
inflight is flagged for a memory leak ("some resources are not freed correctly
after being used", CWE-772). Upstream is deprecated and will not be fixed —
there is no patched release at any version, so no version bump or override can
resolve the finding. inflight is still pulled in transitively by glob@7 and
glob@8, which are in turn required by a lot of build tooling.
This fork fixes the defect and publishes under a different package name so the dependency can be redirected with an npm alias.
What was actually wrong
Upstream's resolver dispatched queued callbacks in a bare loop:
try {
for (var i = 0; i < len; i++) {
cbs[i].apply(null, args) // <-- a throw here aborts the whole loop
}
} finally {
...
}If any callback threw, the loop aborted and every remaining callback was silently dropped. Whatever those callbacks were responsible for closing or releasing — file handles, sockets, pending state — was therefore never released. That is the leak.
To be precise about scope, since it matters for review:
- Upstream did delete the registry entry on the throwing path. That part was not broken, and this fork does not claim otherwise.
- The demonstrable defect is the dropped callbacks.
test.jscontains two regression tests that fail against upstream[email protected]and pass here.
The fix
Every queued callback is invoked even if an earlier one throws. Failures are collected and rethrown after the queue drains, so error propagation is preserved:
- one failure rethrows that error unchanged;
- multiple failures throw an aggregate
Errorcarrying them on.errors.
Two pieces of defensive hardening are also included. These are belt-and-braces rather than fixes for demonstrated upstream failures:
- the drained callback array is emptied so closures become collectable immediately instead of living as long as a retained resolver;
- invoking a resolver after its queue already drained is a no-op instead of a
TypeErroroncbs.length.
Everything else — the wrappy wrapper, once-ified resolvers, the de-zalgo
process.nextTick re-dispatch for callbacks registered mid-drain, and the
null return for a key already in flight — is byte-for-byte upstream behaviour.
The one intentional behavioural difference
Upstream stopped at the first throwing callback; this fork runs all of them. Upstream's own source comment conceded this was arbitrary:
XXX It's somewhat ambiguous whether a new callback added in this pass should be queued for later execution if something in the list of callbacks throws, or if it should just be discarded.
Running every callback is the safer choice, and it is the whole point of the fix.
Versioning
Upstream's highest published version is 1.0.6 and the advisory covers all
versions. This fork starts at 2.0.0, deliberately above upstream, so that
SCA scanners which resolve npm aliases by node_modules path rather than by
resolved package name do not match the advisory range.
Usage
Redirect inflight everywhere in the tree via overrides in package.json:
{
"overrides": {
"inflight": "npm:[email protected]"
}
}After npm install, the lockfile entry resolves to safe-inflight, and
node_modules/**/inflight contains this package. Consumers keep doing
require('inflight') unchanged.
The API is identical to [email protected]:
var inflight = require('inflight')
function req (key, callback) {
callback = inflight(key, callback)
if (!callback) return // already in flight for this key
setTimeout(function () {
callback(null, key) // fires every callback queued for `key`
}, 100)
}Tests
npm test11 tests, including the two CWE-772 regressions. To confirm they genuinely
catch the upstream defect, point test.js at [email protected] and it fails 2
of 11.
License
ISC, same as upstream. Original copyright Isaac Z. Schlueter; fork
modifications copyright Millennium bcp. See LICENSE.
