Commit d75b07b
authored
fix: v0.4.1 — security hardening, goroutine leak, fail-closed fixes (#68)
* docs: promote go install as recommended, demote homebrew tap
* fix: data races, bulk-resolve action validation, hook cancel/deny paths
Data races (internal/approval/store.go):
- Get() and List() now return snapshots (value copies) instead of raw
*Request pointers into the live map. Callers previously read fields
like Status, ResolvedAt, ResolvedBy without holding the lock while
watchExpiry wrote them concurrently — torn reads, potential panics.
The -race detector now passes cleanly.
bulk-resolve action validation (internal/proxy/server.go):
- action="" or any non-deny/approve value previously defaulted to
approve, silently bulk-approving entire runs on typos or empty bodies.
Now returns 400 for any value outside {"approve", "deny"}.
- AutoApproveRun now called BEFORE the resolve loop (fixes TOCTOU):
approvals created between List() and the end of the loop are now
caught by the cache rather than staying pending indefinitely.
Hook cancel/deny paths (cmd/rampart/cli/hook_approval.go):
- Ctrl-C (context cancellation) during the initial POST now returns
hookDeny instead of hookAsk. Rampart should fail closed, not fall
back to Claude Code's native permission prompt.
- 200 {status: "denied"} (bulk-deny path) now returns hookDeny instead
of hookAsk — the wrong security outcome previously.
* fix: goroutine leak on shutdown, parse fail-closed, sessionID trim, format default
Server shutdown goroutine leak (internal/proxy/server.go):
- Shutdown() now calls s.approvals.Close() after HTTP server shutdown.
Store.Close() signals the background cleanup goroutine to exit and
unblocks watchExpiry goroutines. Previously they leaked for up to 1h
(the default approval timeout) after every graceful shutdown.
Parse failures fail closed in enforce mode (cmd/rampart/cli/hook.go):
- Hook now returns hookDeny (not hookAllow) on stdin parse failure when
mode=enforce. A Rampart bug or malformed hook payload must not silently
allow a tool call in enforce mode. Monitor/audit modes remain fail-open
so the agent is never blocked by a transient parsing issue.
- Audit event updated: action reflects actual outcome (deny/allow).
- Error message included in the hookDeny reason string.
Format switch default case (cmd/rampart/cli/hook.go):
- Added explicit default branch returning an error. Format is validated
before the switch, so this is unreachable in practice, but it prevents
a nil parsed pointer from reaching downstream code if validation and
the switch ever diverge.
sessionID trim in deriveRunID (cmd/rampart/cli/hook.go):
- RAMPART_RUN and CLAUDE_CONVERSATION_ID were already TrimSpace'd;
the sessionID parameter itself was not. A whitespace-only session_id
from Claude Code would produce a garbage run_id and break grouping.
Empty ID guard + poll status codes (cmd/rampart/cli/hook_approval.go):
- Guard against 201 with empty ID: previously polled /v1/approvals/
(no ID) for the full timeout with no user feedback.
- Poll loop now handles non-2xx: 404/410 → immediate hookDeny,
5xx → log and retry, other codes fall through.
* fix: CEF log injection, service file token exposure, template injection
CEF log injection (internal/audit/cef.go):
- esc() and escH() now escape \n and \r in addition to \ and = (or |).
An agent could previously inject newlines into command/path parameters
to forge additional CEF fields in the audit log. JSONL was unaffected
(json.Marshal already escapes control characters).
Service file permissions (serve_install.go, setup.go):
- Launchd plist and systemd unit files are now written with mode 0o600
(previously 0o644). Both files contain RAMPART_TOKEN inline.
- Added os.Chmod after os.WriteFile to fix permissions on existing files
(WriteFile only applies the mode bit on creation, not on overwrite).
Template injection (serve_install.go):
- Switched text/template -> html/template for plist generation.
html/template auto-escapes XML special characters in <string> values,
preventing a crafted binary path or token from closing the <string>
element and injecting arbitrary plist keys.
- Token is sanitized (newlines/CR/tabs stripped) before embedding in
serviceConfig to prevent Environment= line injection in systemd units.
XML injection (setup.go):
- Added plistXMLEscape() helper: escapes &, <, >, ", ' in all
string values interpolated into plist XML via fmt.Sprintf.
- Added systemdEnvEscape() helper: strips newlines/CR from token
before embedding in systemd Environment= directives.1 parent ebc6736 commit d75b07b
File tree
9 files changed
+185
-48
lines changed- cmd/rampart/cli
- docs-site/getting-started
- internal
- approval
- audit
- proxy
9 files changed
+185
-48
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
107 | 107 | | |
108 | 108 | | |
109 | 109 | | |
110 | | - | |
111 | | - | |
| 110 | + | |
| 111 | + | |
112 | 112 | | |
113 | 113 | | |
114 | 114 | | |
| |||
297 | 297 | | |
298 | 298 | | |
299 | 299 | | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
300 | 305 | | |
301 | 306 | | |
302 | 307 | | |
303 | | - | |
304 | | - | |
305 | | - | |
306 | | - | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
307 | 319 | | |
308 | 320 | | |
309 | 321 | | |
| |||
312 | 324 | | |
313 | 325 | | |
314 | 326 | | |
315 | | - | |
316 | | - | |
| 327 | + | |
| 328 | + | |
317 | 329 | | |
318 | 330 | | |
319 | 331 | | |
320 | 332 | | |
321 | 333 | | |
322 | 334 | | |
323 | | - | |
| 335 | + | |
324 | 336 | | |
325 | 337 | | |
326 | 338 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
86 | 86 | | |
87 | 87 | | |
88 | 88 | | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
89 | 96 | | |
90 | 97 | | |
91 | 98 | | |
| |||
96 | 103 | | |
97 | 104 | | |
98 | 105 | | |
99 | | - | |
| 106 | + | |
| 107 | + | |
100 | 108 | | |
101 | 109 | | |
102 | 110 | | |
103 | 111 | | |
104 | | - | |
105 | | - | |
106 | | - | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
107 | 122 | | |
108 | 123 | | |
109 | 124 | | |
| |||
122 | 137 | | |
123 | 138 | | |
124 | 139 | | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
125 | 148 | | |
126 | 149 | | |
127 | 150 | | |
| |||
163 | 186 | | |
164 | 187 | | |
165 | 188 | | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
166 | 203 | | |
167 | 204 | | |
168 | 205 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
| 25 | + | |
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| |||
257 | 257 | | |
258 | 258 | | |
259 | 259 | | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
260 | 264 | | |
261 | 265 | | |
262 | 266 | | |
263 | | - | |
| 267 | + | |
264 | 268 | | |
265 | 269 | | |
266 | 270 | | |
| |||
321 | 325 | | |
322 | 326 | | |
323 | 327 | | |
324 | | - | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
325 | 332 | | |
326 | 333 | | |
| 334 | + | |
327 | 335 | | |
328 | 336 | | |
329 | 337 | | |
| |||
359 | 367 | | |
360 | 368 | | |
361 | 369 | | |
362 | | - | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
363 | 373 | | |
364 | 374 | | |
| 375 | + | |
365 | 376 | | |
366 | 377 | | |
367 | 378 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
588 | 588 | | |
589 | 589 | | |
590 | 590 | | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
591 | 611 | | |
592 | 612 | | |
593 | 613 | | |
| |||
607 | 627 | | |
608 | 628 | | |
609 | 629 | | |
610 | | - | |
| 630 | + | |
611 | 631 | | |
612 | | - | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
613 | 635 | | |
614 | 636 | | |
| 637 | + | |
615 | 638 | | |
616 | 639 | | |
617 | 640 | | |
| |||
622 | 645 | | |
623 | 646 | | |
624 | 647 | | |
| 648 | + | |
625 | 649 | | |
626 | 650 | | |
627 | 651 | | |
| |||
654 | 678 | | |
655 | 679 | | |
656 | 680 | | |
657 | | - | |
658 | | - | |
659 | | - | |
660 | | - | |
661 | | - | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
662 | 694 | | |
663 | 695 | | |
| 696 | + | |
664 | 697 | | |
665 | 698 | | |
666 | 699 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
11 | 31 | | |
12 | 32 | | |
13 | 33 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
14 | | - | |
| 14 | + | |
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
| 21 | + | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
| 24 | + | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
| 30 | + | |
31 | 31 | | |
32 | 32 | | |
33 | | - | |
| 33 | + | |
34 | 34 | | |
35 | 35 | | |
36 | | - | |
| 36 | + | |
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
256 | 256 | | |
257 | 257 | | |
258 | 258 | | |
259 | | - | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
260 | 265 | | |
261 | 266 | | |
262 | | - | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
263 | 270 | | |
264 | 271 | | |
265 | 272 | | |
266 | 273 | | |
267 | 274 | | |
268 | 275 | | |
269 | 276 | | |
270 | | - | |
| 277 | + | |
| 278 | + | |
271 | 279 | | |
272 | 280 | | |
273 | 281 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
59 | | - | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
60 | 62 | | |
61 | 63 | | |
62 | 64 | | |
| 65 | + | |
| 66 | + | |
63 | 67 | | |
64 | 68 | | |
65 | | - | |
| 69 | + | |
66 | 70 | | |
67 | 71 | | |
68 | 72 | | |
| 73 | + | |
| 74 | + | |
69 | 75 | | |
70 | 76 | | |
71 | 77 | | |
| |||
0 commit comments