Cursor CLI Agent Fails Behind Corporate Proxy on RHEL

Where does the bug appear (feature/product)?

Cursor CLI

Describe the Bug

Cursor CLI Agent doesn’t honor HTTP_PROXY/HTTPS_PROXY environment variables - API key validation fails behind corporate proxy

Environment:
OS: Red Hat Enterprise Linux 8.10 (Ootpa)
Agent Version: 2026.01.09-231024f
Bundled Node.js: v24.5.0
Corporate Proxy: Fortinet-Proxy (HTTP CONNECT)

Steps to Reproduce

The Cursor CLI agent fails to validate API keys when running behind a corporate HTTP proxy. The error message is “The provided API key is invalid” even though the key is valid and works on other systems without a proxy.

The bundled Node.js runtime does not automatically use HTTP_PROXY/HTTPS_PROXY environment variables. Node.js’s built-in https module requires explicit proxy configuration (like http.request with CONNECT method), but the Cursor agent doesn’t implement this.
Proof:
curl works through the proxy:
curl -x $http_proxy https://api.cursor.com/ # Works
Bundled Node.js with explicit proxy works:
// Using http.request with CONNECT method through proxy - WORKS
Bundled Node.js with https.get (how agent uses it) - FAILS/TIMES OUT:
https.get(‘https://api.cursor.com/’) // Times out, ignores HTTP_PROXY
Same API key works on Ubuntu 22.04 (same network, no proxy required for that VM).

Expected Behavior

Cursor CLI agent should respect HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables, similar to how curl and other CLI tools work.

Operating System

Windows 10/11

Current Cursor Version (Menu → About Cursor → Copy)

$ cursor-agent --version
2026.01.09-231024f

Additional Information

The above report was generated using cursor agent on my windows.

  1. Summary of Everything We Tried
    Session Summary: Debugging Cursor CLI on RHEL 8.10
    Step What We Tried Result
    1 Verified API key format :white_check_mark: Valid (key_xxx…, 68 chars)
    2 Checked proxy connectivity with curl :white_check_mark: Works - reached api . cursor . com
    3 Checked SSL certificates :white_check_mark: Valid, no errors
    4 Tried agent --verbose :cross_mark: Flag doesn’t exist
    5 Tried agent login with NO_OPEN_BROWSER=1 :cross_mark: Gives URL but can’t complete (no browser on VM)
    6 Tried agent login --device-code :cross_mark: Flag doesn’t exist
    7 Unset CURSOR_API_KEY and tried fresh auth :cross_mark: Login times out
    8 Passed API key directly with --api-key flag :cross_mark: Still “invalid key”
    9 Tried agent --list-models :warning: “No models available” (key accepted but no access)
    10 Compared with working Ubuntu system :white_check_mark: Same key works on Ubuntu!
    11 Compared OS versions RHEL 8.10 vs Ubuntu 22.04
    12 Compared glibc versions 2.28 (RHEL) vs 2.35 (Ubuntu)
    13 Compared OpenSSL versions 1.1.1k (RHEL) vs 3.0.2 (Ubuntu)
    14 Checked bundled Node.js binary :white_check_mark: Runs fine (v24.5.0)
    15 Tested Node.js HTTPS request :cross_mark: TIMES OUT - doesn’t use proxy
    16 Tested Node.js with explicit proxy (CONNECT) :white_check_mark: WORKS!
    17 Tried GLOBAL_AGENT_* env vars :cross_mark: No effect
    18 Disabled proxy entirely :cross_mark: Can’t reach internet without proxy
    Root Cause:
    Node.js does NOT automatically honor HTTP_PROXY/HTTPS_PROXY environment variables. The Cursor agent needs to explicitly implement proxy support, which it currently doesn’t do.

Does this stop you from using Cursor

Yes - Cursor is unusable

i was able to find a w/a.

i created a proxy inject js to use proxy and modified agent startup to include the –require in node args.

1 Like

Hey, thanks for the detailed bug report, and especially for the workaround you found.

This is a known issue. The CLI doesn’t fully support the HTTP_PROXY and HTTPS_PROXY environment variables yet. The team is working on improving proxy support.

Can you share the details of your --require workaround? It’ll help other users behind corporate proxies until an official fix is out.

the proxy-inject.js

mkdir -p ~/.cursor

cat > ~/.cursor/proxy-inject.js << 'EOF'
const http = require('http');
const https = require('https');
const tls = require('tls');
const { Readable } = require('stream');

// ============================================
// PROXY CONFIGURATION (from environment)
// ============================================
// Reads from: HTTPS_PROXY, HTTP_PROXY, https_proxy, http_proxy
// Format: http://host:port or https://host:port
// ============================================

function getProxyConfig() {
  const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || 
                   process.env.https_proxy || process.env.http_proxy;
  
  if (!proxyUrl) {
    return null;
  }

  try {
    const url = new URL(proxyUrl);
    return {
      host: url.hostname,
      port: parseInt(url.port, 10) || (url.protocol === 'https:' ? 443 : 8080)
    };
  } catch (e) {
    // Try parsing as host:port format
    const match = proxyUrl.match(/^(?:https?:\/\/)?([^:]+):(\d+)/);
    if (match) {
      return { host: match[1], port: parseInt(match[2], 10) };
    }
    console.error('[Proxy] Invalid proxy URL format:', proxyUrl);
    return null;
  }
}

function isNoProxy(hostname) {
  const noProxy = process.env.NO_PROXY || process.env.no_proxy || '';
  if (!noProxy) return false;
  
  const noProxyList = noProxy.split(',').map(s => s.trim().toLowerCase());
  const host = hostname.toLowerCase();
  
  return noProxyList.some(pattern => {
    if (pattern === '*') return true;
    if (pattern.startsWith('.')) {
      return host.endsWith(pattern) || host === pattern.slice(1);
    }
    return host === pattern || host.endsWith('.' + pattern);
  });
}

const PROXY = getProxyConfig();

if (!PROXY) {
  console.error('[Proxy] No proxy configured. Set HTTP_PROXY or HTTPS_PROXY environment variable.');
} else {
  // Tunneling Agent for https module
  class TunnelingAgent extends https.Agent {
    createConnection(options, callback) {
      const targetHost = options.host || options.hostname;
      const targetPort = options.port || 443;

      // Check NO_PROXY
      if (isNoProxy(targetHost)) {
        return super.createConnection(options, callback);
      }

      const proxyReq = http.request({
        host: PROXY.host,
        port: PROXY.port,
        method: 'CONNECT',
        path: `${targetHost}:${targetPort}`,
        headers: { 'Host': `${targetHost}:${targetPort}` }
      });

      proxyReq.on('connect', (res, socket) => {
        if (res.statusCode === 200) {
          const tlsSocket = tls.connect({
            socket, servername: targetHost,
            rejectUnauthorized: options.rejectUnauthorized !== false
          }, () => callback(null, tlsSocket));
          tlsSocket.on('error', callback);
        } else {
          callback(new Error(`Proxy CONNECT failed: ${res.statusCode}`));
        }
      });
      proxyReq.on('error', callback);
      proxyReq.end();
    }
  }

  https.globalAgent = new TunnelingAgent({ keepAlive: true });

  // Wrap fetch to use https.request through proxy
  const originalFetch = globalThis.fetch;

  globalThis.fetch = async function(input, init = {}) {
    let url;
    if (typeof input === 'string') {
      url = new URL(input);
    } else if (input instanceof URL) {
      url = input;
    } else if (input instanceof Request) {
      url = new URL(input.url);
      init = { ...init, method: input.method, headers: input.headers, body: input.body };
    } else {
      return originalFetch(input, init);
    }

    // Skip proxy for non-HTTPS, localhost, or NO_PROXY hosts
    if (url.protocol !== 'https:' || 
        url.hostname === 'localhost' || 
        url.hostname === '127.0.0.1' ||
        isNoProxy(url.hostname)) {
      return originalFetch(input, init);
    }

    return new Promise((resolve, reject) => {
      const options = {
        hostname: url.hostname,
        port: url.port || 443,
        path: url.pathname + url.search,
        method: init.method || 'GET',
        headers: {},
        agent: https.globalAgent
      };

      if (init.headers) {
        if (init.headers instanceof Headers) {
          init.headers.forEach((v, k) => { options.headers[k] = v; });
        } else if (typeof init.headers === 'object') {
          Object.assign(options.headers, init.headers);
        }
      }
      
      options.headers['Host'] = url.hostname;

      const req = https.request(options, (res) => {
        const chunks = [];
        res.on('data', chunk => chunks.push(chunk));
        res.on('end', () => {
          const body = Buffer.concat(chunks);
          const headers = new Headers();
          Object.entries(res.headers).forEach(([k, v]) => {
            if (Array.isArray(v)) v.forEach(val => headers.append(k, val));
            else if (v) headers.append(k, v);
          });

          resolve(new Response(body, {
            status: res.statusCode,
            statusText: res.statusMessage,
            headers
          }));
        });
      });

      req.on('error', reject);

      if (init.body) {
        if (typeof init.body === 'string') {
          req.write(init.body);
        } else if (Buffer.isBuffer(init.body)) {
          req.write(init.body);
        } else if (init.body instanceof Readable) {
          init.body.pipe(req);
          return;
        }
      }
      req.end();
    });
  };

  console.error('[Proxy] HTTPS + fetch patched for:', PROXY.host + ':' + PROXY.port);
}
EOF

and change to agent script

# Find the current agent version directory
AGENT_DIR=$(dirname $(readlink -f $(which agent)))

# Backup original script
cp "$AGENT_DIR/cursor-agent" "$AGENT_DIR/cursor-agent.original"

# Apply patched startup script
cat > "$AGENT_DIR/cursor-agent" << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
export CURSOR_INVOKED_AS="$(basename "$0")"
if command -v realpath >/dev/null 2>&1; then
  SCRIPT_DIR="$(dirname "$(realpath "$0")")"
else
  SCRIPT_DIR="$(dirname "$(readlink "$0" || echo "$0")")"
fi
NODE_BIN="$SCRIPT_DIR/node"
PROXY_INJECT="$HOME/.cursor/proxy-inject.js"
if [ -f "$PROXY_INJECT" ]; then
  exec -a "$0" "$NODE_BIN" --use-system-ca --require "$PROXY_INJECT" "$SCRIPT_DIR/index.js" "$@"
else
  exec -a "$0" "$NODE_BIN" --use-system-ca "$SCRIPT_DIR/index.js" "$@"
fi
EOF

# Make executable
chmod +x "$AGENT_DIR/cursor-agent"

echo "Patch applied successfully!"

Note: Make sure your proxy environment variables are set in your shell profile or /etc/environment:

# Add to ~/.bashrc or ~/.bash_profile
export HTTP_PROXY="http://your-proxy-host:8080"
export HTTPS_PROXY="http://your-proxy-host:8080"
export NO_PROXY="localhost,127.0.0.1,.internal.domain"
1 Like

This topic was automatically closed 22 days after the last reply. New replies are no longer allowed.