Skip to content

QWEN_CODE_SYSTEM_SETTINGS_PATH / QWEN_CODE_SYSTEM_DEFAULTS_PATH: env override is honored without any file-ownership check #13513

Description

@4ekuct25

QWEN_CODE_SYSTEM_SETTINGS_PATH / QWEN_CODE_SYSTEM_DEFAULTS_PATH: env override is honored without any file-ownership check

Affected: qwen-code v0.24.7 (verified; the same getSystemSettingsPath() shape is present in the 0.24.x bundles)

What

getSystemSettingsPath() (same for getSystemDefaultsPath()) reads the
QWEN_CODE_SYSTEM_SETTINGS_PATH / QWEN_CODE_SYSTEM_DEFAULTS_PATH environment
variables and, if set, returns that path unconditionally — the returned file
becomes the top system settings merge layer.

The real system settings location is a root/admin-only writable path
(/Library/Application Support/QwenCode/settings.json on macOS,
%ProgramData%\qwen-code\settings.json on Windows, /etc/qwen-code/ on
Linux). The whole point of that placement is that only the OS administrator can
set system-level settings (model provider, baseUrl, etc.). The env override
removes that trust boundary: any local user who can set environment
variables for a qwen process can point the CLI at an arbitrary file they own
and gain system-settings authority
— no elevation, no admin rights needed.

Impact

System settings control model provider selection and model.baseUrl. An
attacker who can influence the environment of a qwen process (shared accounts,
parent launchers, cron wrappers, IDE terminal environments, any env
injection) can:

  1. Override which model provider is used — including defeating
    organization-managed provider lockdowns;
  2. Route model traffic (and the configured API key) to an external endpoint.

A provider entry without baseUrl is accepted by the config, and the CLI
then uses the public default endpoint of that authType, so step 2 does not
require the attacker to know or type any URL.

Reproduction (v0.24.7)

  1. Create a user-owned file, e.g. /tmp/sys.json:
{
  "model": { "name": "x", "authType": "openai" },
  "modelProviders": { "openai": [ { "id": "x" } ] }
}
  1. Run with the override and an env API key for the authType:
QWEN_CODE_SYSTEM_SETTINGS_PATH=/tmp/sys.json QWEN_API_KEY=whatever qwen -p "ping"
  1. The request is sent to the public default endpoint for the openai authType
    (observed: api.dashscope.aliyuncs.com), not to the configured/managed
    endpoint.

Control: the same file with an explicit external baseUrl is also honored —
both shapes work, i.e. the gate on explicit baseUrl does not imply a gate on
the file origin.

Suggested behavior

Treat an env-supplied system settings path with the same trust as the real
system path. Minimal options (any one):

  • Honor the override only if the file is a regular file (lstat, not a
    symlink) owned by root
    (or the equivalent admin group on Windows — e.g.
    under C:\ProgramData\qwen-code\); otherwise fall back to the default path
    and log a warning;
  • or do not allow the env override to be used for the system layer at all
    (keep it, if needed, for a dedicated dev/test flag).

Happy to provide more detail on the merge-layer precedence if useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    category/securitySecurity and privacypriority/P3Low - Minor, cosmetic, nice-to-fix issuesscope/settingsSettings and preferencestype/bugSomething isn't working as expected

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions