Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions FIX_ENTRY_LOCATIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Entry 节点位置自动修复

`scripts/fix_entry_locations.py` 根据节点的 `code` 检查并保守修复
`entry_point`、`critical_operation` 和 `trace[*]` 的文件及行号。

## 运行方式

从仓库根目录执行完整检查:

```bash
python3 scripts/fix_entry_locations.py
```

默认生成:

- `entries.fixed.jsonl`:保留全部 entry,只修改唯一确定的节点;
- `fix_diff.csv`:自动修改前后的字段和采用的策略;
- `needs_human.csv`:多处命中、找不到或源码不可用的节点;
- `.cache/vulngym-source/`:按仓库复用的 Git 源码缓存。

只检查未验证数据或指定样本:

```bash
python3 scripts/fix_entry_locations.py --only-unverified
python3 scripts/fix_entry_locations.py --entry-id entry-00103 --entry-id entry-00320
```

已有完整缓存时可使用 `--offline`,确保运行期间不访问网络。其他路径可通过
`--input`、`--output`、`--diff`、`--needs-human` 和 `--cache-dir` 修改。

## 修复策略

脚本先将每行代码去除首尾空白并折叠连续空白,从而容忍缩进及 tab/空格差异,
同时按连续的非空代码行匹配多行片段。匹配失败后依次尝试:

1. 原行号上下 5 行内唯一命中;
2. 原文件内唯一命中;
3. 整个 commit 中唯一命中。

只有唯一命中才会修改。路径或行号变化后,脚本会同步更新 `desc` 中明确出现的
旧路径和行号引用。所有修改写入 `fix_diff.csv`。

多处命中、完全找不到、代码过短而无法安全搜索、候选范围过大或源码获取失败时,
节点保持原样并写入 `needs_human.csv`。

## 限制

- 脚本只修复位置以及 `desc` 中明确的旧位置引用,不自动重写漏洞语义;
- 极短片段(例如单独的 `}`)通常无法支持可靠的跨仓库定位;
- 首次运行需要下载目标 commit,速度取决于网络和仓库大小;后续运行会复用缓存;
- `needs_human.csv` 中的结果必须由人工结合漏洞上下文判断。
84 changes: 84 additions & 0 deletions config_vuln_annotation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# 配置类/非污点类漏洞标注

## 1. 适用范围

适用于根因来自静态配置、危险默认值、权限声明或缺少安全控制,而不是不可信输入传播的漏洞,例如:

- Dockerfile 未声明 `USER`,容器继承基础镜像的 root 用户;
- sudoers、IAM 或文件权限配置过宽;
- 安全选项被关闭或必要限制缺失;
- 第三方构建脚本以不必要的高权限执行。

这类问题可以使用现有schema 表达,不应把配置关系强行标注为污点流或调用链。

## 2. 字段标注原则

### `entry_point`

选择引入危险配置状态的最早可定位声明:

- 不安全默认值未覆盖:选择引入默认值的位置,例如 `FROM`;
- 显式危险配置:选择配置声明本身,例如 `NOPASSWD:ALL`;
- 缺少配置项:不能伪造不存在的代码节点,应锚定真实声明,并在 `desc` 中注明检查范围和缺失项。

### `critical_operation`

选择核心缺陷或危险配置的生效位置:

1. 有显式危险配置时,选择配置声明本身;
2. 缺少安全覆盖项时,选择继承危险状态的 `CMD` 或 `ENTRYPOINT`;
3. 没有显式运行入口时,选择能够证明危险权限被使用的执行指令,并在 `desc` 中明确它只代表构建阶段。

必须区分“直接以 root 运行”和“非 root 用户可以通过 sudo 提权”。

### `trace`

`trace` 只记录配置状态的改变、激活或验证节点:

- 普通 `COPY`、`WORKDIR`、安装和编译步骤不应为了补全链路而加入;
- 两端已经能完整说明问题时,使用 `"trace": []`;
- `entry_point` 和 `critical_operation` 可以指向同一危险配置,trace 可记录后续生效证据。

## 3. `desc` 编写要求

`desc` 应说明:

1. 当前节点如何引入、保留或证明危险配置;
2. 该配置为什么违反最小权限等安全要求。

