Skip to content

feat(proxy): harden the egress proxy sidecar + bound concurrent connections (HF Issue 2) - #88

Merged
rappdw merged 4 commits into
mainfrom
security/proxy-hardening
Jul 28, 2026
Merged

feat(proxy): harden the egress proxy sidecar + bound concurrent connections (HF Issue 2)#88
rappdw merged 4 commits into
mainfrom
security/proxy-hardening

Conversation

@rappdw

@rappdw rappdw commented Jul 28, 2026

Copy link
Copy Markdown
Owner

HF-incident analysis Issue 2 (Low–Medium; defence-in-depth on the incident's exact target).

The egress proxy is the dual-homed container that bridges the --internal sidecar to the internet — the component whose compromise is the incident. It was hardened less than the agent it protects (only --read-only --cap-drop ALL).

Run flags (sandy): add --security-opt no-new-privileges:true, --pids-limit 128, --memory 256m to proxy_run. --user evaluated and declined (documented): the binary binds privileged ports :53/:80/:443, so a non-root uid needs CAP_NET_BIND_SERVICE re-added or the unprivileged-port sysctl — reopening a capability on a cap-dropped, read-only, single-static-binary scratch image for marginal gain.

Connection bound (proxy/accept.go): the three identical accept loops (transparent/CONNECT/forward) now share acceptLoop, which acquires a maxConns(512) semaphore slot before Accept — so a connection storm (self-inflicted or injected) applies backpressure at the kernel backlog instead of growing goroutines/memory without bound. The --memory cap becomes a backstop, not the enforcer (the finding's 'substantive half'). proxy/accept_test.go asserts the bound; the full proxy suite passes -race.

  • run-tests.sh §50: assert the three new proxy_run flags.
  • CLAUDE.md + SPEC: document the hardening + semaphore.

rappdw and others added 4 commits July 28, 2026 15:01
…ctions (HF Issue 2)

The proxy is the dual-homed bridge whose compromise reproduces the HF incident,
so it must be hardened at least as much as the agent it protects. It previously
got only --read-only --cap-drop ALL; the agent gets far more.

Run flags (sandy): add --security-opt no-new-privileges:true, --pids-limit 128,
--memory 256m to proxy_run. Not --user: the binary binds :53/:80/:443, so a
non-root uid would need CAP_NET_BIND_SERVICE or the unprivileged-port sysctl,
reopening a cap on a cap-dropped read-only scratch image for marginal gain
(evaluated, declined — documented).

Connection bound (proxy/accept.go): the three identical accept loops
(transparent/connect/forward) now share acceptLoop, which acquires a slot from a
maxConns(512) semaphore BEFORE Accept — so a connection storm applies backpressure
at the kernel backlog instead of growing goroutines/memory without bound. The
--memory cap is then a backstop, not the enforcer (the finding's 'substantive
half'). proxy/accept_test.go asserts the bound; full proxy suite passes -race.

- run-tests.sh §50: assert the three new proxy_run flags.
- CLAUDE.md + SPEC: document the hardening + semaphore.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sue 2)

The Issue 2 refactor centralized the per-connection 'go guard(...)' spawn into
acceptLoop (proxy/accept.go); the three listeners now dispatch via acceptLoop
instead of each spawning their own guarded goroutine. The invariant is unchanged
(every per-connection goroutine is still guarded), so §53 now asserts accept.go
carries the guarded spawn and each listener routes through acceptLoop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@rappdw
rappdw merged commit 47fa29f into main Jul 28, 2026
2 checks passed
@rappdw
rappdw deleted the security/proxy-hardening branch July 28, 2026 15:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant