CodeVetter · Repo Unpack · Risk map
ollama/ollama
Main risks: the API has no request authentication by default and can be bound to non-loopback hosts via OLLAMA_HOST; the server spawns subprocesses (llama-server, self runner, gpu probes) with model-derived arguments; startup blob pruning deletes on-disk data; registry push/pull signs with a local private key; and several middleware paths decompress/transform untrusted request bodies. Scheduler and runner state is intricate (eviction, OOM retry, panic on model mismatch during load).
- The REST API is unauthenticated; OLLAMA_HOST can bind it to 0.0.0.0 and OLLAMA_ORIGINS CORS allows wildcards/browser extensions, so any reachable origin can pull/delete/run models unless the operator restricts it (inferred)
- Subprocess attack surface: llama-server is exec'd with flags assembled from request/model options (num_ctx, -ngl, -t, chat templates); the runner binary path and env are constructed in startLlamaServer/SetupLlamaServerCommandEnv
- Startup performs destructive maintenance: PruneLayers, manifest.PruneDirectory and fixBlobs delete blobs/manifests under OLLAMA_MODELS; guarded only by OLLAMA_NOPRUNE and a 1h grace period for fresh blobs
- Private signing key ~/.ollama/id_ed25519 (0600) is generated on first serve and used by auth.Sign for registry token exchange; realm host is checked against original host to avoid token leakage cross-origin
- --insecure / registryOptions.Insecure permits plain-HTTP registry traffic (errInsecureProtocol exists but can be bypassed by request flag)
- Request-body decompression is capped at 20MB (maxDecompressedBodySize) in the OpenAI middleware — a decompression-bomb guard; other endpoints bind JSON directly via gin ShouldBindJSON without explicit size limits
- Scheduler contains a deliberate panic when the active load's ModelPath differs from the evicted-retry request — a crash-on-invariant-violation that takes down the whole server
- Secret hygiene in logs: filteredEnv redacts env values containing API/KEY/TOKEN/SECRET/PASSWORD/CREDENTIAL/AUTH before logging subprocess env, but only CUDA_/ROCR_/ROCM_/HIP_/HSA_/GGML_/PATH/LD_LIBRARY_PATH/DYLD_LIBRARY_PATH keys are logged at all
- Codex desktop proxy restricts to loopback requests (isLoopbackRequest) and websocket upgrades are special-cased; misconfiguration here would expose upstream proxying on the shared listener
- Runner stream parsing bounds single response lines at 8MB (llamaServerStreamMaxBufferSize); unbounded growth in a misbehaving subprocess is otherwise handled only via HasExited/ping timeouts
- Legacy/removed features linger as explicit errors: LoRA adapters rejected (errAdaptersUnsupported), typical_p rejected, `useClient2` experiment warns-and-continues; dead flags like --experimental are hidden no-ops
- Blast radius: a single Scheduler serializes all model loads (activeLoading) so a stuck subprocess load stalls every inference request; queue overflow surfaces as ErrMaxQueue (OLLAMA_MAX_QUEUE default 512)