Merge security/fastify-upgrade: fastify 5.12.7 advisories

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-22 23:06:25 +02:00
commit 25d43d1121
3 changed files with 80 additions and 16 deletions

View file

@ -22,7 +22,7 @@
"@gamecult/cultcache-ts": "file:vendor/CultLib/packages/cultcache-ts",
"cultmesh-ts": "file:vendor/CultLib/packages/cultmesh-ts",
"cultnet-ts": "file:vendor/CultLib/packages/cultnet-ts",
"fastify": "^5.8.5",
"fastify": "^5.12.6",
"pg": "^8.20.0",
"zod": "^3.25.76"
},

47
pnpm-lock.yaml generated
View file

@ -28,8 +28,8 @@ importers:
specifier: file:vendor/CultLib/packages/cultnet-ts
version: file:vendor/CultLib/packages/cultnet-ts
fastify:
specifier: ^5.8.5
version: 5.8.5
specifier: ^5.12.6
version: 5.12.7
pg:
specifier: ^8.20.0
version: 8.20.0
@ -532,17 +532,23 @@ packages:
fast-json-stringify@6.3.0:
resolution: {integrity: sha512-oRCntNDY/329HJPlmdNLIdogNtt6Vyjb1WuT01Soss3slIdyUp8kAcDU3saQTOquEK8KFVfwIIF7FebxUAu+yA==}
fast-json-stringify@7.1.3:
resolution: {integrity: sha512-5TDM1yOF/BDFOclKz2G6rs1RsIl5HXMCrg/npmdNIPNQCezshR5kIHjhwBNuMY67jhkTUAm9DguL8xkL/x0Wtw==}
fast-querystring@1.1.2:
resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==}
fast-uri@3.1.0:
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
fast-uri@4.2.3:
resolution: {integrity: sha512-I1PXwP5eAhlNlcdpjt9CgB59op2ZvZfxw+BkqGFVIUOgNpCVTcTqp3HhTX7brxj5vsip+nSY4nTvff+eIA76hg==}
fastify-plugin@5.1.0:
resolution: {integrity: sha512-FAIDA8eovSt5qcDgcBvDuX/v0Cjz0ohGhENZ/wpc3y+oZCY2afZ9Baqql3g/lC+OHRnciQol4ww7tuthOb9idw==}
fastify@5.8.5:
resolution: {integrity: sha512-Yqptv59pQzPgQUSIm87hMqHJmdkb1+GPxdE6vW6FRyVE9G86mt7rOghitiU4JHRaTyDUk9pfeKmDeu70lAwM4Q==}
fastify@5.12.7:
resolution: {integrity: sha512-v4pEPsTRPuqlDIYiQFB+BHjVN4SdHX9u0ABk0ZDUKbbdY1vsNryUd1j4Z+jQEZajvYIVk047Kimva9/AJ79GYw==}
fastq@1.20.1:
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
@ -556,8 +562,8 @@ packages:
picomatch:
optional: true
find-my-way@9.5.0:
resolution: {integrity: sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ==}
find-my-way@9.10.0:
resolution: {integrity: sha512-eru+uCPQ2g+nLBkf84MHP/KyNNMar0BDy0j+i8Fb72GF9/YHBZ58q7FODUtfVV7XU9nfRUHXSmaM8NmZcIbZ4Q==}
engines: {node: '>=20'}
fsevents@2.3.3:
@ -853,8 +859,8 @@ packages:
process-warning@4.0.1:
resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==}
process-warning@5.0.0:
resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==}
process-warning@5.1.1:
resolution: {integrity: sha512-oCkNVj4OKnKEcocVBcDfiIugN1/cE6rgfT3nCtzeqZPA8+rIxMaQ0xXzIkGP8Gj2qUaP1UR7uhJ1VD8lUCpzCg==}
quick-format-unescaped@4.0.4:
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
@ -1475,15 +1481,26 @@ snapshots:
json-schema-ref-resolver: 3.0.0
rfdc: 1.4.1
fast-json-stringify@7.1.3:
dependencies:
'@fastify/merge-json-schemas': 0.2.1
ajv: 8.20.0
ajv-formats: 3.0.1(ajv@8.20.0)
fast-uri: 4.2.3
json-schema-ref-resolver: 3.0.0
rfdc: 1.4.1
fast-querystring@1.1.2:
dependencies:
fast-decode-uri-component: 1.0.1
fast-uri@3.1.0: {}
fast-uri@4.2.3: {}
fastify-plugin@5.1.0: {}
fastify@5.8.5:
fastify@5.12.7:
dependencies:
'@fastify/ajv-compiler': 4.0.5
'@fastify/error': 4.2.0
@ -1491,11 +1508,11 @@ snapshots:
'@fastify/proxy-addr': 5.1.0
abstract-logging: 2.0.1
avvio: 9.2.0
fast-json-stringify: 6.3.0
find-my-way: 9.5.0
fast-json-stringify: 7.1.3
find-my-way: 9.10.0
light-my-request: 6.6.0
pino: 10.3.1
process-warning: 5.0.0
process-warning: 5.1.1
rfdc: 1.4.1
secure-json-parse: 4.1.0
semver: 7.7.4
@ -1509,7 +1526,7 @@ snapshots:
optionalDependencies:
picomatch: 4.0.4
find-my-way@9.5.0:
find-my-way@9.10.0:
dependencies:
fast-deep-equal: 3.1.3
fast-querystring: 1.1.2
@ -1733,7 +1750,7 @@ snapshots:
on-exit-leak-free: 2.1.2
pino-abstract-transport: 3.0.0
pino-std-serializers: 7.1.0
process-warning: 5.0.0
process-warning: 5.1.1
quick-format-unescaped: 4.0.4
real-require: 0.2.0
safe-stable-stringify: 2.5.0
@ -1758,7 +1775,7 @@ snapshots:
process-warning@4.0.1: {}
process-warning@5.0.0: {}
process-warning@5.1.1: {}
quick-format-unescaped@4.0.4: {}

