Skip to content

fix(runtime): block separator-less secret env names from WASM guests#6316

Merged
houko merged 1 commit into
mainfrom
fix-wasm-env-blocklist-suffix
Jun 25, 2026
Merged

fix(runtime): block separator-less secret env names from WASM guests#6316
houko merged 1 commit into
mainfrom
fix-wasm-env-blocklist-suffix

Conversation

@houko

@houko houko commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

host_env_read (the WASM host function backing EnvRead) suppresses secret-looking environment variables before handing them to a guest, so that a plugin granted EnvRead("*") cannot read ANTHROPIC_API_KEY, MY_TOKEN, etc.
The match is a both-sides word-boundary check, deliberately tightened (over a plain contains) so benign config like MONKEYHOUSE, KEYBOARD_LAYOUT, TOKENIZER_OPTS stays readable.

The gap: a separator-less secret name glues the credential word to the end with no boundary — APIKEY, MYTOKEN, DBPASSWORD, GHTOKEN, STRIPEKEY, ALGOLIA_APIKEY.
For APIKEY, KEY starts at index 3 with the preceding byte I (alphanumeric), so the both-sides rule rejects the match and the variable is not blocked — host_env_read then returns the real secret to the guest.
This is a defense-in-depth bypass for any plugin holding a wildcard EnvRead capability.

Changes

  • crates/librefang-runtime/src/host_functions.rsis_blocked_env_var now matches upper.ends_with(sub) || has_word_boundary_substring(&upper, sub).
    The suffix arm catches the separator-less names; the existing both-sides arm is unchanged.
  • A starts_with arm is intentionally omitted: it would re-flag TOKENIZER_OPTS / PRIVATELABEL_NAME / PASSWORDLIST_FILE, the exact benign-config false positives the both-sides rule was written to allow.
  • Trade-off documented in code: the suffix rule over-blocks a benign name ending in a secret word (TURKEY, MONKEY), which is the safe direction — the guest gets null, never a credential.

Verification

  • cargo clippy -p librefang-runtime --lib -- -D warnings — passed, zero warnings.
  • cargo test -p librefang-runtime --lib is_blocked_env_var — 2 passed, 0 failed. The extended test_is_blocked_env_var_word_boundary now asserts APIKEY / MYTOKEN / DBPASSWORD / GHTOKEN / STRIPEKEY / ALGOLIA_APIKEY are blocked, while the existing benign negatives (MONKEYHOUSE, KEYBOARD_LAYOUT, TOKENIZER_OPTS, PRIVATELABEL_NAME, PASSWORDLIST_FILE, MASTERKEYBOARD) still pass.
  • cargo fmt -p librefang-runtime --check — clean.

(Run in the repo's Dockerfile.rust-dev image against an isolated target volume, per the project's no-local-cargo rule.)

Context

Surfaced by a repo-wide security audit. Filed as its own PR (one of several from that pass); it is self-contained in the WASM-sandbox host-function layer and unrelated to the other findings.

@github-actions github-actions Bot added size/S 10-49 lines changed area/docs Documentation and guides area/runtime Agent loop, LLM drivers, WASM sandbox labels Jun 25, 2026
@github-actions github-actions Bot added the has-conflicts PR has merge conflicts that need resolution label Jun 25, 2026
host_env_read suppresses secret-looking env vars (API_KEY, MY_TOKEN, ...) before returning them to a WASM guest, using a both-sides word-boundary match that was deliberately tightened so benign config like MONKEYHOUSE / TOKENIZER_OPTS stays readable by an EnvRead("*") plugin. But a separator-less name such as APIKEY, MYTOKEN, DBPASSWORD or ALGOLIA_APIKEY glues the credential word to the end with no boundary, so the both-sides check missed it and host_env_read returned the real value to any guest holding a wildcard EnvRead capability.

Add a suffix rule: any name ending in a blocked secret word (KEY / SECRET / TOKEN / PASSWORD / CREDENTIAL / PRIVATE) is now treated as a secret. This errs toward over-blocking (a benign TURKEY / MONKEY ending in KEY is also suppressed), which is the safe direction here — the guest receives null, never a credential. A starts_with rule is deliberately NOT added: it would re-break TOKENIZER_OPTS / PRIVATELABEL_NAME / PASSWORDLIST_FILE, which legitimately begin with a blocked word.
@houko
houko force-pushed the fix-wasm-env-blocklist-suffix branch from 3d7cad1 to 07ef530 Compare June 25, 2026 13:16
@github-actions github-actions Bot added ready-for-review PR is ready for maintainer review and removed has-conflicts PR has merge conflicts that need resolution labels Jun 25, 2026
@houko
houko merged commit 3ebec2a into main Jun 25, 2026
31 checks passed
@houko
houko deleted the fix-wasm-env-blocklist-suffix branch June 25, 2026 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docs Documentation and guides area/runtime Agent loop, LLM drivers, WASM sandbox ready-for-review PR is ready for maintainer review size/S 10-49 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant