Fix hoek prototype pollution in examples via @hapi/joi and @hapi/boom - #14
Open
ch-asimakopoulos wants to merge 1 commit into
Open
Fix hoek prototype pollution in examples via @hapi/joi and @hapi/boom#14ch-asimakopoulos wants to merge 1 commit into
ch-asimakopoulos wants to merge 1 commit into
Conversation
Chain 4 of 4. Resolves alert #2 (hoek, prototype pollution via the clone function) in examples/package-lock.json. boom ^7.3.0 -> @hapi/boom ^10.0.1 (hoek 6.1.2 -> @hapi/hoek 11.0.7) joi ^13.6.0 -> @hapi/joi ^15.1.1 (hoek 5.0.4 -> @hapi/hoek 8.5.1) Require paths updated in the four api actions that use them: create.js, delete.js, info.js and update.js. This is not optional cleanup. examples defines joi schemas that are consumed by lib's build.js and validate.js, so after chain 3 moved lib to @hapi/joi 15, leaving examples on joi 13 would hand a joi 13 schema object to @hapi/joi 15's validator - a cross-version mismatch. The two have to move together, which is why this is chained onto chain 3 rather than targeting master. examples/package-lock.json now reports zero advisories at every severity. That also clears the five highs flagged as out of scope back in the koa ReDoS PR, since they were all reached through joi 13 and boom 7. Verified end to end against the chain 3 lib, not just by audit: - /api/v1/discovery returns the correct schema-derived output, which exercises describe().children over @hapi/joi schemas defined here and read by lib. - The full client.js demo passes: create, list, update, list, delete, list all return the expected payloads. The lockfile is regenerated at lockfileVersion 3 to match what is on master. An earlier pass used --lockfile-version 1 out of habit from the other two projects, which would have silently reverted the v3 upgrade that came in with the qs bump. Pre-existing issue found while testing, not introduced here and not fixed here: validation failures and Boom.notFound both return HTTP 500 rather than 422/404. Boom sets its status on err.output.statusCode and leaves err.status and err.statusCode undefined, while Koa reads err.status/err.statusCode to build the response. examples/server.js installs no error-handling middleware to bridge the two, so every Boom error surfaces as a 500. Both boom 7 and @hapi/boom 10 have that same shape, so this migration is neutral with respect to the bug. Reproduced at 10c5d9d, Sokratis Vidros' last commit from 2021-05-29, on the original joi 13 / joi 14 / boom 7 / koa 2.5.2 dependency set: the same three requests return 500 there too, with the server log showing the Boom errors thrown correctly and their joi messages intact. The bug predates all of today's work and the 2022 node-fetch bump. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ch-asimakopoulos
marked this pull request as ready for review
July 31, 2026 14:54
Nikoklis
approved these changes
Jul 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Chain 4 of 4. Base:
security/lib-hoek(#12). Resolves alert #2 (hoek — prototype pollution via theclonefunction).^7.3.0^10.0.1^13.6.0^15.1.1Require paths updated in the four api actions that use them:
create.js,delete.js,info.js,update.js.Why this is chained, not independent
examples defines joi schemas that are consumed by lib's
build.js/validate.js. After chain 3 moved lib to @hapi/joi 15, leaving examples on joi 13 would hand a joi 13 schema object to @hapi/joi 15's validator — a cross-version mismatch. The two have to move together.Verification — end to end, not just audit
examples/package-lock.jsonnow reports zero advisories at every severity. That also clears the five highs I'd flagged as out-of-scope back in the koa ReDoS PR (Fix critical ReDoS in koa (examples) #1) — they were all reached through joi 13 and boom 7./api/v1/discoveryreturns correct schema-derived output, exercisingdescribe().childrenover @hapi/joi schemas defined here and read by lib.client.jsdemo passes against the chain 3 lib: create → list → update → list → delete → list, all expected payloads.--lockfile-version 1out of habit from the other two projects, which would have silently reverted the v3 upgrade that arrived with the qs bump.Validation failures and
Boom.notFound()both return HTTP 500 instead of 422/404.Cause: Boom sets its status on
err.output.statusCodeand leaveserr.status/err.statusCodeundefined, while Koa readserr.status/err.statusCodeto build the response.examples/server.jsinstalls no error-handling middleware to bridge them, so every Boom error surfaces as a 500.Identical shape, so this migration is neutral with respect to the bug.
Reproduced at
10c5d9d— Sokratis Vidros' last commit, 2021-05-29 — on the original joi 13 / joi 14 / boom 7 / koa 2.5.2 dependency set:The Boom errors are thrown correctly with their joi messages intact — only the HTTP status is lost. The bug predates all of today's work and the 2022 node-fetch bump.
The fix would be a couple of lines of Koa middleware in
examples/server.jstranslatingerr.isBoom→ctx.status = err.output.statusCode+ctx.body = err.output.payload. I left it out to keep this PR a pure dependency change — say the word and I'll add it here or as a separate PR.🤖 Generated with Claude Code