Skip to content

fix(env): fix os.getenv prefix collision bug in init_by_lua phase#13147

Open
currenjin wants to merge 1 commit intoapache:masterfrom
currenjin:master
Open

fix(env): fix os.getenv prefix collision bug in init_by_lua phase#13147
currenjin wants to merge 1 commit intoapache:masterfrom
currenjin:master

Conversation

@currenjin
Copy link
Copy Markdown

Problem

In OpenResty's init_by_lua phase, os.getenv() uses nginx's internal environment mechanism which performs prefix-based matching when env NAME=VALUE directives share a common prefix. This causes os.getenv() to return the shorter-named variable's value when the longer-named one is requested.

Example: with both KUBERNETES_CLIENT_TOKEN and KUBERNETES_CLIENT_TOKEN_FILE defined as env NAME=VALUE; directives, calling os.getenv("KUBERNETES_CLIENT_TOKEN_FILE") returns KUBERNETES_CLIENT_TOKEN's value when the shorter name appears first in the config.

Fixes #13055

Root cause

OpenResty's os.getenv in init_by_lua does not perform exact-match lookup when env NAME=VALUE; directives have a common prefix — the shorter name is matched first. In contrast, reading ffi.C.environ directly with Lua string operations (as _M.init() already does) produces a correctly keyed table.

Fix

  1. apisix/core/env.lua: After _M.init() populates apisix_env_vars from ffi.C.environ, override os.getenv with a wrapper that does exact table lookup. Falls back to the original os.getenv for variables set dynamically after startup (e.g., via core.os.setenv).

  2. apisix/init.lua: Move core.env.init() to be the first call in http_init(), ensuring the override is applied before any other code in init_by_lua can call os.getenv.

Tests

  • TEST 10: Verifies os.getenv returns correct values when shorter-prefix variable is declared first in nginx config.
  • TEST 11: Verifies os.getenv called inside init_by_lua (via extra_init_by_lua) returns correct values for prefix-colliding variables.

Risk / Compatibility

  • os.getenv is monkey-patched globally after _M.init(). Existing callers continue to work — the semantics are identical for non-colliding variable names.
  • Variables set dynamically via core.os.setenv fall back to the original os.getenv, so those are unaffected.
  • The ordering change in http_init is safe: core.env.init() has no dependencies on resolver or id initialization.

In OpenResty's init_by_lua phase, os.getenv() uses nginx's internal
environment mechanism which performs prefix-based matching when env
NAME=VALUE directives share a common prefix. This causes os.getenv()
to return the shorter-named variable's value when the longer-named one
is requested (e.g., KUBERNETES_CLIENT_TOKEN_FILE returns the value of
KUBERNETES_CLIENT_TOKEN).

The fix overrides os.getenv in _M.init() with a wrapper that uses
exact table lookup from apisix_env_vars (built correctly from
ffi.C.environ). Also moves core.env.init() to be the first call in
http_init() to ensure the override is applied before any other code
in init_by_lua can call os.getenv.

Fixes apache#13055
@dosubot dosubot bot added size:M This PR changes 30-99 lines, ignoring generated files. bug Something isn't working labels Apr 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: Environment variable with common prefix returns incorrect value in init_by_lua

1 participant