Commit 89217e5
feat(tools): SSRF guard on browse_url for loopback / private / link-local targets
Follow-up to TOOLS_AUDIT_2026-05-25 (paired with security review F-03).
browse_url previously accepted any well-formed http(s) URL, so the model
(or a redirect chain) could be steered at internal resources:
- localhost / 127.0.0.1 — local dev servers, admin panels
- 10.x / 172.16-31.x / 192.168.x — internal corporate / home network
- 169.254.169.254 — AWS/GCP/Azure cloud metadata service (creds leak)
- ::1, fe80::/10, fc00::/7 — IPv6 equivalents
Add assertNotSSRF() called from two places:
1. The validator, so the model gets a clear error before the request.
2. The impl boundary, so redirect re-entry (callTool.browse_url skips
the validator) and any future internal caller can't bypass it.
Covers literal hostname bans only. DNS-resolution bypasses (a
public-looking hostname that resolves to a private IP) are not caught
here — that needs async preflight + IPs-of-redirect checking and is
queued as a follow-up.
Includes unit tests covering loopback, private ranges, link-local
(incl. cloud metadata), IPv6 forms, IPv4-mapped IPv6, and boundary
cases just outside the blocked CIDRs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 7190206 commit 89217e5
2 files changed
Lines changed: 138 additions & 0 deletions
Lines changed: 62 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
179 | 179 | | |
180 | 180 | | |
181 | 181 | | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
182 | 239 | | |
183 | 240 | | |
184 | 241 | | |
| |||
473 | 530 | | |
474 | 531 | | |
475 | 532 | | |
| 533 | + | |
476 | 534 | | |
477 | 535 | | |
478 | 536 | | |
| |||
1509 | 1567 | | |
1510 | 1568 | | |
1511 | 1569 | | |
| 1570 | + | |
| 1571 | + | |
| 1572 | + | |
| 1573 | + | |
1512 | 1574 | | |
1513 | 1575 | | |
1514 | 1576 | | |
| |||
Lines changed: 76 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
0 commit comments