tracking: 外呼与输入校验面(4 项)—— 外部可控输入未被当作不可信数据
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 12/100
- Tipo di issue
- Bug
- Chiarezza
- Da chiarire
- Stato di attività
- Attiva
- Ambito
- networking, security
Direzione di ricerca
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.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
优先级 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 的纯函数部分)。
- Lingua principale
- Rust
- Stelle
- 4
- Fork
- 0
- Merge medio
- 5h 32m
- PR unite (30g)
- 7
Preparare l'ambiente
- Include un Dockerfile o un file Docker Compose
- Nessun modello di pull request
- Nessuna guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di jeffkit/recursive
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
jeffkit/recursive#159 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 15/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 15/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 8/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 12/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di jeffkit/recursive
Issue simili
-
C-bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
rust-lang/rust-analyzer#23501 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 1 giorno
-
[Bug]: Web chat input doesn't regain focus after a reply finishesForse già presa @GaijinSystems l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
zeroclaw-labs/zeroclaw#11658 ·
I maintainer di solito rispondono entro 2 giorni
-
good first issue help wanted
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
bytecodealliance/wasm-tools#2768 ·
I maintainer di solito rispondono entro 1 giorno