Network
Who may reach Veefore, where Veefore may reach, and the six guards on the egress path.
Two directions, two different sets of controls.
#Inbound — who may reach Veefore
#IP allow and deny rules
bashcurl -s $CP/v1/admin/networks -H "Authorization: Bearer $KEY"
Requires network:read and network:update. A request from a disallowed
network is refused with NETWORK_RESTRICTED.
Test from outside before you rely on it
An allow-list that excludes your own egress address locks everyone out, including whoever would fix it.
Add the new range, verify from it, then remove the old one. In that order.
Most useful on the control plane, where the set of legitimate sources is small and known: your office ranges, your VPN, your CI. The gateway is different — agents may run anywhere, and an allow-list there is often more restriction than you can maintain.
#Separate ingresses
text ingress: console + control plane ingress: gateway
/v1/* only /gateway/v1/* only
│ │
people, CLI, CI agents
│
PostgreSQL (private)
Do not expose `/v1/*` where agents can reach it
The control plane is where policies are activated, credentials are registered and delegations are created. It has no business being reachable from wherever your agents run.
Correspondingly, do not expose /gateway/v1/* on the human-facing ingress.
There is no reason for a browser to reach it.
This is the control that makes the plane split worth having. → Deployment
The gateway exposes exactly two things publicly: /gateway/v1/* and
/.well-known/veefore-platform-key.
#CORS
iniCORS_ALLOWED_ORIGINS=https://console.example.com
Exact origins, comma-separated. A mismatch makes the console appear completely broken with no useful error in the UI — check the browser's network tab before anything else.
#TLS
Terminate at your ingress; both planes speak HTTP behind it. veefore doctor
reports a plane reachable over plaintext HTTP on a non-loopback host as a
finding.
#Outbound — where Veefore may reach
Real egress happens only when GATEWAY_ALLOW_REAL_EGRESS=true and the tool kind
is HTTP. Six guards apply at the egress boundary — after policy, after
approval, after the credential is leased, immediately before bytes leave the
process.
| Guard | Refusal |
|---|---|
Tool kind must be HTTP |
Otherwise the simulated runtime runs |
endpoint_url must be set |
UNPROCESSABLE |
Host must be in this tool's own destination_allowlist |
DESTINATION_BLOCKED |
| HTTPS required unless the host is loopback | DESTINATION_BLOCKED |
redirect: 'error' — redirects are never followed |
Execution fails |
Timeout at GATEWAY_EGRESS_TIMEOUT_MS, 15s |
EXECUTION_TIMEOUT |
Plus a per-tool circuit breaker: five consecutive failures opens it for 20 seconds, so one broken downstream cannot consume the gateway's capacity.
Redirects are refused, not followed
Following a redirect is how an allowlisted host becomes a request to a host that was never allowlisted. That is server-side request forgery with extra steps, and the only safe handling is to refuse.
If your downstream redirects, point endpoint_url at the final location.
The allowlist is checked twice
Once in the pipeline, once at the egress boundary against the tool's own list.
The second check is what protects you if the endpoint is edited later, or if a code path reaches execution without the first check having run. Defence in depth applied to one specific, high-consequence decision.
#Policy on destinations
json{
"id": "rule-destination-allowlist",
"name": "Only approved payment hosts",
"priority": 860,
"enabled": true,
"when": {
"kind": "group",
"id": "g-destination",
"operator": "and",
"children": [
{
"kind": "condition",
"id": "c-cap",
"field": "capability",
"operator": "starts_with",
"value": "refund."
},
{
"kind": "condition",
"id": "c-host",
"field": "destination.host",
"operator": "not_in",
"value": ["payments.internal.example.com", "payments-eu.internal.example.com"]
}
]
},
"then": { "decision": "BLOCK", "reason": "Refunds may only reach approved payment hosts." }
}
Belt and braces with the tool's allowlist. The policy version also appears in
the action record with a reason you wrote, which is more useful in an
investigation than a generic DESTINATION_BLOCKED.
destination.risk_level is also available, so a high-risk destination can
require approval rather than being refused outright.
#Webhook delivery
Also egress, also gated by GATEWAY_ALLOW_REAL_EGRESS, also refuses redirects,
with a 10-second timeout.
With egress off, delivery is not attempted and is recorded as failed with an explicit reason — never reported as delivered. A delivery claimed as successful when nothing was sent would be a lie in the one record you would later rely on.
#Watch the destinations
The Risk Center shows what your agents actually contact, which is frequently not what anyone expected.
bashcurl -s $CP/v1/risk/overview -H "Authorization: Bearer $KEY"
Compare against your tools' allowlists. A destination appearing there that nobody intended is worth a conversation and probably a narrower allowlist.
UNUSUAL_DESTINATION is a risk signal, so a newly seen destination raises the
score and can be tested directly in a rule:
json{
"kind": "condition",
"id": "c-new-dest",
"field": "risk.signals",
"operator": "contains",
"value": "UNUSUAL_DESTINATION"
}
#Emergency: block a destination
bashcurl -X POST $CP/v1/security/emergency/execute \
-H "Authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{
"kind": "BLOCK_DESTINATION",
"target_id": "suspicious.example.com",
"reason": "Unexpected egress observed from finance-agent",
"confirm_blast_radius": true
}'
Reversible and immediate. Then fix the tools' allowlists, which is the durable fix.
#Checklist
- [ ] Separate ingresses for control plane and gateway
- [ ] Gateway exposes only
/gateway/v1/*and the well-known key - [ ] TLS terminated at both, no plaintext on a non-loopback host
- [ ]
CORS_ALLOWED_ORIGINSmatches exactly where the console is served - [ ] Database private to both planes
- [ ] IP restrictions on the control plane, tested from outside first
- [ ] Every tool's
destination_allowlistas narrow as the tool needs - [ ]
GATEWAY_ALLOW_REAL_EGRESSon deliberately, per environment - [ ] Destinations reviewed in the Risk Center weekly