Skip to content

fix: fix API proxy sidecar bugs preventing Anthropic-only usage#843

Merged
Mossaka merged 4 commits intomainfrom
fix/api-proxy-bugs
Feb 13, 2026
Merged

fix: fix API proxy sidecar bugs preventing Anthropic-only usage#843
Mossaka merged 4 commits intomainfrom
fix/api-proxy-bugs

Conversation

@Mossaka
Copy link
Collaborator

@Mossaka Mossaka commented Feb 13, 2026

Summary

Fixes several bugs in the API proxy sidecar (introduced in #751) that prevented it from working, especially with Anthropic-only configurations:

  • Healthcheck failure: Port 10000 only listened when OpenAI key was set. Now always listens on 10000 for Docker healthcheck.
  • No Squid routing: http-proxy-middleware doesn't respect HTTP_PROXY env var. Replaced with https-proxy-agent for explicit Squid CONNECT tunneling.
  • Missing lockfile: containers/api-proxy/package-lock.json was missing, causing npm ci to fail during Docker build.
  • Host iptables blocking: FW_WRAPPER chain (DOCKER-USER) didn't allow agent→sidecar traffic. Added ACCEPT rule for api-proxy IP.
  • Agent iptables blocking: OUTPUT filter chain's final DROP rule blocked TCP to sidecar. Added ACCEPT + NAT RETURN for api-proxy IP.
  • NO_PROXY not set: curl from agent routed sidecar requests through Squid instead of direct. Added api-proxy IP to NO_PROXY.
  • DNS resolution in chroot: Docker DNS couldn't resolve api-proxy hostname in chroot mode. Switched OPENAI_BASE_URL/ANTHROPIC_BASE_URL to use IP addresses directly.

Test plan

  • Unit tests pass (785/785)
  • New integration test suite (tests/integration/api-proxy.test.ts) with 6 tests:
    • Anthropic healthcheck passes
    • OpenAI healthcheck passes
    • ANTHROPIC_BASE_URL set correctly in agent
    • OPENAI_BASE_URL set correctly in agent
    • End-to-end: Anthropic API request routed through Squid (gets auth error from real api.anthropic.com)
    • Both health endpoints work with Anthropic-only config
  • Manual verification: Squid access log shows TCP_TUNNEL:HIER_DIRECT for api.anthropic.com:443

🤖 Generated with Claude Code

The API proxy sidecar (PR #751) had several bugs that prevented it from
working when only an Anthropic API key was provided:

1. Health endpoint only listened on port 10000 when OpenAI key was set,
   causing Docker healthcheck failures with Anthropic-only configs
2. http-proxy-middleware didn't route through Squid (no HTTP_PROXY support),
   replaced with https-proxy-agent for explicit Squid routing
3. Missing package-lock.json caused npm ci to fail during container build
4. Host-level iptables (DOCKER-USER) blocked agent→sidecar traffic
5. Agent iptables OUTPUT filter dropped TCP to sidecar IP
6. NO_PROXY not set, causing curl to route sidecar requests through Squid
7. Docker DNS couldn't resolve 'api-proxy' hostname in chroot mode,
   switched BASE_URLs to use IP addresses directly

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 13, 2026 21:51
@github-actions
Copy link
Contributor

github-actions bot commented Feb 13, 2026

🎬 THE ENDSmoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨

@github-actions
Copy link
Contributor

github-actions bot commented Feb 13, 2026

Chroot tests passed! Smoke Chroot - All security and functionality tests succeeded.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 13, 2026

📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤

@github-actions
Copy link
Contributor

github-actions bot commented Feb 13, 2026

🌑 The shadows whisper... Smoke Codex failed. The oracle requires further meditation...

No actions taken; awaiting a concrete task request.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 13, 2026

✅ Coverage Check Passed

Overall Coverage

Metric Base PR Delta
Lines 82.88% 82.97% 📈 +0.09%
Statements 82.88% 82.96% 📈 +0.08%
Functions 82.74% 82.74% ➡️ +0.00%
Branches 74.87% 74.97% 📈 +0.10%
📁 Per-file Coverage Changes (2 files)
File Lines (Before → After) Statements (Before → After)
src/host-iptables.ts 79.3% → 78.6% (-0.70%) 79.5% → 78.8% (-0.70%)
src/docker-manager.ts 84.7% → 85.3% (+0.59%) 84.2% → 84.7% (+0.58%)

Coverage comparison generated by scripts/ci/compare-coverage.ts

@github-actions
Copy link
Contributor

Build Test: Bun - Results

Project Install Tests Status
elysia 1/1 PASS
hono 1/1 PASS

Overall: PASS

All tests completed successfully!

AI generated by Build Test Bun

@github-actions
Copy link
Contributor

Smoke Test Results: Copilot ✅

Last 2 Merged PRs:

Test Results:

  • ✅ GitHub MCP: Retrieved PR data
  • ✅ Playwright: Verified GitHub page title
  • ✅ File Writing: Created test file
  • ✅ Bash Tool: Verified file content

Overall Status: PASS

cc @Mossaka @lpcox @Claude

AI generated by Smoke Copilot

@github-actions
Copy link
Contributor

Deno Build Test Results

Project Tests Status
oak 1/1 ✅ PASS
std 1/1 ✅ PASS

Overall: ✅ PASS

All Deno tests completed successfully.

AI generated by Build Test Deno

@github-actions
Copy link
Contributor

Build Test Results: Node.js

Project Install Tests Status
clsx PASS ✅ PASS
execa PASS ✅ PASS
p-limit PASS ✅ PASS

Overall: ✅ PASS

All Node.js projects successfully installed dependencies and passed their test suites.

AI generated by Build Test Node.js

@github-actions
Copy link
Contributor

.NET Build Test Results

All .NET projects were successfully tested:

Project Restore Build Run Status
hello-world PASS
json-parse PASS

Overall: PASS

Test Details

hello-world:

  • Restore: ✅ Completed in 90 ms
  • Build: ✅ No warnings or errors (5.79s)
  • Run: ✅ Output: "Hello, World!"

json-parse:

  • Restore: ✅ Completed in 804 ms
  • Build: ✅ No warnings or errors (1.44s)
  • Run: ✅ Successfully parsed and displayed JSON data

AI generated by Build Test .NET

@github-actions
Copy link
Contributor

Smoke Test Results: Claude Engine

Last 2 Merged PRs:

Test Results:

  • ✅ GitHub MCP: Retrieved PRs successfully
  • ✅ Playwright: Navigated to GitHub, title verified
  • ✅ File Writing: Created test file
  • ✅ Bash Tool: Verified file contents

Status: PASS

AI generated by Smoke Claude

@github-actions
Copy link
Contributor

Go Build Test Results ✅

All Go projects successfully built and tested.

Project Download Tests Status
color 1/1 PASS ✅
env 1/1 PASS ✅
uuid 1/1 PASS ✅

Overall: PASS ✅

AI generated by Build Test Go

@github-actions
Copy link
Contributor

Java Build Test Results

Project Compile Tests Status
gson 1/1 PASS
caffeine 1/1 PASS

Overall: PASS

All Java projects built and tested successfully through AWF with Maven proxy configuration.

AI generated by Build Test Java

@github-actions
Copy link
Contributor

C++ Build Test Results

Project CMake Build Status
fmt PASS
json PASS

Overall: PASS

All C++ projects built successfully.

AI generated by Build Test C++

@github-actions
Copy link
Contributor

Rust Build Test Results

Project Build Tests Status
fd 1/1 PASS
zoxide 1/1 PASS

Overall: PASS

All Rust projects built and tested successfully.

AI generated by Build Test Rust

@github-actions
Copy link
Contributor

Smoke Test Results (Copilot)

✅ GitHub MCP - Last 2 merged PRs:

✅ Playwright - Page title contains "GitHub"
✅ File Writing - Created /tmp/gh-aw/agent/smoke-test-copilot-22004471242.txt
✅ Bash Tool - File verified with cat

Status: PASS 🎉

cc @Mossaka

AI generated by Smoke Copilot

@github-actions
Copy link
Contributor

Build Test: Bun ✅

Project Install Tests Status
elysia 1/1 PASS ✅
hono 1/1 PASS ✅

Overall: PASS ✅

All Bun projects successfully installed dependencies and passed their test suites.

AI generated by Build Test Bun

@github-actions
Copy link
Contributor

Build Test: Node.js - PASS ✅

Project Install Tests Status
clsx PASS PASS
execa PASS PASS
p-limit PASS PASS

Overall: PASS

All Node.js projects successfully installed and passed their test suites.

AI generated by Build Test Node.js

@github-actions
Copy link
Contributor

Smoke Test Results (Claude)

Last 2 Merged PRs:

  • fix: add roles: all to smoke-codex workflow
  • fix: address security review feedback on API proxy sidecar

Tests:

  • ✅ GitHub MCP (retrieved PRs)
  • ✅ Playwright (page title: "GitHub · Change is constant. GitHub keeps you ahead. · GitHub")
  • ✅ File Writing (created test file)
  • ✅ Bash Tool (verified file contents)

Status: PASS

AI generated by Smoke Claude

@github-actions
Copy link
Contributor

.NET Build Test Results ✅

All .NET projects successfully built and ran through the firewall.

Project Restore Build Run Status
hello-world PASS
json-parse PASS

Overall: PASS

Test Details

  • hello-world: Compiled and printed "Hello, World!" ✅
  • json-parse: Restored NuGet packages, compiled, parsed JSON, and displayed output ✅

AI generated by Build Test .NET

@github-actions
Copy link
Contributor

Security Review: Critical API Key Leakage Vulnerability Found

I've identified a critical security vulnerability in this PR that allows API keys to leak to the agent container when using --env-all with --enable-api-proxy.

🔴 Critical: API Key Leakage with --env-all Flag

File: src/docker-manager.ts
Lines: 391-397, 311-321

Vulnerability:

When users enable both --enable-api-proxy and --env-all flags, the ANTHROPIC_API_KEY and OPENAI_API_KEY environment variables will be leaked to the agent container, completely defeating the security purpose of the API proxy sidecar feature.

Root Cause:

The protection at line 405 only applies when --env-all is NOT used:

// Line 403-405 (in the else branch - only applies without --env-all)
if (process.env.ANTHROPIC_API_KEY && !config.enableApiProxy) 
  environment.ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;

However, when --env-all is used (lines 392-397), ALL environment variables not in EXCLUDED_ENV_VARS are passed through:

if (config.envAll) {
  for (const [key, value] of Object.entries(process.env)) {
    if (value !== undefined && !EXCLUDED_ENV_VARS.has(key) && ...) {
      environment[key] = value; // ⚠️ This will include API keys!
    }
  }
}

The EXCLUDED_ENV_VARS set (lines 311-321) does NOT include ANTHROPIC_API_KEY or OPENAI_API_KEY, so they will be passed through to the agent container.

Attack Scenario:

  1. User runs: awf --enable-api-proxy --env-all --allow-domains example.com 'malicious-script.sh'
  2. The malicious script in the agent container can access $ANTHROPIC_API_KEY or $OPENAI_API_KEY
  3. The attacker can exfiltrate these keys through allowed domains or other side channels
  4. The API proxy sidecar feature intended to protect these credentials is completely bypassed

Recommended Fix:

Add explicit API key exclusion in the envAll block:

// In the envAll block (line 392-397)
if (config.envAll) {
  for (const [key, value] of Object.entries(process.env)) {
    // Exclude API keys when api-proxy is enabled (they should only be in sidecar)
    if (config.enableApiProxy && (key === 'OPENAI_API_KEY' || key === 'ANTHROPIC_API_KEY')) {
      continue;
    }
    if (value !== undefined && !EXCLUDED_ENV_VARS.has(key) && !Object.prototype.hasOwnProperty.call(environment, key)) {
      environment[key] = value;
    }
  }
}

Test Coverage Needed:

Add a test case to verify API keys are NOT leaked when both flags are used:

it('should not leak API keys to agent when both enableApiProxy and envAll are enabled', () => {
  process.env.ANTHROPIC_API_KEY = 'sk-ant-secret';
  process.env.OPENAI_API_KEY = 'sk-secret';
  
  const config = { ...mockConfig, enableApiProxy: true, envAll: true, anthropicApiKey: 'sk-ant-secret' };
  const result = generateDockerCompose(config, mockNetworkConfigWithProxy);
  const env = result.services.agent.environment as Record(string, string);
  
  expect(env.ANTHROPIC_API_KEY).toBeUndefined();
  expect(env.OPENAI_API_KEY).toBeUndefined();
});

✅ Other Security Changes Reviewed and Approved

The following changes were reviewed and found to be security-appropriate:

iptables Changes:

  • Host-level ACCEPT rule properly scoped to ports 10000-10001 only (src/host-iptables.ts:444-454)
  • Container NAT RETURN prevents Squid redirect loop (containers/agent/setup-iptables.sh:130-135)
  • Container filter ACCEPT allows agent→sidecar communication (containers/agent/setup-iptables.sh:273-276)
  • Defense-in-depth maintained: API proxy sidecar still routes through Squid for domain whitelisting

API Proxy Server Hardening:

  • SSRF protection: Validates relative paths only (line 72)
  • Header stripping: Removes client-supplied auth headers (lines 23-36)
  • Request size limits: 10 MB maximum to prevent DoS (line 98)
  • Input sanitization: Strips control characters from logs (lines 39-43)

Suggested Action: Please fix the API key leakage vulnerability before merging this PR.

AI generated by Security Guard

@github-actions
Copy link
Contributor

Rust Build Test Results

Project Build Tests Status
fd 1/1 PASS
zoxide 1/1 PASS

Overall: PASS

All Rust projects built and tested successfully.

AI generated by Build Test Rust

@github-actions
Copy link
Contributor

Chroot Version Comparison Test Results

The chroot mode test compared runtime versions between the host and chroot container:

Runtime Host Version Chroot Version Match?
Python Python 3.12.12 Python 3.12.3 ❌ NO
Node.js v24.13.0 v20.20.0 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Overall Status: ❌ Tests did not pass completely

The version mismatches for Python and Node.js are expected - chroot mode provides transparent access to host binaries, so minor version differences between the container and host environments are acceptable. The Go version matches exactly.

AI generated by Smoke Chroot

@github-actions
Copy link
Contributor

Java Build Test Results ✅

All Java projects compiled and tested successfully through the AWF firewall.

Project Compile Tests Status
gson 1/1 PASS
caffeine 1/1 PASS

Overall: PASS

All Maven dependencies were successfully downloaded through the proxy, and all tests passed.

AI generated by Build Test Java

@github-actions
Copy link
Contributor

Merged PRs: fix: add roles: all to smoke-codex workflow | fix(ci): add missing ANTHROPIC_API_KEY to detection job
GitHub MCP last 2 merged PRs ✅
Safeinputs gh pr list ✅
Playwright github.com title ✅
Tavily search ❌ (tool unavailable)
File write ✅
Bash cat ✅
Discussion query + comment ✅
Build (npm ci && npm run build) ✅
Overall status: FAIL

AI generated by Smoke Codex

Add --enable-api-proxy to the awf command in the smoke-claude CI
workflow so the API proxy sidecar is exercised during smoke tests.
This validates that Claude Code works correctly when routed through
the sidecar (ANTHROPIC_BASE_URL pointing to the proxy).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Contributor

github-actions bot commented Feb 13, 2026

📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤

@github-actions
Copy link
Contributor

github-actions bot commented Feb 13, 2026

Chroot tests passed! Smoke Chroot - All security and functionality tests succeeded.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 13, 2026

✨ The prophecy is fulfilled... Smoke Codex has completed its mystical journey. The stars align. 🌟

@github-actions
Copy link
Contributor

github-actions bot commented Feb 13, 2026

🎬 THE ENDSmoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨

@github-actions
Copy link
Contributor

Build Test: Node.js Results

Project Install Tests Status
clsx PASS ✅ PASS
execa PASS ✅ PASS
p-limit PASS ✅ PASS

Overall: ✅ PASS

All Node.js projects successfully installed dependencies and passed their test suites.

AI generated by Build Test Node.js

@github-actions
Copy link
Contributor

Build Test: Deno

Project Tests Status
oak 1/1 ✅ PASS
std 1/1 ✅ PASS

Overall: ✅ PASS

All Deno tests completed successfully.

AI generated by Build Test Deno

@github-actions
Copy link
Contributor

Go Build Test Results ✅

All Go projects successfully built and tested!

Project Download Tests Status
color 1/1 PASS ✅
env 1/1 PASS ✅
uuid 1/1 PASS ✅

Overall: PASS ✅

All modules downloaded successfully and all tests passed.

AI generated by Build Test Go

@github-actions
Copy link
Contributor

C++ Build Test Results

Project CMake Build Status
fmt PASS
json PASS

Overall: PASS

All C++ projects built successfully.

AI generated by Build Test C++

@github-actions
Copy link
Contributor

Bun Build Test Results ✅

Project Install Tests Status
elysia 1/1 PASS ✅
hono 1/1 PASS ✅

Overall: PASS ✅

All tests completed successfully with Bun v1.3.9.

AI generated by Build Test Bun

@github-actions
Copy link
Contributor

Smoke Test Results - Copilot

✅ GitHub MCP: Last 2 merged PRs retrieved

✅ Playwright: GitHub homepage verified (title contains "GitHub")
✅ File Writing: Test file created at /tmp/gh-aw/agent/smoke-test-copilot-22005014196.txt
✅ Bash Tool: File read successfully

Status: PASS 🎉

cc @Mossaka

AI generated by Smoke Copilot

@github-actions
Copy link
Contributor

Smoke Codex Test Report
PR: fix: add roles: all to smoke-codex workflow
PR: fix(ci): add missing ANTHROPIC_API_KEY to detection job
PR: perf: batch chroot integration tests to reduce container overhead
PR: fix: fix API proxy sidecar bugs preventing Anthropic-only usage
Tests: MCP review ✅ | safeinputs-gh ✅ | playwright title ✅
Tests: tavily search ❌ | file write+cat ✅ | discussion comment ✅ | build ✅
Overall: FAIL

AI generated by Smoke Codex

@github-actions
Copy link
Contributor

Smoke Test Results: Claude Engine

Last 2 merged PRs:

✅ GitHub MCP - Retrieved PRs
✅ Playwright - Verified page title "GitHub · Change is constant. GitHub keeps you ahead. · GitHub"
✅ File Writing - Created /tmp/gh-aw/agent/smoke-test-claude-22005016831.txt
✅ Bash Tool - Verified file content

Status: PASS

AI generated by Smoke Claude

@github-actions
Copy link
Contributor

.NET Build Test Results

Project Restore Build Run Status
hello-world PASS
json-parse PASS

Overall: PASS

All .NET projects successfully restored, built, and ran with expected output.

AI generated by Build Test .NET

@github-actions
Copy link
Contributor

Build Test: Java - Results

Project Compile Tests Status
gson 1/1 PASS
caffeine 1/1 PASS

Overall: PASS

All Java projects compiled successfully and all tests passed.

AI generated by Build Test Java

@github-actions
Copy link
Contributor

Chroot Version Comparison Test Results

Runtime Host Version Chroot Version Match?
Python 3.12.12 3.12.3 ❌ NO
Node.js v24.13.0 v20.20.0 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Overall Status: FAILED - Not all runtime versions match between host and chroot environments.

The chroot mode successfully used the host's Go installation, but Python and Node.js versions differ between the host system and the chroot environment.

AI generated by Smoke Chroot

@github-actions
Copy link
Contributor

Rust Build Test Results ✅

Project Build Tests Status
fd 1/1 PASS
zoxide 1/1 PASS

Overall: PASS

All Rust projects built and tested successfully.

AI generated by Build Test Rust

@Mossaka Mossaka merged commit 1243f68 into main Feb 13, 2026
89 checks passed
@Mossaka Mossaka deleted the fix/api-proxy-bugs branch February 13, 2026 22:37
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.

1 participant