描述缺失项时应给出检查范围,例如:

> 检查本 Dockerfile 第 1 至 23 行,未发现 USER 指令覆盖基础镜像的 root 默认用户。

避免使用“权限沿 COPY 传播”“调用栈”等不符合配置语义的表述,也不能推断代码无法证明的运行状态。

## 4. OpenClaw 样本处理

| Entry | `entry_point` | `critical_operation` | `trace` |
|---|---|---|---|
| `entry-00241` | `FROM` 引入 root 默认值 | `CMD` 使配置在运行时生效 | 空 |
| `entry-00242` | `FROM` 引入 root 默认值 | 最后的 `RUN pnpm install`,仅代表构建阶段 | 空 |
| `entry-00243` | `FROM` 引入 root 默认值 | `ENTRYPOINT` 使配置在运行时生效 | 空 |
| `entry-00244` | `NOPASSWD:ALL` | 同一危险配置 | `USER app` 和后续 sudo 命令 |

四条样本均可由当前 schema 表达,不需要从 benchmark 删除。

## 5. 向后兼容建议

当前修复不增加字段。未来可考虑增加可选字段:

```json
{
"analysis_kind": "configuration",
"negative_evidence": {
"file": "scripts/e2e/Dockerfile",
"scope": "1-23",
"expected": "USER <non-root-user>",
"desc": "检查范围内未声明 USER。"
}
}
```

可选字段不会改变现有字段类型,旧消费者可以直接忽略。

修正后的记录继续保留 `verify: 0`,人工确认代码、行号和语义后才能改为 `1`。
14 changes: 14 additions & 0 deletions config_vuln_changes.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
entry_id,field,before,after,reason
entry-00241,entry_point.desc,"把普通构建层描述为 root 特权传播","明确 FROM 引入 root 默认值,并记录 1-23 行缺少 USER","配置状态不是污点传播"
entry-00241,critical_operation.desc,"使用容器逃逸门槛等泛化影响描述","明确 CMD 是 root 默认身份的运行时生效点","解释节点为什么构成关键操作"
entry-00241,trace,"7 个节点,包含 FROM、RUN、WORKDIR 和 CMD","空数组","中间构建指令没有改变有效用户配置"
entry-00242,entry_point.desc,"声称后续所有容器应用进程均继承 root","只确认 1-9 行缺少 USER,后续显式构建命令为 root","文件没有显式 CMD 或 ENTRYPOINT"
entry-00242,critical_operation.desc,"推断依赖注入攻击,未区分构建与运行阶段","限定为 pnpm 安装及生命周期脚本在构建阶段以 root 执行","避免超出代码证据"
entry-00242,trace,"5 个节点并声称 root 延伸至容器运行时","空数组","FROM 到最终 RUN 的关系直接,且没有显式运行入口"
entry-00243,entry_point.desc,"把所有中间指令称为特权传播链","明确 FROM 默认用户以及 1-14 行缺少 USER","配置继承不需要伪造传播链"
entry-00243,critical_operation.desc,"以传播链终止节点描述 ENTRYPOINT","明确 ENTRYPOINT 是 root 配置的运行时生效点","使用配置生效语义"
entry-00243,trace,"5 个节点,包含 apt-get、COPY、chmod","空数组","这些指令没有改变运行身份"
entry-00244,entry_point,"FROM ubuntu:24.04(并错误声称最终进程继承 root)","第 18 行 NOPASSWD:ALL 配置","文件第 20 行实际存在 USER app"
entry-00244,critical_operation,"第 29 行 ENTRYPOINT","第 18 行 NOPASSWD:ALL 配置","核心缺陷是无限制免密 sudo,而非 ENTRYPOINT 直接以 root 启动"
entry-00244,trace,"7 个节点,混合基础镜像、构建步骤和运行入口","第 20 行 USER app 与第 27 行 sudo chmod 两个节点","只保留配置激活与可用性证据"
GHSA-W7J5-J98M-W679,report.vuln_title,"OpenClaw has multiple E2E/test Dockerfiles that run all processes as root - Dockerfile","OpenClaw has multiple E2E/test Dockerfiles that run all processes as root","恢复 GitHub Advisory 的规范标题"
Loading