Skip to content

Fix hoek prototype pollution in lib via @hapi/joi and @hapi/boom - #12

Open
ch-asimakopoulos wants to merge 1 commit into
security/lib-high-depsfrom
security/lib-hoek
Open

Fix hoek prototype pollution in lib via @hapi/joi and @hapi/boom#12
ch-asimakopoulos wants to merge 1 commit into
security/lib-high-depsfrom
security/lib-hoek

Conversation

@ch-asimakopoulos

Copy link
Copy Markdown

Chain 3 of 4. Base: security/lib-high-deps (#11). Resolves alert SokratisVidros#33 (hoek — prototype pollution via the clone function).

hoek arrived by three paths, all now gone

boom 7.3.0                     → hoek 6.1.3
joi 14.3.1                     → hoek 6.1.3  (and via topo 3.0.3)
koa-joi-validate → joi 10.6.0  → hoek 4.3.1  (and via topo 2.1.1)
Dependency Before After hoek
boom ^7.3.0 @hapi/boom ^10.0.1 @hapi/hoek 11.0.7 ✓
joi ^14.3.1 @hapi/joi ^15.1.1 @hapi/hoek 8.5.1 ✓
koa-joi-validate ^0.5.1 removed

The unscoped boom/joi packages were deprecated in favour of the @hapi/* scope years ago and never received the hoek fix.

koa-joi-validate is removed as dead weight — nothing in lib requires it (grep confirms zero usage), and it pins joi at exactly 10.6.0, which dragged in the oldest hoek in the tree.

Why @hapi/joi 15 and not the current joi 18

Per your call on the trade-off. joi 16 removed Joi.validate(), removed schema.isJoi, and renamed describe().childrendescribe().keys — and this code depends on all three:

lib/validate.js:29   joi.validate(ctx.request.body, schema, opts)
lib/build.js:78      if (!joiSchema.isJoi)
lib/build.js:82      joiSchema.describe().children

@hapi/joi 15 is the last release keeping that surface, so clearing the advisory needs no code migration and — more importantly — doesn't break the joi schemas that consumers of apicco-lib write in their own api files, nor change the /discovery output. apicco-lib stays on 1.x.

⚠️ The trade-off, stated plainly: @hapi/joi 15 is itself end-of-life and will never receive future fixes. It is currently clean of advisories, but migrating to joi 18 with an apicco-lib 2.0.0 release remains the real long-term fix. Happy to open that as a separate non-chained PR whenever you want it.

Source changes are only the require paths

build.js, validate.js, build.test.js, validate.test.js. Every call site is untouched, and each was verified directly against @hapi/joi 15:

build.js:78    isJoi                    -> true
build.js:82    describe().children keys -> [ 'movie_id' ]
validate.js:29 Joi.validate             -> error.details[0].type = number.base, path = ["movie_id"]
validate.js    Boom.badData             -> 422
build.js       Boom.notFound            -> 404

Verification

  • hoek advisory cleared. The moderate joi link() RangeError is also gone — @hapi/joi 15 doesn't have link(). Only brace-expansion remains (no patched version at any release).
  • 9/9 tests pass, snapshot unchanged — including the specs that assert joi's error messages, which is the real check on behavioural compatibility.
  • Runtime tree diff shows only the intended swap: the boom, joi and koa-joi-validate subtrees replaced by @hapi/boom + @hapi/joi, with koa-router, koa-compose, lodash and require-directory untouched.

Why chain 4 is required

examples/ still uses joi@13/boom@7 and passes its schemas into this code. A joi 13 schema object handed to @hapi/joi 15's validator is a cross-version mismatch, so chain 4 migrates examples to match — it isn't optional cleanup.

🤖 Generated with Claude Code

Chain 3 of 4. Resolves alert SokratisVidros#33 (hoek, prototype pollution via the clone
function) in lib/package-lock.json.

hoek was not a direct dependency; it arrived by three paths, all of which
are now gone:

  boom 7.3.0                      -> hoek 6.1.3
  joi 14.3.1                      -> hoek 6.1.3 (and via topo 3.0.3)
  koa-joi-validate -> joi 10.6.0  -> hoek 4.3.1 (and via topo 2.1.1)

Changes:

  boom  ^7.3.0  -> @hapi/boom ^10.0.1  (-> @hapi/hoek 11.0.7)
  joi   ^14.3.1 -> @hapi/joi  ^15.1.1  (-> @hapi/hoek 8.5.1)
  koa-joi-validate ^0.5.1 -> removed

The unscoped boom and joi packages were deprecated in favour of the
@hapi/* scope years ago and never received the hoek fix. koa-joi-validate
is removed because it is dead weight: nothing in lib requires it, and it
pins joi at exactly 10.6.0, which dragged in the oldest hoek in the tree.

@hapi/joi 15 rather than the current joi 18 deliberately. joi 16 removed
Joi.validate(), removed schema.isJoi and renamed describe().children to
describe().keys - all three of which this code depends on:

  lib/validate.js:29  joi.validate(ctx.request.body, schema, opts)
  lib/build.js:78     if (!joiSchema.isJoi)
  lib/build.js:82     joiSchema.describe().children

@hapi/joi 15 is the last release keeping that surface, so clearing the
advisory needs no code migration and, more importantly, does not break
the schemas that consumers of apicco-lib write in their own api files, or
change the /discovery endpoint's output. apicco-lib stays on 1.x.

The trade-off is that @hapi/joi 15 is itself end-of-life and will not
receive future fixes. It is currently clean of advisories, but a later
migration to joi 18 with an apicco-lib 2.0.0 release is the real
long-term fix.

Source changes are only the require paths, in build.js, validate.js,
build.test.js and validate.test.js. Every call site is unchanged, and each
was verified directly against @hapi/joi 15: isJoi returns true,
describe().children still yields the key map, Joi.validate still returns
{ error, value } with error.details[].type and .path, and Boom.badData /
Boom.notFound still map to 422 / 404.

The hoek advisory is cleared, and so is the moderate joi link() RangeError,
which @hapi/joi 15 does not have. Only brace-expansion remains, and it has
no patched version at any release. 9/9 tests pass with the snapshot
unchanged, including the specs that assert joi's error messages.

A full runtime tree diff shows only the intended swap: the boom, joi and
koa-joi-validate subtrees are replaced by @hapi/boom and @hapi/joi, with
koa-router, koa-compose, lodash and require-directory untouched.

Note that examples/ still uses joi 13 and boom 7 and passes its schemas
into this code, so chain 4 migrates it to match.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants