Skip to content

fix: egress filtering when running as non-root user#118

Open
sao90 wants to merge 1 commit intoopen-webui:mainfrom
sao90:fix/egress-filtering-as-non-root-user
Open

fix: egress filtering when running as non-root user#118
sao90 wants to merge 1 commit intoopen-webui:mainfrom
sao90:fix/egress-filtering-as-non-root-user

Conversation

@sao90
Copy link
Copy Markdown

@sao90 sao90 commented May 5, 2026

Summary

Egress filtering (OPEN_TERMINAL_ALLOWED_DOMAINS) is broken in the current default image. Two bugs exist:

  1. The container crashes on startup when running as the default unprivileged user
  2. Even if the crash is bypassed, the DNS whitelist never resolves — all outbound traffic is blocked including whitelisted domains

Addressing issue: #119


Bug 1 — Container crash on capability drop

When egress filtering is enabled, the entrypoint configures iptables rules and then attempts to permanently drop CAP_NET_ADMIN using capsh. However, capsh is executed as the unprivileged user, which lacks the CAP_SETPCAP permission required to modify the bounding set. Combined with set -e, this crashes the container immediately:

unable to raise CAP_SETPCAP for BSET changes: Operation not permitted

Fix: Execute capsh via sudo (which the user account has passwordless access to), and use --user=user to securely drop back to the unprivileged user before starting the application.

- exec capsh --drop=cap_net_admin -- -c "exec open-terminal $*"
+ exec sudo capsh --drop=cap_net_admin --user=user -- -c "exec open-terminal $*"

Bug 2 — dnsmasq blocked from reaching upstream DNS

The iptables rules block ALL outbound port 53 traffic. This includes dnsmasq's own queries to the upstream DNS server, which it needs to resolve whitelisted domains. As a result, the allowed ipset is never populated, and all outbound connections fail — even to whitelisted domains.
Fix: Explicitly allow dnsmasq to reach the captured upstream DNS server before applying the blanket port 53 block.

+ sudo iptables -A OUTPUT -p udp -d "$UPSTREAM_DNS" --dport 53 -j ACCEPT
+ sudo iptables -A OUTPUT -p tcp -d "$UPSTREAM_DNS" --dport 53 -j ACCEPT
  sudo iptables -A OUTPUT -p udp --dport 53 -j DROP
  sudo iptables -A OUTPUT -p tcp --dport 53 -j DROP

Test Results

Configuration: --cap-add NET_ADMIN, OPEN_TERMINAL_ALLOWED_DOMAINS=pypi.org

Test v0.11.34 (default, as user) v0.11.34 (forced to run as root*) This PR
Boots without crashing FAIL PASS PASS
Runs as unprivileged user (UID 1000) — (crashed) FAIL (runs as root) PASS
cap_net_admin permanently dropped — (crashed) PASS PASS
DNS: pypi.org resolves via dnsmasq — (crashed) FAIL (no answer) PASS
DNS: google.com blocked — (crashed) PASS (all DNS broken) PASS
HTTP: pypi.org accessible (200) — (crashed) FAIL (000 — timeout) PASS
HTTP: google.com blocked — (crashed) PASS (all traffic broken) PASS
* "Forced to run as root" = launching the container with --user 0:0 to bypass Bug 1. This is not a viable workaround because it means the AI sandbox process runs with full root privileges, defeating the container's security model.

Notes

  • Both bugs must be fixed together. Fixing only Bug 1 results in a container that boots but still has completely non-functional egress filtering.
  • No changes to the Dockerfile or other files — only entrypoint.sh is modified.

@sao90 sao90 marked this pull request as ready for review May 5, 2026 10:33
@sao90 sao90 marked this pull request as draft May 5, 2026 11:03
@sao90 sao90 marked this pull request as ready for review May 5, 2026 11:05
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