Repository navigation
Bug: Ollama provider discovery is blocked by destination policy in OpenCode 2.7.43 #758
Description
Client or integration
Claude Code
Area
CLI
Summary
I'm using OpenCode 2.7.43 with Ollama as the default provider under Ubuntu 24.04 WSL2.
Although the Ollama provider is correctly configured and Ollama is reachable, ocx sync refuses to discover local models because the destination policy blocks loopback/localhost addresses.
As a result:
No Ollama models are added to the catalog.
/v1/models only exposes OpenAI models.
Claude model aliases (for example claude-opus-4-8-rox) are forwarded to the OpenAI backend instead of Ollama.
Claude Code then fails because OpenAI rejects those model names.
Expected behavior:
The built-in Ollama provider should be allowed to discover models from the configured local endpoint.
Reproduction
Reproduction
Environment
OpenCode: 2.7.43
Installed via:
npm install -g @bitkyc08/opencodex
Ubuntu 24.04 WSL2
Ollama running locally
Configuration:
{
"defaultProvider": "ollama",
"providers": {
"ollama": {
"adapter": "openai-chat",
"baseUrl": "http://127.0.0.1:11434/v1"
}
}
}
Verify Ollama is reachable:
curl http://127.0.0.1:11434/v1/models
This correctly returns my installed models.
Run:
ocx sync
Result:
Provider model discovery for "ollama" was blocked by destination policy:
provider URL targets loopback address
Changing the URL to http://localhost:11434/v1 changes the message to:
provider URL targets localhost destination
but the behavior is identical.
Expected Result
ocx sync should successfully discover the models exposed by the configured Ollama endpoint and include them in the OpenCode model catalog.
Actual Result
Model discovery is blocked.
curl http://127.0.0.1:10100/v1/models
returns only OpenAI models.
Claude requests are then routed to OpenAI instead of Ollama.
Example proxy log:
400 openai/claude-opus-4-8-rox
The OpenAI backend responds:
The 'claude-opus-4-8-rox' model is not supported when using Codex with a ChatGPT account.
Additional Information
The provider appears to be configured correctly:
ocx provider show ollama
returns:
Provider: ollama (default)
adapter: openai-chat
baseUrl: http://127.0.0.1:11434/v1
The installed source also registers the built-in Ollama provider with:
allowPrivateNetworkByDefault: true
located in:
src/providers/registry.ts
However, model discovery is still rejected by the destination policy during ocx sync.
Version
2.7.43
Operating system
Windows 11 24H2
Provider and model
No response
Logs or error output
nbpacio@COOLMAN-PC:~$ ocx config show
{
"port": 10100,
"providers": {
"openai": {
"adapter": "openai-responses",
"baseUrl": "https://chatgpt.com/backend-api/codex",
"codexAccountMode": "pool",
"authMode": "forward"
},
"ollama": {
"adapter": "openai-chat",
"baseUrl": "http://127.0.0.1:11434/v1"
}
},
"defaultProvider": "ollama",
"openaiProviderTierVersion": 2,
"multiAgentGuidanceEnabled": true,
"codexShimAutoRestore": true,
"subagentModels": [
"gpt-5.5",
"gpt-5.6-sol",
"gpt-5.6-terra",
"gpt-5.6-luna",
"gpt-5.4-mini"
],
"websockets": false,
"codexAutoStart": true,
"activeCodexAccountId": "__main__"
}
nbpacio@COOLMAN-PC:~$ ocx sync
[opencodex] Provider model discovery for "ollama" was blocked by destination policy: provider URL targets loopback address [urlClass=provider-models, fallback=configured].
Pointed Codex's built-in openai provider at the opencodex proxy (openai_base_url).
Codex model catalog: /mnt/c/Users/nbpac/.codex/opencodex-catalog.json
Codex resume history: untouched (threads keep their native openai tag).
All models now route through opencodex proxy (like OpenRouter).
OpenAI models (gpt-5.5, etc.) are passed through to OpenAI.
Custom models route to their configured providers.
Fallback reference: /mnt/c/Users/nbpac/.codex/opencodex.config.toml
Target Codex home: /mnt/c/Users/[USER]/.codex
nbpacio@COOLMAN-PC:~$ ocx provider show ollama
Provider: ollama (default)
adapter: openai-chat
baseUrl: http://127.0.0.1:11434/v1
nbpacio@COOLMAN-PC:~$ curl http://127.0.0.1:11434/v1/models
{"object":"list","data":[{"id":"hf.co/tvall43/Qwen3.6-14B-A3B-FableVibes-GGUF:Q4_K_M","object":"model","created":1785333239,"owned_by":"tvall43"},{"id":"fervent_mcclintock/Gemma-3-12B-Instruct:Q4_K_M","object":"model","created":1785332957,"owned_by":"fervent_mcclintock"},{"id":"frob/mradermacher-Llama3.3-8B-Thinking-Heretic-Claude-4.5-Opus:q8_0","object":"model","created":1785332291,"owned_by":"frob"},{"id":"deepseek-r1:8b","object":"model","created":1785331986,"owned_by":"library"},{"id":"qcwind/qwen3-8b-instruct-Q4-K-M:latest","object":"model","created":1785330826,"owned_by":"qcwind"}]}
nbpacio@COOLMAN-PC:~$ curl http://127.0.0.1:11434/v1/models
{"object":"list","data":[{"id":"hf.co/tvall43/Qwen3.6-14B-A3B-FableVibes-GGUF:Q4_K_M","object":"model","created":1785333239,"owned_by":"tvall43"},{"id":"fervent_mcclintock/Gemma-3-12B-Instruct:Q4_K_M","object":"model","created":1785332957,"owned_by":"fervent_mcclintock"},{"id":"frob/mradermacher-Llama3.3-8B-Thinking-Heretic-Claude-4.5-Opus:q8_0","object":"model","created":1785332291,"owned_by":"frob"},{"id":"deepseek-r1:8b","object":"model","created":1785331986,"owned_by":"library"},{"id":"qcwind/qwen3-8b-instruct-Q4-K-M:latest","object":"model","created":1785330826,"owned_by":"qcwind"}]}
nbpacio@COOLMAN-PC:~$Screenshots and supporting files
No response
Redacted configuration
Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
github-actions commentedon Jul 30, 2026
Automated translation bookkeeping — detected language: unknown.
Wibias commentedon Jul 30, 2026
[shipping-github] Research review
Claim: Built-in Ollama discovery is blocked by destination policy despite
allowPrivateNetworkByDefault: true.Checked against: dev@be177ea5
providerOutboundGet→resolvePublicAddresseshonors onlyprovider.allowPrivateNetwork; registryallowPrivateNetworkByDefaultis not applied on that path, so loopback Ollama/modelsis blockedallowPrivateNetworkignored for discovery); this report is the built-in Ollama default gapEvidence: Registry marks ollama with
allowPrivateNetworkByDefault: true(src/providers/registry.ts).providerDestinationConfigErrorconsults the registry, butsrc/lib/provider-outbound.tspassesallowPrivateNetwork: provider.allowPrivateNetworkintoresolvePublicAddresses, which only admits private when that flag istrue. Saved configs typically omit the flag. Workaround: setallowPrivateNetwork: trueon the provider.Gaps: Did not run live
ocx syncagainst a local Ollama in this session.Wibias commentedon Jul 30, 2026
[shipping-github] Security review
Checked against: dev@be177ea5
Scope: Provider model-discovery destination policy vs registry
allowPrivateNetworkByDefault(Ollama/local providers)provider.allowPrivateNetwork === true. That is over-restrictive for built-ins that declareallowPrivateNetworkByDefault, not an open SSRF hole.allowPrivateNetwork: truefor arbitrary providers, or that admits metadata/link-local/unspecified destinations, would re-open discovery-time SSRF.Summary: No exploitable bypass found on tip. Treat the patch as security-sensitive destination-policy wiring.
Residual: Custom providers pointing at private ranges still need explicit user opt-in after the fix.
Wibias commentedon Jul 30, 2026
[shipping-github] Opened PR #775 to address this.
lidge-jun commentedon Jul 31, 2026
Fixed on
codex/260731-pr-merge-round(3f7a5045).The cause was one provider being judged by two boundaries that disagreed. Ollama's registry entry carries
allowPrivateNetworkByDefault— a local model server is what it is — and config validation honoured that. Outbound discovery did not: it read only the operator'sallowPrivateNetworkflag (src/lib/provider-outbound.ts), so a stock Ollama provider validated cleanly and was then refused at the fetch.Both boundaries now use the same permission helper. Nothing new is granted: a provider with neither a registry default nor an explicit flag is denied exactly as before, and only the three entries that are local by definition (Ollama, vLLM, LM Studio) carry the default.
The SSRF exclusions are untouched, and they sit in front of this permission rather than inside it — metadata, link-local and unspecified destinations are rejected before any private-network question is asked. The regression tests assert that for Ollama specifically, since it is the provider that gained access; if those exclusions were ever folded into the same check,
169.254.169.254is where it would show, and an SSRF there leaks cloud instance credentials.Worth recording how the tests got there, because the first version was useless. They initially drove the injected-executor branch, and reverting the fix did not fail them — that branch delegates to a helper which already consulted the registry, so they never touched the defect. Real discovery has no injected executor and goes through the pinned transport. They now inject
resolveAddressesthere and assert the permission value it actually receives. Reverting the fix fails 1 of 6; restoring passes 6/6.This touches a destination-security boundary, so it wants a maintainer's review before it reaches
dev, even though it only re-uses a permission the config layer already grants. PR #775 proposed the same architecture and reached the same conclusion independently.The branch merges into
devand ships once the optimization work in flight there completes.fix(providers): honour the registry private-network default at the fe…
fix: address issue lidge-jun#758
docs(plan): record the round outcome, including what was wrong
merge: the 260731 PR round into dev
docs(plan): name the six fixes we can actually land, in dependency order
fix: address issue lidge-jun#758
fix(providers): honour the registry private-network default at the fe…
docs(plan): record the round outcome, including what was wrong
merge: the 260731 PR round into dev
docs(plan): name the six fixes we can actually land, in dependency order