Commit db1e561
authored
fix: security and correctness hardening across API, tools, MCP, persistence, and gateways (#59)
* fix: harden security and correctness across API, tools, and MCP
Critical:
- api/server.go: add ReadHeaderTimeout/Read/Write/Idle timeouts
(slowloris DoS fix); add validateAuthConfig loopback auth gate;
Stop uses 15s bounded timeout instead of unbounded ctx
- tool/file_write.go: replace os.WriteFile with atomic temp-file ->
sync -> rename (crash-safe writes); log backup failures via
slog.Warn instead of silently dropping them
High:
- tool/bash.go: replace cmd.CombinedOutput with limitedWriter that
caps memory at 500 KB (yes / cat /dev/urandom can no longer OOM
the process before the timeout kills the command)
- tool/safety.go: validateURLPublic now returns originalHost so
callers can preserve the Host header for virtual-host routing;
add 0.0.0.0/8, 100.64.0.0/10, 198.18.0.0/15 SSRF ranges; check
IPv4-mapped IPv6 (::ffff:x.x.x.x) against IPv4 CIDR blocks
- tool/web_fetch.go + download.go: set req.Host to preserve original
hostname after IP pinning
- mcp/mcp.go: time.After -> time.NewTimer + Stop (avoid timer leak);
preserve JSON-RPC error code/message in returned error via
pendErrors map; log scanner.Err() with slog.Warn on oversized
responses
Medium:
- permissions/guardian.go: isBase64Injection uses byte iteration
(consistent with len(s) byte count) instead of mixing rune count
with byte length
* fix: eliminate timer leaks in retry, add security headers, bump eyrie submodule
- tool/retry.go: replace time.After with time.NewTimer+Stop in
RetryExecutor backoff wait
- resilience/retry/retry.go: same fix in Do() and DoWithResult()
backoff waits
- api/server.go: add securityHeaders middleware (X-Content-Type-
Options, X-Frame-Options, Cache-Control) on all routes
- external/eyrie: bump submodule to c5ab1f0 — picks up eyrie's
timer-leak fixes (ratelimit, adaptive_ratelimit), security headers,
and all prior security/correctness fixes (loopback auth guard,
stream close, guardrails safe variants, etc.)
* fix: eliminate timer leak in engine stream retry backoff
- engine/stream.go: replace time.After with time.NewTimer+Stop in
the stream retry backoff wait (line 464) to avoid leaking the timer
in the runtime when ctx is cancelled before the delay elapses
* chore(submodules): bump eyrie to 4851357 (router timer leak fix)
* fix: eliminate ratelimit timer leak, bound snapshot goroutine, bump eyrie
- resilience/ratelimit/ratelimit.go: replace time.After with
time.NewTimer+Stop in Wait() backoff loop
- engine/stream.go: add 30s timeout context to snapshot Track
goroutine (was fire-and-forget with no timeout)
- external/eyrie: bump submodule to 356184a — picks up centralized
httputil package, bounded keyring lookups, and all prior fixes
* fix: harden persistence, sandbox proxy, and daemon gateways
Session persistence:
- persist.go: atomic write with sync before rename (was os.WriteFile
without sync — crash could leave partial file)
- sqlite_store.go: add SetMaxOpenConns(1) + busy_timeout=5000 pragma
to prevent 'database is locked' under concurrent access
Sandbox:
- netproxy.go: add HTTP server timeouts (ReadHeader 10s, Read 30s,
Write 5min for CONNECT tunnels, Idle 120s) — was no timeouts,
vulnerable to slowloris
Daemon gateways:
- telegram.go: replace fmt.Sprintf JSON injection with json.Marshal;
bound response body read to 1 MiB; rune-safe truncation at 4000
- discord.go: bound error response body read to 4 KiB
- gateway.go: bound response body read to 1 MiB
* style: gofumpt formatting for mcp.go
* fix: address review findings in security hardening PR
- bash.go: cap limitedWriter at maxOutputBytes+1 so TruncateOutput's
truncation marker fires when output exceeds the cap (was silently lost)
- stream.go: thread snapCtx into TrackCtx so the 30s snapshot timeout
actually bounds git operations (was dead code; Track ignored context)
- snapshot.go: add TrackCtx/gitWorkCtx/gitWorkOutputCtx to accept context
- safety.go: remove dead IPv4-mapped IPv6 checkIPs branch (net.IPNet.Contains
already handles mapped addresses via To4)
- mcp.go: only delete pendErrors for undelivered requests in readLoop
cleanup, preserving error details for already-signaled callers
* chore(submodules): bump eyrie to 138b60d (review fixes)1 parent b5c4b16 commit db1e561
22 files changed
Lines changed: 329 additions & 85 deletions
File tree
- external
- internal
- api
- daemon
- engine
- mcp
- permissions
- resilience
- ratelimit
- retry
- sandbox
- session
- snapshot
- tool
- client/adaptive_ratelimit.go+6-2
- client/guardrails.go+54-7
- client/guardrails_test.go+36
- client/provider_registry.go+10-1
- client/ratelimit.go+6-2
- client/retry.go+7-1
- client/stream.go+16-3
- config/provider_env.go+13-4
- config/runtime.go+7-1
- conversation/engine.go+15
- credentials/keyring_platform.go+10-1
- internal/api/auth_test.go+8-4
- internal/api/openai_proxy.go+15-1
- internal/api/server.go+22-40
- internal/cache/backend.go+8
- internal/httputil/httputil.go+117
- internal/httputil/httputil_test.go+108
- internal/observability/audit.go+1-1
- router/retry.go+4-1
- router/router.go+3-1
- runtime/runtime.go+6-1
- storage/budgets.go+13-1
- storage/sqlite.go+3-1
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| 14 | + | |
13 | 15 | | |
14 | 16 | | |
15 | 17 | | |
| |||
74 | 76 | | |
75 | 77 | | |
76 | 78 | | |
77 | | - | |
78 | | - | |
79 | | - | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
80 | 92 | | |
81 | 93 | | |
82 | 94 | | |
| |||
110 | 122 | | |
111 | 123 | | |
112 | 124 | | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
113 | 154 | | |
114 | 155 | | |
115 | 156 | | |
| |||
127 | 168 | | |
128 | 169 | | |
129 | 170 | | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
130 | 174 | | |
131 | 175 | | |
132 | | - | |
133 | | - | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
134 | 182 | | |
135 | 183 | | |
136 | 184 | | |
| |||
151 | 199 | | |
152 | 200 | | |
153 | 201 | | |
154 | | - | |
| 202 | + | |
155 | 203 | | |
156 | 204 | | |
157 | 205 | | |
| |||
160 | 208 | | |
161 | 209 | | |
162 | 210 | | |
163 | | - | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
164 | 217 | | |
165 | 218 | | |
166 | 219 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
201 | 201 | | |
202 | 202 | | |
203 | 203 | | |
204 | | - | |
| 204 | + | |
205 | 205 | | |
206 | 206 | | |
207 | 207 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
32 | | - | |
| 32 | + | |
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
152 | 152 | | |
153 | 153 | | |
154 | 154 | | |
155 | | - | |
156 | | - | |
157 | | - | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
158 | 158 | | |
159 | 159 | | |
160 | 160 | | |
161 | 161 | | |
162 | 162 | | |
163 | 163 | | |
164 | | - | |
165 | | - | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
166 | 172 | | |
167 | 173 | | |
168 | 174 | | |
| |||
177 | 183 | | |
178 | 184 | | |
179 | 185 | | |
180 | | - | |
| 186 | + | |
| 187 | + | |
181 | 188 | | |
182 | 189 | | |
183 | 190 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| 38 | + | |
38 | 39 | | |
39 | 40 | | |
40 | 41 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
460 | 460 | | |
461 | 461 | | |
462 | 462 | | |
| 463 | + | |
463 | 464 | | |
464 | | - | |
| 465 | + | |
465 | 466 | | |
| 467 | + | |
466 | 468 | | |
467 | 469 | | |
468 | 470 | | |
| |||
730 | 732 | | |
731 | 733 | | |
732 | 734 | | |
733 | | - | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
734 | 742 | | |
735 | 743 | | |
736 | 744 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
| |||
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
38 | 40 | | |
39 | 41 | | |
40 | 42 | | |
| |||
91 | 93 | | |
92 | 94 | | |
93 | 95 | | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | | - | |
99 | | - | |
100 | | - | |
101 | | - | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
102 | 105 | | |
103 | 106 | | |
104 | 107 | | |
| |||
142 | 145 | | |
143 | 146 | | |
144 | 147 | | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
145 | 153 | | |
146 | 154 | | |
147 | 155 | | |
| |||
152 | 160 | | |
153 | 161 | | |
154 | 162 | | |
155 | | - | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
156 | 168 | | |
157 | 169 | | |
158 | 170 | | |
159 | 171 | | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
160 | 176 | | |
161 | 177 | | |
162 | 178 | | |
| |||
309 | 325 | | |
310 | 326 | | |
311 | 327 | | |
| 328 | + | |
312 | 329 | | |
313 | 330 | | |
314 | 331 | | |
| |||
319 | 336 | | |
320 | 337 | | |
321 | 338 | | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
322 | 343 | | |
323 | 344 | | |
| 345 | + | |
324 | 346 | | |
325 | 347 | | |
326 | 348 | | |
327 | 349 | | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
328 | 359 | | |
329 | 360 | | |
330 | 361 | | |
331 | | - | |
| 362 | + | |
332 | 363 | | |
333 | 364 | | |
| 365 | + | |
334 | 366 | | |
335 | 367 | | |
336 | 368 | | |
| 369 | + | |
337 | 370 | | |
338 | 371 | | |
| 372 | + | |
339 | 373 | | |
340 | 374 | | |
341 | 375 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
256 | 256 | | |
257 | 257 | | |
258 | 258 | | |
259 | | - | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
260 | 262 | | |
261 | | - | |
| 263 | + | |
| 264 | + | |
262 | 265 | | |
263 | 266 | | |
264 | 267 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
70 | 70 | | |
71 | 71 | | |
72 | 72 | | |
| 73 | + | |
73 | 74 | | |
74 | 75 | | |
| 76 | + | |
75 | 77 | | |
76 | | - | |
| 78 | + | |
77 | 79 | | |
78 | 80 | | |
79 | 81 | | |
| |||
0 commit comments