Skip to content

Commit ffc1746

Browse files
Mossakaclaude
andauthored
fix(proxy): add lowercase proxy vars and NODE_EXTRA_CA_CERTS (#1234)
* fix(proxy): add lowercase proxy vars and NODE_EXTRA_CA_CERTS Yarn 4 (undici), Corepack, and some Node.js HTTP clients only check lowercase http_proxy/https_proxy environment variables. This caused EPROTO SSL errors when these tools tried to make HTTPS connections through the Squid proxy. - Add lowercase http_proxy/https_proxy alongside uppercase variants - Set NODE_EXTRA_CA_CERTS when SSL Bump is enabled so Node.js trusts the AWF session CA certificate - Export NODE_EXTRA_CA_CERTS in entrypoint.sh for container context - Add tests for lowercase proxy vars and NODE_EXTRA_CA_CERTS Fixes #949 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(proxy): add NO_PROXY to api-proxy container for health check The api-proxy container's curl health check was routing through Squid because of the newly-added lowercase http_proxy/https_proxy env vars. curl respects lowercase proxy vars, causing localhost health checks to fail. Add NO_PROXY/no_proxy with localhost entries to prevent this. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove lowercase http_proxy to prevent HTTP forward-proxy bypass Some curl builds (Ubuntu 22.04) ignore uppercase HTTP_PROXY for HTTP URLs as an httpoxy mitigation. This means HTTP traffic correctly falls through to iptables DNAT interception where Squid blocks at the connection level. Setting lowercase http_proxy causes curl to use the forward proxy, where Squid's 403 error page returns exit code 0 — breaking security expectations. Only https_proxy (lowercase) is needed for Yarn 4/undici/Corepack compatibility since these tools connect to registries via HTTPS. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d964ac2 commit ffc1746

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
lines changed

containers/agent/entrypoint.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,11 @@ if [ "${AWF_SSL_BUMP_ENABLED}" = "true" ]; then
104104
echo "[entrypoint] SSL Bump mode detected - updating CA certificates..."
105105
if [ -f /usr/local/share/ca-certificates/awf-ca.crt ]; then
106106
update-ca-certificates 2>/dev/null
107+
# Set NODE_EXTRA_CA_CERTS so Node.js tools (Yarn 4, Corepack, npm) trust the AWF CA.
108+
# Node.js uses its own CA bundle, not the system CA store updated by update-ca-certificates.
109+
export NODE_EXTRA_CA_CERTS="/usr/local/share/ca-certificates/awf-ca.crt"
107110
echo "[entrypoint] CA certificates updated for SSL Bump"
111+
echo "[entrypoint] NODE_EXTRA_CA_CERTS set to $NODE_EXTRA_CA_CERTS"
108112
echo "[entrypoint] ⚠️ WARNING: HTTPS traffic will be intercepted for URL inspection"
109113
else
110114
echo "[entrypoint][WARN] SSL Bump enabled but CA certificate not found"

src/docker-manager.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,10 +507,49 @@ describe('docker-manager', () => {
507507

508508
expect(env.HTTP_PROXY).toBe('http://172.30.0.10:3128');
509509
expect(env.HTTPS_PROXY).toBe('http://172.30.0.10:3128');
510+
expect(env.https_proxy).toBe('http://172.30.0.10:3128');
510511
expect(env.SQUID_PROXY_HOST).toBe('squid-proxy');
511512
expect(env.SQUID_PROXY_PORT).toBe('3128');
512513
});
513514

515+
it('should set lowercase https_proxy for Yarn 4 and Corepack compatibility', () => {
516+
const result = generateDockerCompose(mockConfig, mockNetworkConfig);
517+
const agent = result.services.agent;
518+
const env = agent.environment as Record<string, string>;
519+
520+
// Yarn 4 (undici), Corepack, and some Node.js HTTP clients only check lowercase
521+
expect(env.https_proxy).toBe(env.HTTPS_PROXY);
522+
// http_proxy is intentionally NOT set - see comment in docker-manager.ts
523+
expect(env.http_proxy).toBeUndefined();
524+
});
525+
526+
it('should set NODE_EXTRA_CA_CERTS when SSL Bump is enabled', () => {
527+
const sslBumpConfig = { ...mockConfig, sslBump: true };
528+
const ssl = {
529+
caFiles: {
530+
certPath: '/tmp/awf-test/ssl/ca-cert.pem',
531+
keyPath: '/tmp/awf-test/ssl/ca-key.pem',
532+
derPath: '/tmp/awf-test/ssl/ca-cert.der',
533+
},
534+
sslDbPath: '/tmp/awf-test/ssl_db',
535+
};
536+
const result = generateDockerCompose(sslBumpConfig, mockNetworkConfig, ssl);
537+
const agent = result.services.agent;
538+
const env = agent.environment as Record<string, string>;
539+
540+
expect(env.NODE_EXTRA_CA_CERTS).toBe('/usr/local/share/ca-certificates/awf-ca.crt');
541+
expect(env.AWF_SSL_BUMP_ENABLED).toBe('true');
542+
});
543+
544+
it('should not set NODE_EXTRA_CA_CERTS when SSL Bump is disabled', () => {
545+
const result = generateDockerCompose(mockConfig, mockNetworkConfig);
546+
const agent = result.services.agent;
547+
const env = agent.environment as Record<string, string>;
548+
549+
expect(env.NODE_EXTRA_CA_CERTS).toBeUndefined();
550+
expect(env.AWF_SSL_BUMP_ENABLED).toBeUndefined();
551+
});
552+
514553
it('should set NO_COLOR=1 to disable ANSI color output from CLI tools', () => {
515554
const result = generateDockerCompose(mockConfig, mockNetworkConfig);
516555
const agent = result.services.agent;

src/docker-manager.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,13 @@ export function generateDockerCompose(
371371
const environment: Record<string, string> = {
372372
HTTP_PROXY: `http://${networkConfig.squidIp}:${SQUID_PORT}`,
373373
HTTPS_PROXY: `http://${networkConfig.squidIp}:${SQUID_PORT}`,
374+
// Lowercase https_proxy for tools that only check lowercase (e.g., Yarn 4/undici, Corepack).
375+
// NOTE: We intentionally do NOT set lowercase http_proxy. Some curl builds (Ubuntu 22.04)
376+
// ignore uppercase HTTP_PROXY for HTTP URLs (httpoxy mitigation), which means HTTP traffic
377+
// falls through to iptables DNAT interception — the correct behavior for connection-level
378+
// blocking. Setting http_proxy would route HTTP through the forward proxy where Squid's
379+
// 403 error page returns exit code 0, breaking security expectations.
380+
https_proxy: `http://${networkConfig.squidIp}:${SQUID_PORT}`,
374381
SQUID_PROXY_HOST: 'squid-proxy',
375382
SQUID_PROXY_PORT: SQUID_PORT.toString(),
376383
HOME: homeDir,
@@ -727,6 +734,10 @@ export function generateDockerCompose(
727734
agentVolumes.push(`${sslConfig.caFiles.certPath}:/usr/local/share/ca-certificates/awf-ca.crt:ro`);
728735
// Set environment variable to indicate SSL Bump is enabled
729736
environment.AWF_SSL_BUMP_ENABLED = 'true';
737+
// Tell Node.js to trust the AWF session CA certificate.
738+
// Without this, Node.js tools (Yarn 4, Corepack, npm) fail with EPROTO
739+
// because Node.js uses its own CA bundle, not the system CA store.
740+
environment.NODE_EXTRA_CA_CERTS = '/usr/local/share/ca-certificates/awf-ca.crt';
730741
}
731742

732743
// SECURITY: Selective mounting to prevent credential exfiltration
@@ -1043,6 +1054,10 @@ export function generateDockerCompose(
10431054
// Route through Squid to respect domain whitelisting
10441055
HTTP_PROXY: `http://${networkConfig.squidIp}:${SQUID_PORT}`,
10451056
HTTPS_PROXY: `http://${networkConfig.squidIp}:${SQUID_PORT}`,
1057+
https_proxy: `http://${networkConfig.squidIp}:${SQUID_PORT}`,
1058+
// Prevent curl health check from routing localhost through Squid
1059+
NO_PROXY: `localhost,127.0.0.1,::1`,
1060+
no_proxy: `localhost,127.0.0.1,::1`,
10461061
// Rate limiting configuration
10471062
...(config.rateLimitConfig && {
10481063
AWF_RATE_LIMIT_ENABLED: String(config.rateLimitConfig.enabled),

0 commit comments

Comments
 (0)