View file

@ -0,0 +1,47 @@
import Fastify, { type FastifyReply, type FastifyRequest } from "fastify";
import { afterEach, describe, expect, it } from "vitest";
// GHSA-p68q-wchp-6fh7 (fastify < 5.12.2): a malformed request target under one
// plugin prefix, with a method that has no route in the main router, was
// dispatched to the not-found handler of a sibling plugin, skipping that
// handler's preHandler. This pins the framework fix; it is not about a Heimdall
// route.
describe("fastify malformed URL under sibling not-found handlers", () => {
const apps: Array<ReturnType<typeof Fastify>> = [];
afterEach(async () => {
await Promise.all(apps.splice(0).map((app) => app.close()));
});
async function build() {
const app = Fastify();
apps.push(app);
await app.register(async (pub) => {
pub.get("/ping", async () => "pong");
}, { prefix: "/public" });
await app.register(async (priv) => {
priv.setNotFoundHandler(
{
preHandler: async (request: FastifyRequest, reply: FastifyReply) => {
if (!request.headers.authorization) return reply.code(401).send({ error: "auth" });
},
},
(_request: FastifyRequest, reply: FastifyReply) => reply.code(404).send({ secret: "PRIVATE-TENANT-DATA" }),
);
priv.get("/x", async () => "x");
}, { prefix: "/private" });
return app;
}
it("fails closed with 400 and never reaches another prefix's not-found handler", async () => {
const app = await build();
const response = await app.inject({ method: "DELETE", url: "/public/%zz" });
expect(response.body).not.toContain("PRIVATE-TENANT-DATA");
expect(response.statusCode).toBe(400);
});
it("still runs the authenticated not-found preHandler for a well-formed URL", async () => {
const app = await build();
const response = await app.inject({ method: "DELETE", url: "/private/nothing" });
expect(response.statusCode).toBe(401);
});
});