paperclipai/paperclip · warning

[plugin-kubernetes] egressMode=standard cannot enforce FQDN-

Error message

[plugin-kubernetes] egressMode=standard cannot enforce FQDN-based egress rules; falling back to public-IPv4 (TCP 80/443) with private/link-local ranges excluded so the configured FQDNs (${totalFqdnsForWarn.join(", ")}) remain reachable. Switch egressMode to "cilium" for exact FQDN allow-listing.

What it means

The Kubernetes sandbox provider enforces egress with standard (Calico-style) NetworkPolicy, which can only express IP/CIDR rules — not FQDNs. When FQDN allow-lists are configured (adapter defaults plus egressAllowFqdns) and no operator CIDRs are supplied, the plugin falls back to allowing all public IPv4 TCP 80/443 (excluding private/link-local) so the FQDNs stay reachable. Isolation is therefore much broader than the configured allow-list intends; switch to egressMode=cilium for exact FQDN enforcement.

Source

Thrown at packages/plugins/sandbox-providers/kubernetes/src/plugin.ts:319

  ): Promise<PluginEnvironmentLease> {
    const config = kubernetesProviderConfigSchema.parse(params.config);
    const namespace = deriveTenantNamespace(config, params.companyId);

    // The adapter for THIS run is the agent's adapter (params.adapterType) when
    // supplied, so one environment can serve mixed harnesses; otherwise fall back
    // to the environment's configured default adapter. getAdapterDefaults validates
    // it is a registered adapter (throws otherwise), so a curated-out adapter fails
    // the lease as before.
    const effectiveAdapterType = resolveRunAdapterType(params.adapterType, config.adapterType);

    // Emit a runtime warning if FQDNs are configured but egressMode=standard
    // cannot enforce them. Mirrors the validateConfig warning so operators see
    // it in paperclip-server logs even if they missed the validation step.
    const adapterDefaultsForWarn = getAdapterDefaults(effectiveAdapterType, config.adapters);
    const totalFqdnsForWarn = [...adapterDefaultsForWarn.allowFqdns, ...config.egressAllowFqdns];
    if (config.egressMode === "standard" && totalFqdnsForWarn.length > 0) {
      if (config.egressAllowCidrs.length === 0) {
        console.warn(
          `[plugin-kubernetes] egressMode=standard cannot enforce FQDN-based egress rules; falling back to public-IPv4 (TCP 80/443) with private/link-local ranges excluded so the configured FQDNs (${totalFqdnsForWarn.join(", ")}) remain reachable. Switch egressMode to "cilium" for exact FQDN allow-listing.`,
        );
      } else {
        console.warn(
          `[plugin-kubernetes] egressMode=standard cannot enforce FQDN-based egress rules. The following FQDNs are reachable only via operator-supplied egressAllowCidrs: ${totalFqdnsForWarn.join(", ")}. Switch egressMode to "cilium" for exact FQDN allow-listing.`,
        );
      }
    }

    const kc = createKubeConfig({
      inCluster: config.inCluster,
      kubeconfig: config.kubeconfig,
    });
    const clients = makeKubeClients(kc);

    // Ensure the tenant namespace and all its RBAC / network policy resources
    // exist before we try to create the Job.
    const adapterDefaults = getAdapterDefaults(effectiveAdapterType, config.adapters);

View on GitHub (pinned to 120ae5428f)

Solutions

  1. Set egressMode to "cilium" on a Cilium-equipped cluster for exact FQDN allow-listing.
  2. Alternatively supply egressAllowCidrs covering the FQDNs' resolved public IPs (this switches to the narrower CIDR-based warning).
  3. Alternatively remove the FQDN entries if broad public IPv4 HTTPS egress is acceptable.
  4. If the FQDNs come from adapter defaults, override the adapter's allowFqdns defaults to empty.

Example fix

// before
{ "egressMode": "standard", "egressAllowFqdns": ["api.anthropic.com"] }

// after
{ "egressMode": "cilium", "egressAllowFqdns": ["api.anthropic.com"] }
Defensive patterns

Strategy: validation

Validate before calling

// Fail the deploy when FQDN allow-listing is required but unenforceable:
function assertEgressConfig(config: SandboxProviderConfig): void {
  const fqdns = [...adapterDefaults.allowFqdns, ...config.egressAllowFqdns];
  if (config.egressMode === 'standard' && fqdns.length > 0 && config.egressAllowCidrs.length === 0) {
    throw new Error(
      `egressMode=standard silently broadens egress to public IPv4 80/443 for ${fqdns.join(', ')}; ` +
      'use egressMode=cilium or supply egressAllowCidrs',
    );
  }
}

Prevention

When it happens

Trigger: Sandbox lease with config.egressMode === 'standard' and a non-empty FQDN set (adapterDefaults.allowFqdns + config.egressAllowFqdns) while config.egressAllowCidrs is empty — the warn is emitted per lease creation.

Common situations: Operator adds api.anthropic.com or similar to allowFqdns expecting allow-listing on a non-Cilium cluster; adapter curated defaults already carry FQDNs so the warn appears even without explicit operator config; security review discovers broad public HTTPS egress.

Related errors


AI-assisted analysis of paperclipai/paperclip@120ae5428f (2026-08-18). Data as JSON: /api/errors/58e6533793e66e5f. Report an issue: GitHub.