Model URL Security
Ark validates all model base URLs to protect against Server-Side Request Forgery (SSRF) attacks. These security checks prevent malicious URLs from accessing internal services, local files, or cloud metadata endpoints.
Always-On Security Checks
The following validations are always active and cannot be disabled:
HTTPS Enforcement
Protects against: Credential exposure, man-in-the-middle attacks
All model base URLs must use HTTPS. HTTP connections are rejected to prevent API keys and credentials from being transmitted in plaintext.
# ✅ Valid
baseUrl: "https://api.openai.com/v1"
# ❌ Rejected
baseUrl: "http://api.openai.com/v1"Exception: Cluster-internal services (.svc.cluster.local) are allowed to use HTTP since they cannot be accessed from outside the cluster. This is primarily used for testing and development with mock services.
# ✅ Valid (cluster-internal)
baseUrl: "http://mock-openai.default.svc.cluster.local/v1"
baseUrl: "http://service.namespace.svc.cluster.local:8080/api"Scheme Validation
Protects against: Local file access, code injection
Only network protocols (HTTPS) are allowed. File access and script execution schemes are blocked.
# ❌ Rejected
baseUrl: "file:///etc/passwd"
baseUrl: "ftp://internal.server/data"
baseUrl: "javascript:alert(1)"Loopback Address Blocking
Protects against: Localhost exploitation, internal service access
Loopback addresses (127.0.0.1, ::1) are blocked to prevent access to services running on the same host as the controller.
# ❌ Rejected
baseUrl: "https://127.0.0.1:8080/v1"
baseUrl: "https://localhost/v1"
baseUrl: "https://[::1]/api"Private IP Blocking
Protects against: Internal network scanning, unauthorized access to private services
Private IP ranges (RFC 1918) are blocked by default to prevent access to internal network resources.
# ❌ Rejected (private IPs)
baseUrl: "https://10.0.0.1/v1"
baseUrl: "https://172.16.5.10/api"
baseUrl: "https://192.168.1.100/v1"Cloud Metadata Service Blocking
Protects against: Cloud credential theft, instance metadata exposure
The link-local range (169.254.0.0/16) used by cloud providers for metadata services is blocked.
# ❌ Rejected (cloud metadata)
baseUrl: "https://169.254.169.254/latest/meta-data"Validation Errors
When a model URL fails validation, you’ll see an error message indicating which check failed:
Error: spec.config.openai.baseUrl validation failed: all URLs must use HTTPS; got http://
Error: spec.config.azure.baseUrl validation failed: loopback IP addresses are not allowed: 127.0.0.1
Error: spec.config.openai.baseUrl validation failed: private IP addresses are not allowed: 10.0.0.1Supported Model URLs
All model base URLs must use HTTPS and resolve to public IP addresses. Common cloud AI providers that work by default:
- OpenAI:
api.openai.com - Azure OpenAI:
*.openai.azure.com - Anthropic:
api.anthropic.com - Google AI:
generativelanguage.googleapis.com,*.googleapis.com - AWS Bedrock:
bedrock-runtime.*.amazonaws.com
For detailed configuration examples, see the sections below.
Restricting to Approved Domains (Domain Whitelist)
By default, Ark allows any HTTPS domain. Organizations can enable a domain whitelist to restrict model base URLs to approved providers only.
When to Use Domain Whitelist
Enable the domain whitelist to:
- Restrict to approved cloud AI providers only
- Block unauthorized external services
- Enforce organizational policies on model endpoints
- Prevent data exfiltration to untrusted domains
Enabling the Domain Whitelist
If you installed Ark using ark install, follow these steps:
Step 1: Enable the domain whitelist
# Enable domain whitelist via Helm upgrade
helm upgrade ark-controller oci://ghcr.io/mckinsey/agents-at-scale-ark/charts/ark-controller \
--namespace ark-system \
--set modelUrlSecurity.domainWhitelist.enabled=true \
--reuse-valuesThis creates a ConfigMap named model-url-security with example domains (commented out).
Step 2: Configure allowed domains
Edit the ConfigMap to specify which domains are allowed:
kubectl edit configmap model-url-security -n ark-systemUncomment and add your approved domains:
data:
whitelisted-domains: |
# Example: Major cloud AI providers
api.openai.com
api.anthropic.com
# Example: Internal AI gateway with wildcard
*.prod.ai-gateway.company.comSee Common Configurations below for more specific examples (AWS, Azure, GCP, etc.).
Step 3: Restart the controller
kubectl rollout restart deployment ark-controller -n ark-systemStep 4: Verify the configuration
Try creating a model with a non-whitelisted domain to confirm it’s blocked:
kubectl apply -f - <<EOF
apiVersion: ark.mckinsey.com/v1alpha1
kind: Model
metadata:
name: test-blocked
spec:
provider: openai
model: gpt-4
config:
openai:
baseUrl:
value: "https://unauthorized-service.com/v1"
apiKey:
value: "test"
EOFYou should see an error:
Error: domain not in whitelist: unauthorized-service.comDomain Pattern Matching
The whitelist supports multiple patterns:
# Exact domain match
api.openai.com
# Subdomain match (automatically includes subdomains)
openai.azure.com # Matches: my-resource.openai.azure.com
# Wildcard pattern
*.prod.example.com # Matches: api.prod.example.com, llm.prod.example.com
# Top-level domain match
amazonaws.com # Matches: bedrock-runtime.us-east-1.amazonaws.comCommon Configurations
OpenAI + Anthropic Only
data:
whitelisted-domains: |
api.openai.com
api.anthropic.comAzure OpenAI Enterprise
data:
whitelisted-domains: |
openai.azure.comMulti-Cloud + Internal Gateway
data:
whitelisted-domains: |
# Public cloud providers
api.openai.com
api.anthropic.com
generativelanguage.googleapis.com
# Internal AI gateway
*.prod.ai-gateway.company.comAWS Bedrock (Multi-Region)
data:
whitelisted-domains: |
# AWS Bedrock endpoints
bedrock-runtime.us-east-1.amazonaws.com
bedrock-runtime.us-west-2.amazonaws.com
bedrock-runtime.eu-west-1.amazonaws.com
bedrock-runtime.ap-southeast-1.amazonaws.com
# Or allow all AWS Bedrock regions
amazonaws.comGoogle Vertex AI
data:
whitelisted-domains: |
# Vertex AI endpoints
us-central1-aiplatform.googleapis.com
europe-west4-aiplatform.googleapis.com
asia-southeast1-aiplatform.googleapis.com
# Or allow all Google AI services
googleapis.comSelf-Hosted / Custom Gateway
data:
whitelisted-domains: |
# Custom domain for self-hosted gateway
ai-gateway.company.com
llm-proxy.company.com
# Staging environment
ai-gateway.staging.company.com
# Multiple environments with wildcard
*.ai-gateway.company.comDisabling the Domain Whitelist
To disable domain restrictions and allow any HTTPS domain again:
helm upgrade ark-controller oci://ghcr.io/mckinsey/agents-at-scale-ark/charts/ark-controller \
--namespace ark-system \
--set modelUrlSecurity.domainWhitelist.enabled=false \
--reuse-valuesThe ConfigMap will be removed automatically, and the controller will allow any HTTPS domain.
Allowing Internal Endpoints (Private IP Allowlist)
By default, Ark blocks all private IP addresses (RFC 1918 ranges). Organizations with internal model gateways can enable an allowlist to permit specific private IP ranges.
When to Use Private IP Allowlist
Enable the private IP allowlist to:
- Connect to internal AI gateway services on private networks
- Use on-premises model hosting infrastructure
- Access models deployed in private subnets
- Integrate with internal proxy servers
Enabling the Private IP Allowlist
If you installed Ark using ark install, follow these steps:
Step 1: Enable the private IP allowlist
# Enable private IP allowlist via Helm upgrade
helm upgrade ark-controller oci://ghcr.io/mckinsey/agents-at-scale-ark/charts/ark-controller \
--namespace ark-system \
--set modelUrlSecurity.privateIPAllowlist.enabled=true \
--reuse-valuesThis creates a ConfigMap named model-url-security with example CIDR ranges (commented out).
Step 2: Configure allowed IP ranges
Edit the ConfigMap to specify which private IP ranges are allowed:
kubectl edit configmap model-url-security -n ark-systemUncomment and add your approved CIDR ranges:
data:
allowed-private-ips: |
# Example: Internal AI Gateway subnet
10.100.50.0/24
# Example: Specific gateway server
192.168.10.100/32Important: Use CIDR notation (e.g., 10.0.0.0/24 for subnets, 192.168.1.1/32 for single IPs). See CIDR Notation Examples below for more details.
Step 3: Restart the controller
kubectl rollout restart deployment ark-controller -n ark-systemStep 4: Verify the configuration
Try creating a model with an allowed private IP:
kubectl apply -f - <<EOF
apiVersion: ark.mckinsey.com/v1alpha1
kind: Model
metadata:
name: internal-gateway
spec:
provider: openai
model: gpt-4
config:
openai:
baseUrl:
value: "https://10.100.50.10/v1"
apiKey:
value: "test-key"
EOFThe model should be created successfully. Try an IP not in the allowlist to confirm blocking:
kubectl apply -f - <<EOF
apiVersion: ark.mckinsey.com/v1alpha1
kind: Model
metadata:
name: blocked-ip
spec:
provider: openai
model: gpt-4
config:
openai:
baseUrl:
value: "https://192.168.1.1/v1"
apiKey:
value: "test-key"
EOFYou should see an error:
Error: private IP addresses are not allowed: 192.168.1.1CIDR Notation Examples
# Single IP address
192.168.1.100/32
# Small subnet (256 addresses)
10.100.50.0/24
# Medium subnet (65,536 addresses)
172.16.0.0/16
# Large subnet (16,777,216 addresses)
10.0.0.0/8Security Considerations
⚠️ Important Security Notes:
- Loopback addresses (127.0.0.0/8) are always blocked - even if added to the allowlist
- Metadata service IPs (169.254.0.0/16) are always blocked - even if added to the allowlist
- Only add IP ranges you trust and control
- Use the smallest CIDR range necessary (prefer
/32for single hosts,/24for small subnets) - Regularly audit and review allowed ranges
Disabling the Private IP Allowlist
To disable and block all private IPs again:
helm upgrade ark-controller oci://ghcr.io/mckinsey/agents-at-scale-ark/charts/ark-controller \
--namespace ark-system \
--set modelUrlSecurity.privateIPAllowlist.enabled=false \
--reuse-valuesThe ConfigMap will be removed automatically, and the controller will block all private IP addresses.