You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* feat(security): egress firewall ruleset generator + tests
Pure build_egress_ruleset + discovery/validation + --self-test for the WS/WebRTC
SSRF egress firewall. Hermetic unit tests incl. parity vs ssrf_guard._is_blocked_ip.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(security): image tooling + root-in-userns init for egress firewall
Install nftables/iproute2/util-linux; drop USER fingpt so PID1 loads the firewall
as root-in-userns then setpriv-drops to uid1001. No setcap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(security): root-init-drop entrypoint loads the egress firewall fail-closed
Guarded temp-file nft load + post-load table assertion + active self-test (metadata
unreachable, redis/DNS reachable), chown runtime, then setpriv-drop to uid1001 with
NET_ADMIN removed from the bounding set + no_new_privs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* ci(security): --cap-add=NET_ADMIN + pre-cutover firewall validation; compose cap_add
Grant NET_ADMIN (load-bearing) to the api container; start redis then validate the new
image can load the egress firewall + pass its self-test on fingpt-net before the
--replace cutover (abort on failure so the old container keeps serving); record the
previous image for manual rollback; grant NET_ADMIN in docker-compose for local dev.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(security): disable WebRTC + QUIC at Chromium (egress firewall defense-in-depth)
Remove RTCPeerConnection in every frame (async factory + sync path) and add
--disable-quic, shrinking the public WS/WebRTC/QUIC exfil surface the netns firewall
leaves as a documented residual. Updates the factory guard test for the new await.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(ops): off-box uptime monitor for deploy-independent fail-closed detection
Scheduled curl of the public /health/ so a reboot/OOM/update that fails the egress
firewall load (fail-closed, no auto-rollback) is caught within minutes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(security): update non-root guards for root-init-drop
USER fingpt moved from the Dockerfile to entrypoint.sh (setpriv drop, NET_ADMIN out
of the bounding set, no_new_privs) so PID1 can load the egress firewall as root. Assert
the drop at its new home; count only actual chown commands (not the new comment prose).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(security): address self-review findings (resilience, honesty, coverage)
Adversarial review fixes (branch validated on the droplet):
- Self-test no longer makes redis/DNS a hard boot gate (was a resilience regression vs
main): metadata-DROP leg stays fatal; redis/DNS legs are advisory (warn, non-fatal) so
a redis blip at reboot cannot fail-close a correct firewall.
- Metadata proof is now a reachable->blocked TRANSITION (--metadata-reachable before load
+ METADATA_WAS_REACHABLE), honestly flagged INCONCLUSIVE off-cloud instead of a vacuous
pass. Applied in entrypoint + the deploy pre-cutover gate.
- Deploy: redis started idempotently (start-if-absent, not --replace) so an aborted
pre-cutover gate no longer bounces live redis / wipes counters.
- Uptime monitor retry budget widened to ~180s (past the ~130s cold start) to stop
false DOWN alarms during deploys.
- entrypoint: EGRESS_FW_LOADED marker + app-phase guard (fail closed if the app phase is
ever reached without the root-init firewall load).
- discover_own_v6 constrained to ULA/GUA (symmetric with the v4 nesting check).
- Chromium hardening comments corrected to best-effort (not a boundary).
- New coverage: discovery parser (real ip -o output + rogue special-range), self-test
fatal/non-fatal legs, entrypoint grep<->generator sentinel coupling, structural
privilege-drop guard, ExecStart + compose NET_ADMIN cap locks, behavioral sync
Chromium hardening test.
Deferred (documented in PR): EGRESS_OWN_SUBNET prefixlen floor, RULES mktemp trap,
writable HOME for the dropped user.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* polish(security): address PR #326 review findings
Review findings from the pre-merge code review, all non-blocking:
- Dedup _DISABLE_WEBRTC_JS: single public constant ssrf_guard.DISABLE_WEBRTC_JS
(both scraper paths already import ssrf_guard); tests upgraded from substring
to exact-equality against the shared constant so a local copy cannot drift back.
- Bound the advisory redis self-test leg's worst case: probe timeout 3s -> 1s
(same-subnet connect answers in ms or RSTs instantly; 6*(1+1)=12s worst case
vs 24s inside the ~130s deploy health window).
- _V6_DROP: document the future-IPv6 NDP footgun (ff00::/8 + fe80::/10 output
drops swallow neighbor discovery; icmpv6 carve-out needed if v6 ever enabled).
- Deploy workflow: document that redis start-if-absent freezes the redis image
across deploys + the manual recreate procedure for redis upgrades.
- entrypoint.sh: make explicit that EGRESS_FW_LOADED is a spoofable
mistake-guard, not a security boundary.
- Design spec: record the shipped amendment that the DNS/redis self-test legs
are advisory (WARN), not fatal; only the metadata leg is fatal.
Full suite: 576 passed, 1 skipped. manage.py check clean. Delta adversarially
reviewed (3 independent lenses): behavior-preserving except the intended
timeout change, which touches only the advisory leg.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* refactor(security): simplify PR #326 per 4-lens cleanup review
- Deploy gate now runs the image's REAL entrypoint (--egress-check-only)
instead of an inline re-copy of the root-init sequence that had already
drifted (missing [ -s ] + grep sentinels); wiring pinned by a new
structural test (flag must sit after setpriv, before the store build)
- egress_firewall: single _nets_within() nesting guard shared by v4/v6
discovery; _ip_addr_cidrs scans only its family's key; EGRESS_OWN_SUBNET
override now fully hermetic (suppresses the v6 ip subprocess too, +test)
- ssrf_guard.CHROMIUM_HARDENING_ARGS: --disable-quic single-sourced for
both launch sites, next to DISABLE_WEBRTC_JS
- test_ssrf_wire: one shared async + one shared sync Playwright mock
scaffold replace four hand-copied chains
- test_dockerfile_nonroot: setpriv flags asserted once on the actual exec
statement (strictly stronger than the whole-file substring checks);
line-continuation joiner reduced to a re.sub
- sentinel test also pins the entrypoint's nft table-name literal to
ef.TABLE; spec amended to record the gate's new shape
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
0 commit comments