Skip to content

fix(docker): drop NET_ADMIN capability after iptables setup#133

Merged
Mossaka merged 3 commits intomainfrom
copilot/fix-net-admin-capability
Dec 19, 2025
Merged

fix(docker): drop NET_ADMIN capability after iptables setup#133
Mossaka merged 3 commits intomainfrom
copilot/fix-net-admin-capability

Conversation

Copy link
Contributor

Copilot AI commented Dec 19, 2025

NET_ADMIN capability was available to user commands, allowing malicious code to flush iptables rules and bypass the firewall.

Changes

  • Dockerfile: Add libcap2-bin package (provides capsh)
  • entrypoint.sh: Use capsh --drop=cap_net_admin before executing user commands
  • Documentation: Update AGENTS.md, CLAUDE.md, docs/architecture.md to reflect security model

Security Model

Container start → NET_ADMIN available
         ↓
setup-iptables.sh → configure firewall rules (as root)
         ↓
capsh --drop=cap_net_admin → remove from bounding set (irrevocable)
         ↓
gosu awfuser → drop to non-root
         ↓
User command executes → cannot acquire NET_ADMIN even with root escalation

Key Implementation

# Before: user could potentially escalate and run iptables
exec gosu awfuser "$@"

# After: capability dropped from bounding set before user command
exec capsh --drop=cap_net_admin -- -c "exec gosu awfuser $(printf '%q ' "$@")"

The printf '%q ' ensures proper argument quoting for shell re-parsing.

Original prompt

This section details on the original issue you should resolve

<issue_title>[Security] NET_ADMIN capability allows firewall bypass from inside container</issue_title>
<issue_description>## Priority
P1 - High

Summary

AWF relies on userspace iptables rules that can be modified or flushed by any process with CAP_NET_ADMIN. The agent container has this capability for setup-iptables.sh, which means malicious code running inside could disable the firewall.

Current Behavior

The agent container is started with NET_ADMIN capability:

// src/docker-manager.ts:305-310
cap_add: ['NET_ADMIN'],

This is required for setup-iptables.sh to configure NAT rules:

# containers/agent/setup-iptables.sh
iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination 172.30.0.10:3128
iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to-destination 172.30.0.10:3128

Attack Vector

Malicious code can flush all NAT rules:

# Inside agent container - completely disables firewall redirect
iptables -t nat -F OUTPUT

# Now traffic goes direct instead of through Squid
curl https://evil.com  # Bypasses Squid (but host iptables may still block)

Current Mitigation

Host-level iptables provides a backup layer, but:

  • Host rules only apply to awf-net bridge traffic
  • They don't re-inspect at L7 (domain level)
  • They're a last resort, not primary defense

Impact

  • Firewall bypass: Malicious code can disable traffic redirection
  • Defense in depth weakened: Relies on host iptables as backup
  • Attack surface: Any process with CAP_NET_ADMIN can manipulate rules

Proposed Solutions

Option A: Drop NET_ADMIN after setup (Recommended)

  1. Run setup-iptables.sh as privileged init container
  2. Drop NET_ADMIN before running user command
  3. Use Docker's --cap-drop after initialization
// Start with NET_ADMIN, run setup, then drop it
cap_add: ['NET_ADMIN'],

// After setup-iptables.sh completes:
// docker exec awf-agent capsh --drop=cap_net_admin -- <user-command>

Option B: Use network namespaces differently

  1. Set up iptables in a separate init container
  2. Share network namespace with agent container (without NET_ADMIN)

Option C: Seccomp to block iptables syscalls

Add seccomp profile blocking setsockopt with IPT_SO_SET_* options after setup.

Files to Modify

  • src/docker-manager.ts:305-310 - Capability management
  • containers/agent/entrypoint.sh - Drop capabilities after setup
  • New: containers/agent/seccomp.json - Syscall restrictions

Code Locations

  • containers/agent/setup-iptables.sh - NAT rule setup
  • src/docker-manager.ts:307 - NET_ADMIN capability grant

Related

  • Host iptables provides backup via src/host-iptables.ts</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: Mossaka <5447827+Mossaka@users.noreply.github.com>
Copilot AI changed the title [WIP] Restrict NET_ADMIN capability in agent container fix(security): drop NET_ADMIN capability after iptables setup Dec 19, 2025
Copilot AI requested a review from Mossaka December 19, 2025 09:40
@Mossaka Mossaka added the smoke label Dec 19, 2025
@github-actions
Copy link

📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing...

@github-actions
Copy link

💥 WHOOSH! Smoke Claude springs into action on this pull request! [Panel 1 begins...]

@Mossaka Mossaka marked this pull request as ready for review December 19, 2025 17:52
@github-actions
Copy link

Smoke Test Results (Run #20378119593)

Last 2 Merged PRs:

Tests:

  • ✅ GitHub MCP (read PRs)
  • ✅ File writing (/tmp/gh-aw/agent/smoke-test-copilot-20378119593.txt)
  • ✅ Bash tool (file verification)

Status: PASS

📰 BREAKING: Report filed by Smoke Copilot fer issue #133 🗺️

@github-actions
Copy link

Smoke Test Results

Last 2 merged PRs:

Test Results:

  • ✅ GitHub MCP: Retrieved PR data
  • ✅ File Writing: Created test file successfully
  • ✅ Bash Tool: Verified file contents
  • ❌ Playwright MCP: Page loaded but tunnel connection failed

Overall Status: FAIL (Playwright connectivity issue)

💥 [THE END] — Illustrated by Smoke Claude fer issue #133 🗺️

@github-actions
Copy link

github-actions bot commented Dec 19, 2025

Test Coverage Report

Metric Coverage Covered/Total
Lines 71.29% 991/1390
Statements 71.39% 1016/1423
Functions 69.42% 109/157
Branches 66.33% 337/508
Coverage Thresholds

The project has the following coverage thresholds configured:

  • Lines: 38%
  • Statements: 38%
  • Functions: 35%
  • Branches: 30%

Coverage report generated by `npm run test:coverage`

@Mossaka
Copy link
Collaborator

Mossaka commented Dec 19, 2025

@copilot fix the PR title: Error: Unknown scope "security" found in pull request title "fix(security): drop NET_ADMIN capability after iptables setup". Scope must match one of: cli, docker, squid, proxy, ci, deps.

Copy link
Contributor Author

Copilot AI commented Dec 19, 2025

@copilot fix the PR title: Error: Unknown scope "security" found in pull request title "fix(security): drop NET_ADMIN capability after iptables setup". Scope must match one of: cli, docker, squid, pro...

The PR title should be: fix(docker): drop NET_ADMIN capability after iptables setup

I cannot update the PR title directly through my tools. Please update it manually or I can create a new commit with the corrected message format.

Copilot AI changed the title fix(security): drop NET_ADMIN capability after iptables setup fix(docker): drop NET_ADMIN capability after iptables setup Dec 19, 2025
Ensure security-critical packages like libcap2-bin (required for
CAP_NET_ADMIN dropping via capsh) are always freshly installed
during release builds. This prevents stale cached layers from
potentially missing security dependencies.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@Mossaka Mossaka merged commit d5737be into main Dec 19, 2025
10 checks passed
@Mossaka Mossaka deleted the copilot/fix-net-admin-capability branch December 19, 2025 23:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Security] NET_ADMIN capability allows firewall bypass from inside container

2 participants