Repository navigation
Releases
Releases · unixsec/skillscan
release 1.4.1
安全修复
本版本修复的问题来自 v1.4.0 的从零安装端到端验证:在全新环境中安装后,扫描了 skillhub 下载量前 200 的真实 skill。
- auditor 可以提交扫描,并抢注 skill 的归属(高):按权限矩阵,auditor 不能提交扫描,但
POST /v1/scans放行了。skill 的 owner 在首次提交时登记,所以 auditor 能抢先注册别人的 skill_id。现在纯 auditor 提交返回403;同时持有 approver 或 admin 的不受影响。控制台对纯 auditor 不再显示提交表单。 - 市场接口是另一个入口(高):OIDC 登录的人类会话,scopes 直接取自 IdP 签发的 token。如果 IdP 给人签发了
scan:submit,auditor 可以经POST /v1/market/scans绕过上面的限制。现在/v1/market只接受机器身份,即 client-credentials、账号密码和 mTLS 三种;人类会话返回403 only available to service accounts,并且在限流计数之前就被拒绝。 - 带命名空间的 skill 无法隔离(高):inventory 的单 skill 路由(详情、quarantine、restore、retire、owner、baseline)不接受带
/的 skill_id,比如@acme/deploy-helper,一律返回404。实测环境中 262 个 skill 里有 251 个带/,也就是说隔离这个应急手段对大多数 skill 用不了。现在原样写法和 URL 编码写法都能用。
新增两个守卫测试:
- 凡是会创建扫描的路由,都必须拒绝纯 auditor;新增的提交接口会自动被覆盖。
- 应用里不能出现不带
:path的{skill_id}路由。
部署修复
- 开启动态沙箱执行器、只按 chart 安装时,monolith 连不上 MySQL:chart 渲染的出站策略只放行了 apiserver。现在它带上了
deploy/networkpolicy/monolith-egress-allowlist.yaml中的全部规则,scripts/check_chart_render.py会检查两者是否一致。 - 沙箱因隔离证明失败被跳过时,没有任何日志:现在每次状态变化(拒绝执行、恢复)记一条 warning,状态不变时不重复记。部署指南 §6.1⑥ 补上了 Kyverno 渲染漏写的
-s <沙箱命名空间>,并新增 §6.14「启用动态沙箱执行器」。 - 离线包:
build_offline_bundle.sh新增三个选项。打出的镜像里写入构建提交,/healthz不再显示build: unknown。--mtu N/--network NAME:用于路径 MTU 小于 1500 的网络。--with-sandbox:打入沙箱的 runner 和 dnstrap 镜像,并把执行器需要的 digest pin 写进 manifest。
文档
- README 的扫描示例改为真实输出:
curl … | sh命中 NET-07,等级 MEDIUM,判 REVIEW。这个等级是有意设定的。另外,API 返回的severity是数字(0–4)。 - 部署指南修正了过期的离线包 tag(以前写的是
0.1.0)。市场接入指南的排错表补充了上面那个新的403。
升级须知
- 客户端可见的变化:用浏览器或 OIDC 人类会话调用
/v1/market的,现在返回403。按设计,市场接口只给服务账号用。 - 没有新增配置项,缓存身份不变,升级后不会重新判定。
- 改配置的方式:仍然用
helm get values取出线上真值,合并后再helm upgrade。
所有测试都跑在真实的 k3s、MySQL 和 Redis 上:全量 4407 passed,另有 2 个已知的 vendor pin 用例需要 .git 才能跑。修复也在线上复测过:auditor 提交被拒;200 个带 / 的 skill id 全部能打开;沙箱执行正常,判定与修复前一致。市场接口的修复由集成测试和守卫测试覆盖。
release 1.4.0
Highlights
- 扫描管线存活性 — 必需的消费组集中在
airlock.REQUIRED_GROUPS一处声明。消费组被删除后,
整个拓扑 1 秒内自愈;此前 monolith 的workers组不会自动恢复,实测零吞吐持续了 26 分钟,
而健康面板始终显示ok。新增事件循环停摆探测器;解包改在线程里执行,突发负载下
/healthz的最大延迟从 30016ms 降到 41ms。 - 进度、准入与沉默引擎 —
GET /v1/scans/{id}现在总会带progress对象,能区分"卡住"和
"忙"。管线超过阈值时,两条提交路径都返回429和Retry-After。持续不交付结果的顾问型引擎
会被移出等待集,并在判定里写明advisory_engine_silent:<engines>;按扫描是否真的等过它来判定,
并设有时效上限,引擎恢复后会自动回到等待集。 - 13 个自研引擎与评分方案 p4 — 检测引擎加固,评分新增 SC1–SC6 守卫和降级分类。
在 186 个包上与旧版逐包零差异;在 60 个混合语料上,判定只收紧、没有放宽。 - 动态沙箱执行器(gVisor + Kubernetes) — 在隔离的 Job 里真正执行技能包,v1 只放行 DNS 陷阱,
其余网络一律拒绝。执行在 monolith 内的异步通道中进行,不再拖住 worker tick。通道按积压
弹性决定宽度,沙箱 ResourceQuota 由maxConcurrency推导。因容量不足而证据不全的扫描,
会在通道空闲时自动补全重扫,最多 2 次。默认关闭,节点上必须先装好 gVisor RuntimeClass。 - 吞吐 — 同一批 60 个真实包、判定逐包不变的前提下:181s(4 核)→ 140s → 88s(8 核)。
其中一处是存在已久的缺陷:engine-runner 的内联引擎在事件循环上阻塞执行,配置的"宽度"
从未让它们真正并行。 - 结果收集与重投 — 收集器每个 tick 按时间预算排空结果流;sweep 在 workers 组或结果流有积压时
不再重投扫描。执行器开启时,重投从 156 次降到 0,用时从 848s 降到 230s。
升级须知
- 缓存身份变化:评分方案升到 p4,执行器配置也计入缓存身份,所以升级后同样内容的包会重新判定,
不会沿用旧结果。 - 客户端可见的变化:管线过载时提交接口返回
429并带Retry-After,调用方需要按它退避重试。 - 新增配置项:
engineRunner.maxConcurrency:默认 3,engine-runner 沙箱层的宽度上限。加核后要连同
limits.cpu一起调高,否则加的核用不上。dynamicSandbox.executor.laneDrainTargetS:默认 30,决定积压清空过程中通道保持多宽。
它不会抬高峰值,峰值仍由maxConcurrency和 quota 限定。SKILLSCAN_ENGINE_SILENCE_WINDOW:默认 20,判定引擎沉默的样本窗口。- 沉默排除的时效
max_age_s:默认 900s。
- 改配置的方式:用
helm get values取出线上真值,合并新键后再helm upgrade。
不要只带新键升级,否则其余值会回落到默认值。
所有结论都来自在真实 k3s、MySQL 和 Redis 上的测试:全量 4393 passed,2 个已知的 vendor pin 用例
需要 .git 才能跑。
release 1.2.0
Highlights
- 管线健康面 — 一次调用
GET /v1/admin/pipeline读到队列深度、消费组 lag/PEL、
worker 存活、任务状态分布与死信量。任一分区读不到时呈现unknown而非默认健康。 - 有界流保留 — 系统内第一条 Redis 流裁剪:只删除每个消费组都已确认消费、且超过
24 小时取证地板的历史条目,分批执行,PEL 与未投递条目一概不动。 - 阈值告警接线 — 五个维度(流积压、投递停滞、超龄排队、最老等待、死信率)经日志与
SIEM CEF 输出,含级别迁移去重与量级再发射。 - 企业事故修复 — worker tick 步骤结构性隔离(单步故障不再拖垮整轮)、DSN 凭据
URL 转义、连接池主动回收、可选 Redis Sentinel 发现、镜像构建指纹经/healthz自证。 - 共享内容多归属 — 多个团队可各自注册同一份技能包,判定共享而归属独立;豁免、
复审授权、信任层级与信息披露四处做了跨租户封口。 - 市场接口可用性 — M2M 契约终于能从 Helm chart 启用(此前三个变量在 chart、
VM 清单与 compose 中均无出口,任何 Helm 部署下调用均返回 401)。
Release 1.1.0
Highlights
- LLM gateway — a single egress point for every LLM-backed engine. Translates
each provider's dialect (model naming, token-limit field, Anthropic's top-level
system, paired-field integrity) and classifies every outcome with a stable
code, so a refused request shape is distinguishable from a slow one. - CPU-aware sandbox scheduling — concurrency is chosen from queue depth and
bounded by the container's cgroup CPU quota, not by host cores. - Threat intel — signature-verified offline IOC import enables the intel
matcher tier (domain / IP / hash). - Pagination — reviews, inventory and reeval listings are windowed at 50 rows
and return a total. - Engine console — split into control (enable/disable) and status (last
result, duration, window counts).
Correctness
- Cache identity now covers the sandbox tier: a refreshed vulnerability database,
an edited rule, a bumped vendor pin or a different LLM model all re-judge
previously scanned packages instead of serving a stale verdict. - Verdict monotonicity — adding a confident finding can no longer relax a verdict.
- A Vault failure between scoring and signing no longer strands a scan.
- Least-privilege database grants are verified by authenticating as each module
account, not by asking whether the account exists.
Notes
Malicious-package advisories from OSV are now classified CRITICAL and titled
distinctly from CVEs. The aig adapter no longer records "no risk found"
placeholders as findings.
Full changelog: v1.0...v1.1.0