All published images build on node:20-alpine:
| file |
line |
server/Dockerfile |
3 (builder), 33 (runtime) |
client/Dockerfile |
1 (base, inherited by deps/builder/runner) |
monitor-agent/Dockerfile |
1 |
Node.js 20 reached end-of-life at the end of April 2026, and the Docker Hub tag reflects that — it has not been rebuilt in nearly four months:
| tag |
last pushed |
node:20-alpine |
2026-04-15 |
node:22-alpine |
2026-07-29 |
node:24-alpine |
2026-08-03 |
(Checked 2026-08-11. The 20-alpine image currently contains Node v20.20.2 on Alpine 3.23.4.)
Why this matters beyond the version number
Because the tag is frozen, rebuilding the images cannot pick up fixes for anything already in that layer — the Node runtime and its bundled OpenSSL included. docker build --pull fetches the same April image every time.
That specifically penalises self-hosters who rebuild on a schedule to stay patched. We rebuilt v2.8.0 from source on 2026-08-11 — two weeks after the published image was built — and Trivy reported identical results:
| image |
published ghcr.io |
rebuilt from the same tag |
rybbit-backend:v2.8.0 |
107 fixed HIGH/CRITICAL |
107 |
rybbit-client:v2.8.0 |
25 fixed HIGH/CRITICAL |
25 |
Same CVEs, same packages. Reproducible with:
trivy image --scanners vuln --ignore-unfixed --severity HIGH,CRITICAL \
ghcr.io/rybbit-io/rybbit-backend:v2.8.0
Two of those findings are libcrypto3/libssl3 at 3.5.6-r0 (CVE-2026-45447, OpenSSL heap use-after-free in PKCS7_verify(), fixed in 3.5.7-r0) — inherited directly from the frozen base and unreachable by a rebuild. Moving to a maintained base tag resolves those on the next build.
Compatibility looks straightforward
- No
package.json in the repo declares an engines constraint, so nothing pins Node 20 explicitly.
next@16.2.6 requires node >=20.9.0 — an open lower bound. Node 22 and 24 both satisfy it.
fastify@5.8.5, react@19.2.4 and drizzle-orm@0.45.2 all support Node 22 and 24.
- The only workflows referencing
node-version: 20 are translate.yml and translate-docs.yml (docs translation), not application build or test — so CI coupling to Node 20 looks minimal.
Suggested fix
Bump the four FROM lines to node:22-alpine (Active LTS through April 2027) or node:24-alpine. Worth bumping @types/node alongside — it is pinned at ^20.14.8 in both server/package.json and client/package.json.
Happy to open the PR if that would help; it seemed better to check which major you would prefer before sending one.
All published images build on
node:20-alpine:server/Dockerfileclient/Dockerfiledeps/builder/runner)monitor-agent/DockerfileNode.js 20 reached end-of-life at the end of April 2026, and the Docker Hub tag reflects that — it has not been rebuilt in nearly four months:
node:20-alpinenode:22-alpinenode:24-alpine(Checked 2026-08-11. The
20-alpineimage currently contains Node v20.20.2 on Alpine 3.23.4.)Why this matters beyond the version number
Because the tag is frozen, rebuilding the images cannot pick up fixes for anything already in that layer — the Node runtime and its bundled OpenSSL included.
docker build --pullfetches the same April image every time.That specifically penalises self-hosters who rebuild on a schedule to stay patched. We rebuilt
v2.8.0from source on 2026-08-11 — two weeks after the published image was built — and Trivy reported identical results:ghcr.iorybbit-backend:v2.8.0rybbit-client:v2.8.0Same CVEs, same packages. Reproducible with:
Two of those findings are
libcrypto3/libssl3at3.5.6-r0(CVE-2026-45447, OpenSSL heap use-after-free inPKCS7_verify(), fixed in3.5.7-r0) — inherited directly from the frozen base and unreachable by a rebuild. Moving to a maintained base tag resolves those on the next build.Compatibility looks straightforward
package.jsonin the repo declares anenginesconstraint, so nothing pins Node 20 explicitly.next@16.2.6requiresnode >=20.9.0— an open lower bound. Node 22 and 24 both satisfy it.fastify@5.8.5,react@19.2.4anddrizzle-orm@0.45.2all support Node 22 and 24.node-version: 20aretranslate.ymlandtranslate-docs.yml(docs translation), not application build or test — so CI coupling to Node 20 looks minimal.Suggested fix
Bump the four
FROMlines tonode:22-alpine(Active LTS through April 2027) ornode:24-alpine. Worth bumping@types/nodealongside — it is pinned at^20.14.8in bothserver/package.jsonandclient/package.json.Happy to open the PR if that would help; it seemed better to check which major you would prefer before sending one.