tracking: 外呼与输入校验面(4 项)—— 外部可控输入未被当作不可信数据
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 12/100
- Tipo de issue
- Error
- Claridad
- Necesita aclaración
- Estado de actividad
- Activo
- Área
- networking, security
Línea de trabajo
This is a tracking issue with no code of its own; the four child issues (#169 to #172) are the real work, and they must land in order. Start by reading src/tools/policy_domain/url_guard.rs around validate_url and is_private_ip, then src/tools/http_call.rs (encode_segment, build_url), src/tools/a2a.rs (the base interpolation and task_id check), and src/tools/install_skill.rs (slug and extract_zip). Done means the four cluster acceptance checks in the body pass, each with negative tests for the bypass cases.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
优先级 P1 · 依赖:无 · 类型:tracking(簇设计入口,不产出代码;子单全部落地后关闭)
记号:正文中的「不变量 #N」指.dev/AGENTS.md编号,不是 issue 编号;#150这类才是 issue。本簇子单头部写depends-on: #N表示落地串行(同文件/同契约),不会与语义阻塞混淆。
基线 HEAD = 14bac15a(子单同基线)。本单来自一次全仓审计:先按根因归簇,再拆成可独立验收的子单。
共同根因
四条都是「外部可控输入没有被当成不可信数据」,集中在 url_guard 与两个外呼工具:
- SSRF 只查字面主机(#169):
src/tools/policy_domain/url_guard.rs:58-145对Host::Domain仅拦localhost/*.localhost/metadata.google.internal与 IP 字面写法,全仓无自定义 DNS resolver(连接期不校验),且is_private_ip漏100.64/10、0/8(除0.0.0.0)、::a.b.c.d、64:ff9b::/96。169.254.169.254.nip.io这类名字直接放行(重定向绕过已由Policy::none关闭,剩下的就是 DNS 面)。 - 路径逃逸(#170):
src/tools/http_call.rs:437-447的encode_segment保留.,整段..经build_url(:577-586)交给Url::set_path后被解析消解,且不校验最终 path 是否仍以运维 base path 为前缀 → 请求打到网关根路径并带着运维鉴权头。 - shell 注入(#171):
validate_url返回原始输入(url_guard.rs:121),a2a_call把base直接插进单引号命令(src/tools/a2a.rs:272-292),只对task_id做了白名单(:389-409)→ 提前闭合引号的curl|sh可被注入。 - 技能安装缺完整性(#172):
install_dir放行 slug"."(src/tools/install_skill.rs:150-156)→dest变成共享根;extract_zip剥第一层后可在dest内覆盖兄弟技能(:228-258);默认跟随重定向、read_to_end无上限(:290-338、:350-363);slug 未编码即拼 URL(:454-497)。
子单与依赖
| 子单 | 依赖 | 范围 |
|---|---|---|
| #169 | 无 | 自定义 reqwest Resolve:解析结果过 is_private_ip 再连;补齐私网/保留段 |
| #170 | depends-on: #169 | 拒绝 ./.. 参数;断言最终 path 以 base path 为前缀 |
| #171 | depends-on: #170 | 用规范化 Url;拒绝 ' " \ $ \ 空白`;优先 argv/env 传参 |
| #172 | depends-on: #171 | slug 白名单 [A-Za-z0-9_-]+;redirect(none) + sha256 pin;entry/总量双上限 |
落地思路
- #169 不需要新依赖(不变量 #6 不受影响):本机 reqwest 0.12.28 已提供
ClientBuilder::dns_resolver与reqwest::dns::Resolve;把校验放在 resolver 里比放在validate_url里更难绕过(连接期生效)。 - 顺序按同文件串行:#169 与 #171 都动
url_guard.rs,#170/#171 都动src/tools/与 URL 拼装,#172 依赖同一套出站校验约定。 - #170 加的是不变量式断言(
final_url.path().starts_with(base_path)),比逐个过滤字符更可靠。 - 与 B 簇在
url_guard.rs(validate_url被权限面复用)相邻;与 G 簇在src/tools/相邻,按全局顺序错开。
簇级验收
WebFetch/a2a对nip.io形态、DNS rebinding 形态与100.64.x.x全部被拒;http_call的id=".."构建失败;正常id="42"路径为/{base}/42;a2a_call收到含'/空白/;的 URL 时返回错误而非生成可执行命令;install_skill拒 slug".";含..//绝对路径/超限的 zip 被拒且无文件落盘。
边界
不含鉴权与租户身份(G 簇 #152、#146);不含 SKILL 内容来源的信任模型(#64/#76/#77 已定的 SkillSource 边界)。
实施顺序、PR 拆分与验收矩阵(补充 · 2026-10-10)
顺序(四单同域,串行):#169 → #170 → #171 → #172。
理由:#169 与 #171 都动 url_guard.rs;#170 与 #171 都动 URL 拼装;#172 依赖同一套"出站 URL 必须经校验"的约定。四单都不大,串行成本可接受。
跨簇重叠:url_guard.rs(validate_url)被权限面复用(B 簇 #153 只改工具名,不改 URL 逻辑,实际不冲突);src/tools/ 目录级重叠与 G 簇相邻。
PR 拆分:一子单一 PR。每个 PR 附"绕过尝试"的负向测试(本簇的价值就在于此)。
簇级验收 → 测试映射:见正文四条,落在 src/tools/policy_domain/url_guard.rs、src/tools/http_call.rs、src/tools/a2a.rs、src/tools/install_skill.rs 的单测中;#169 建议加一个 reqwest resolver 的单测(可用 Resolve trait 的纯函数部分)。
- Lenguaje dominante
- Rust
- Estrellas
- 4
- Forks
- 0
- Merge medio
- 5 h 32 min
- PR fusionados (30 d)
- 7
Preparar el entorno
- Incluye un Dockerfile o un archivo de Docker Compose
- Sin plantilla de pull request
- Sin guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de jeffkit/recursive
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
jeffkit/recursive#159 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
Dificultad 4/5 3-5 días Aptitud para principiantes 15/100
Los mantenedores suelen responder en 1 día
-
Dificultad 4/5 3-5 días Aptitud para principiantes 15/100
Los mantenedores suelen responder en 1 día
-
tracking: 安全面闭环——已落地机制的绕过(4 项)Abierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 8/100
Los mantenedores suelen responder en 1 día
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 12/100
Los mantenedores suelen responder en 1 día
Todos los issues de jeffkit/recursive
Issues similares
-
[Bug]: Web chat input doesn't regain focus after a reply finishesPosiblemente ocupada @GaijinSystems la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
zeroclaw-labs/zeroclaw#11658 ·
Los mantenedores suelen responder en 2 días
-
good first issue help wanted
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
-
documentation
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
NuSkooler/enigma-bbs#907 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Los mantenedores suelen responder en 1 día