最近 TiDB、PHP 都曝出了大漏洞,这两天刚部署 Misskey,也碰上了 😅
我的 Misskey 应用版本为 2026.10.0,容器内 Node.js 为 26.4.0,重新拉取官方镜像后版本未变。
在原镜像上替换 Node.js,重新打包并部署后,运行时升级至 26.12.1,Misskey 应用版本保持不变。
安全更新
Node.js 官方公告 列出了 10 月 21 日的安全更新,最高严重级别为 High。其中包括 DNS 名称含 NUL 字符时被截断、TLS 主机名校验绕过,以及可能导致远程代码执行的 Brotli 解码器越界写入等问题。公告对应的修复版本是:
发布分支 本次修复版本 22.x 22.23.4 24.x 24.22.1 26.x 26.12.1
容器使用 26.x,本次升级至同一大版本的 26.12.1。后续升级应重新核对安全公告。
检查容器和上游镜像
Docker 部署的 Misskey 使用镜像内的 Node.js。升级宿主机上的 Node.js,或者单纯重启容器,都不会替换镜像中的运行时。
下面的命令在部署主机执行。示例沿用 /opt/misskey、Compose 服务名 web,以及容器名 misskey-web-1;其他部署需要替换为自己的名称。
1
2
3
4
5
6
7
cd /opt/misskey
docker compose ps
docker compose exec -T web node --version
docker inspect misskey-web-1 \
--format 'IMAGE={{.Config.Image}} IMAGE_ID={{.Image}}'
检查结果:
1
2
3
Misskey: 2026.10.0
镜像: misskey/misskey:2026.10.0
Node.js: v26.4.0
随后检查上游镜像是否已经更新:
1
2
3
4
5
6
docker pull misskey/misskey:2026.10.0
docker run --rm --network none --entrypoint node \
misskey/misskey:2026.10.0 --version
docker buildx imagetools inspect misskey/misskey:latest
截至 2026 年 10 月 23 日,官方 2026.10.0 镜像内的 Node.js 仍为 26.4.0,latest 指向同一个镜像索引。上游尚未更新运行时,重新拉取镜像无法完成升级。
保留原镜像,构建修补版本
这次环境是 Linux x86_64,原镜像基于 Debian,使用 glibc。下面下载的 linux-x64 官方二进制适用于这一环境;ARM 或 Alpine/musl 镜像不能直接照搬。
留下配置和镜像回退点
1
2
3
4
5
6
7
8
9
10
11
set -euo pipefail
cd /opt/misskey
STAMP = $( date -u +%Y%m%dT%H%M%SZ)
BACKUP = "/opt/misskey/node-security-backup- $STAMP "
mkdir -m 700 " $BACKUP "
cp -a compose.yaml " $BACKUP /compose.yaml"
BASE_IMAGE = $( docker inspect misskey-web-1 --format '{{.Image}}' )
docker tag " $BASE_IMAGE " "local/misskey:before-node-security- $STAMP "
docker tag " $BASE_IMAGE " local/misskey:base-node26.4.0
按正在运行的容器镜像 ID 保存本地标签,固定构建基底和回退镜像。此处仅备份 Compose 配置并保留镜像;升级 Misskey 应用或变更数据库前,还需备份数据库和上传文件。
下载并校验官方 Node.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mkdir -p node-security/node-dist
cd node-security/node-dist
curl -fSLO --retry 3 \
https://nodejs.org/dist/v26.12.1/node-v26.12.1-linux-x64.tar.xz
curl -fSLO --retry 3 \
https://nodejs.org/dist/v26.12.1/SHASUMS256.txt
grep ' node-v26.12.1-linux-x64.tar.xz$' SHASUMS256.txt \
| sha256sum -c -
tar -xJf node-v26.12.1-linux-x64.tar.xz --strip-components= 1 \
node-v26.12.1-linux-x64/bin/node
./bin/node --version
预期看到校验 OK 和 v26.12.1。这里使用 HTTPS 下载并核对官方 SHA-256 清单,没有额外进行发布签名验证。
只替换运行时
在 /opt/misskey/node-security/Dockerfile 写入:
1
2
FROM local/misskey:base-node26.4.0
COPY node-dist/bin/node /usr/local/bin/node
然后构建并单独检查新镜像:
1
2
3
4
5
6
7
8
cd /opt/misskey
docker build --pull= false \
-t local/misskey:2026.10.0-node26.12.1 ./node-security
docker run --rm --network none --entrypoint node \
local/misskey:2026.10.0-node26.12.1 \
-p 'JSON.stringify({node:process.version,modules:process.versions.modules})'
输出为:
新旧运行时的模块 ABI 均为 147,依赖兼容性仍需启动服务验证。
本次仅替换 Node.js 可执行文件,未重新编译 Misskey,也未升级 npm、pnpm 或开发头文件。后续编译原生模块或升级 Misskey 时,需重新检查构建链和基础镜像。
修改 Compose,替换 web 容器
原来的 web 镜像配置是:
1
2
3
services :
web :
image : misskey/misskey:2026.10.0
将 web 中这一项替换为下面三项,其余端口、挂载、网络和环境变量保留 :
1
2
3
4
5
services :
web :
image : local/misskey:2026.10.0-node26.12.1
pull_policy : never
build : ./node-security
pull_policy: never 让部署使用本地修补镜像;build 保留重建入口。随后检查配置并替换 web 服务:
1
2
3
4
5
cd /opt/misskey
docker compose config --quiet
docker compose up -d --no-deps --pull never \
--wait --wait-timeout 180 web
这次只重新创建了 web 容器,PostgreSQL 和 Redis 没有重启。web 切换期间会有短暂中断。
原镜像的启动命令包含数据库迁移和应用启动。虽然此次没有改变 Misskey 应用版本,仍要观察启动是否完成,不能看到容器进入 running 就认定升级成功。
验证正在运行的服务
容器和镜像是否一致
1
2
3
4
5
docker inspect misskey-web-1 \
--format 'IMAGE={{.Config.Image}} IMAGE_ID={{.Image}} STATUS={{.State.Status}} HEALTH={{.State.Health.Status}}'
docker image inspect local/misskey:2026.10.0-node26.12.1 \
--format '{{.Id}}'
容器镜像 ID 与本地修补镜像一致,状态为 running,健康检查为 healthy。
运行时和应用版本是否符合预期
1
2
3
4
5
docker compose exec -T web node -p \
'JSON.stringify({node:process.version,openssl:process.versions.openssl,modules:process.versions.modules})'
docker compose exec -T web node -p \
'require("/misskey/package.json").version'
实测输出:
1
2
{"node":"v26.12.1","openssl":"3.5.9","modules":"147"}
2026.10.0
页面、API 和日志是否正常
下面域名是占位示例,执行前换成自己的实例地址:
1
2
3
4
5
6
7
8
curl --fail --silent --output /dev/null \
--write-out 'HTTP %{http_code}\n' https://social.example.com/
curl --fail --silent --request POST \
--header 'Content-Type: application/json' --data '{}' \
https://social.example.com/api/ping
docker compose logs --since 5m --tail 100 web
这次首页返回 HTTP 200,/api/ping 返回包含 pong 的 JSON。启动日志显示 worker 已启动并监听端口,数据库和 Redis 也保持健康。
本次验证了应用启动及基本 HTTP/API,未进行漏洞利用复现,也未完整测试登录、上传和联邦交互。
回退与后续维护
若新镜像启动失败,且应用版本未变、未新增数据库迁移,可恢复备份的 compose.yaml,将 web.image 改为已保存的 local/misskey:before-node-security-时间戳,并设置 pull_policy: never。执行以下命令重新创建容器,再核对镜像 ID:
1
2
3
4
cd /opt/misskey
docker compose config --quiet
docker compose up -d --no-deps --no-build --pull never \
--wait --wait-timeout 180 web
官方标签可能已被前面的 docker pull 更新,回退必须使用保存的本地标签。回退会恢复旧运行时,仅用于临时恢复服务。
如果以后升级了 Misskey 应用,且已经执行数据库迁移,就不能默认“换回旧镜像”一定能回滚,需要结合该版本迁移说明和数据库备份处理。不要执行 docker compose down -v 来升级,它会删除 Compose 管理的数据卷。
当前部署使用的是本地修补镜像。以后官方发布新镜像时,先拉取并独立检查它的 Node.js 版本,再决定是否切回官方镜像;切回时要同步调整 image、pull_policy 和 build,避免继续使用旧修补镜像或误将它重建回来。