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
- Set egressMode to "cilium" on a Cilium-equipped cluster for exact FQDN allow-listing.
- Alternatively supply egressAllowCidrs covering the FQDNs' resolved public IPs (this switches to the narrower CIDR-based warning).
- Alternatively remove the FQDN entries if broad public IPv4 HTTPS egress is acceptable.
- 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
- Treat the matching validateConfig warning as a CI blocker, not a log line.
- Standardize on Cilium clusters wherever FQDN allow-listing is a compliance requirement.
- Document the public-IPv4 fallback semantics to security reviewers so nobody mistakes it for allow-listing.
- Check adapter defaults for built-in allowFqdns — the warn can fire with zero operator config.
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
- [plugin-kubernetes] egressMode=standard cannot enforce FQDN-
- Access denied
- UI parser path escapes package directory — skipping
- sandbox runtime asset key is not a simple path segment: ${ke
AI-assisted analysis of paperclipai/paperclip@120ae5428f (2026-08-18).
Data as JSON: /api/errors/58e6533793e66e5f.
Report an issue: GitHub.