security: close config trust-boundary gaps and gate completion loader
Merged
JE
4mo ago+3642+3642+0123456789012345678901234567890123456789-169-169-012345678901234567890123456789
Close config trust-boundary gaps and gate the completion loader
(Threat: T2 malicious repo/parent-dir .basecamp/config.json; cleartext key leak.)
The existing untrusted guard already gates base_url/profiles/llm_provider/llm_endpoint/llm_api_key. This closes the siblings that slipped through:
cache_dir/cache_enabled— an untrusted repo config could redirect every cache write (completion, resilience, TUI workspace, recents, traces) to any user-writable path. Now trust-gated; accepted values arefilepath.Cleaned.llm_model— trust-gated (silent paid-model substitution).llm_max_concurrent/llm_token_budget— trust-gated (paid-LLM cost amplification).llm_endpoint— scheme-validated on accept (rejectsfile://etc.). HTTPS enforcement (so anhttp://endpoint can't leakllm_api_keyin cleartext) is applied at consumption viasummarize.ValidateEndpointinworkspace.NewSession— not at startup inroot.go— so a badllm_endpointcan't brick unrelated commands that never use it.- Completion loader (
completion/cache.go,completer.go) — repo/local profile loading now goes through the sameTrustStore.IsTrustedcheck as the main config; completion descriptions are stripped of control chars.
Tests
config_test.go adds reject-from-local / accept-from-global / llm_endpoint-scheme cases.
Part 4/6 of the stacked security series. Base: security/03-oauth-hardening. (Shares root.go with part 5 — hence the stack ordering.)
📚 Stack (merge bottom-up)
- #478 — reject foreign-host URLs in
api(basemain) - #479 — strip ANSI/OSC escapes from output
- #480 — harden OAuth discovery / token endpoints
- #481 — close config trust-boundary gaps + completion gate
- #482 — tighten config-dir perms + plugin scope argv
- #483 — bump toolchain/x-net + CI gates
Each is independent except #482 depends on #481 (shared root.go). #478 can land first/alone.