Skip to main content

LocalAI trust_remote_code gate (R-098)

trust_remote_code=True lets a fetched model repo ship and execute arbitrary Python at load time (AutoTokenizer / vLLM custom code). That is the classic "model repo is the attack vector" hole: the repo is chosen by a client, so a client used to be able to flip the flag on. GSEC R-098 removes that.

Where the gate lives​

MOD does not deploy LocalAI. There is no LocalAI persistent stack, no model-catalog entry, and no compose-generation path in the API that produces a LocalAI container. LocalAI is deployed standalone by its own CORE/DockerContainers/LocalAI/docker-compose.yaml, and the gate is an env var on that deployment:

# CORE/DockerContainers/LocalAI/docker-compose.yaml
services:
api:
environment:
- MODELS_PATH=/models
# GSEC R-098: force trust_remote_code off unless an operator explicitly
# enables it. Fetched-model custom code will NOT run while this is false.
- LOCALAI_TRUST_REMOTE_CODE_ALLOWED=false

The vendored backends read that env in one place each:

BackendFileFunction
Python (all Python backends)CORE/DockerContainers/LocalAI/backend/python/mod_security.pyeffective_trust_remote_code(client_value)
GoCORE/DockerContainers/LocalAI/core/backend/options.goeffectiveTrustRemoteCode(cfgVal)

Both compute the same rule:

effective = admin_gate_is_on AND client_asked_for_it

So the client-supplied value (per-request or per-model config) can never enable remote code on its own. With the gate off, the effective value is always False regardless of what the client or model config asked for.

True-ish values accepted for the env: 1, true, yes, on (case-insensitive in the Python gate; the Go gate accepts those plus their upper/title-case forms). Anything else — including unset or empty — means off.

How an operator sets it​

  1. Default (recommended): leave it off. Nothing to do. The compose file ships =false, and an unset env is also off. Fetched-model custom code does not run.
  2. Opt in deliberately. Edit the LocalAI deployment's compose (or its .env, since that file is also read) to LOCALAI_TRUST_REMOTE_CODE_ALLOWED=true, then restart that LocalAI container. This is a decision about a specific model repo you trust; it is not a MOD platform setting and it does not touch any MOD worker, stack, or node container.
  3. Keep the platform setting honest. MOD does register models.localai_trust_remote_code_allowed (default False) in the platform-settings registry. It is advisory: it records the admin's intent for audit / conformance reporting, and is not bridged into any container env. If you flip the env in step 2, set the setting to True too so the recorded state matches the enforced state — otherwise the setting and the deployment disagree, and the setting is the one that will be read out of an audit.

Verifying​

Ask a LocalAI model config (or a request) for trust_remote_code=true:

  • Gate off → the backend loads with trust_remote_code=False; no repo code runs. This is the enforced behaviour you should see.
  • Gate on → the flag passes through as requested, and the repo's custom code executes. Treat that as a deliberate, per-repo exception.
  • models.require_pinned_revision (R-098) is the companion control on the model-weights fetch side: pin the repo to a commit/tag and record a sha256 manifest so a swapped-out file fails the deploy. That one is enforced by MOD (the weights fetcher is MOD-generated); the LocalAI one is not, because the deployment is not MOD-generated.