fix(config): strip ASCII control characters from env values before writing to .env - #40887
Open
yubingz wants to merge 2 commits into
Open
fix(config): strip ASCII control characters from env values before writing to .env#40887yubingz wants to merge 2 commits into
yubingz wants to merge 2 commits into
Conversation
…iting to .env Fixes NousResearch#40840 Problem: On Windows, pressing ESC/arrow keys during CLI prompts inserts ANSI control characters (e.g. \x1b, \x1b[A) into input. These characters pass through prompt() → save_env_value() and get written to .env, silently corrupting configuration. A corrupted SEARXNG_URL (for example) causes web_search to permanently fail with no clear error message. Root cause: - Windows input() returns raw escape sequences on ESC/arrow key presses - prompt() only calls .strip() which does not filter control characters - save_env_value() strips non-ASCII but ESC (0x1b) is valid ASCII - No URL prefix validation in _configure_provider() Fix (three-layer defense): 1. Add _strip_control_chars() in config.py — strips C0/C1 control chars while preserving TAB (0x09) used as delimiter by some tools 2. Call _strip_control_chars() in save_env_value() before writing to .env 3. Add http(s):// prefix validation in _configure_provider() for _URL/_HOST/_ENDPOINT environment variables Tests: - 14 new tests in test_control_char_stripping.py - All 151 tests pass, 0 regressions
yubingz
force-pushed
the
fix/strip-control-chars-env-values
branch
from
June 26, 2026 14:56
700c3a6 to
f8ad548
Compare
This was referenced Jun 30, 2026
teknium1
reviewed
Jul 14, 2026
teknium1
left a comment
Contributor
There was a problem hiding this comment.
Thanks for addressing a real Windows configuration-corruption path. Current main still writes all ASCII controls other than LF/CR through save_env_value() (hermes_cli/config.py:7554-7618), while the shared non-secret prompt uses raw input() plus .strip() (hermes_cli/cli_output.py:63-65).
Problems
tests/hermes_cli/test_control_char_stripping.py:125,:143, and:160only inspect the result underif env_path.exists(). Those tests pass if the writer produces no.envfile, so they do not prove the persistence behavior.- The new URL-validation/retry branch in
hermes_cli/tools_config.py:3084-3101has no regression test. The current SearXNG plugin exposesSEARXNG_URLthrough this exact provider flow (plugins/web/searxng/provider.py:141-152).
Suggested changes
- Assert the file exists unconditionally, verify its saved value, and verify the process environment is sanitized too.
- Add a provider-flow test proving bare ESC is not saved and a valid
http(s)retry is accepted.
Automated hermes-sweeper review.
| save_env_value("SEARXNG_URL", "\x1b") | ||
|
|
||
| # The value written to .env should be empty (ESC stripped) | ||
| if env_path.exists(): |
Contributor
There was a problem hiding this comment.
This conditional makes the integration test pass if save_env_value() returns without creating .env. Assert env_path.exists() unconditionally before reading it, then verify the persisted value (and ideally os.environ); the identical guards below should be changed too.
…gression tests - Assert env_path.exists() unconditionally in all integration tests (previous `if env_path.exists()` guards let tests pass without proving persistence behavior) - Verify os.environ is sanitized after save_env_value - Add TestProviderFlowUrlValidation class covering URL validation in _configure_provider: bare ESC rejection, valid retry acceptance, and scheme-less URL passthrough Addresses review feedback on PR NousResearch#40887.
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #40840
Problem
On Windows, pressing ESC or arrow keys during CLI prompts (
hermes setup) inserts raw ANSI control characters (e.g.\x1b,\x1b[A) into input. These characters pass throughprompt()→save_env_value()and get written to.env, silently corrupting configuration.For example, a corrupted
SEARXNG_URLlikehttp://\x1blocalhost:8888causes web_search to permanently fail with no clear error message — the user has no idea their config is broken.Root Cause
input()returns raw escape sequences on ESC/arrow key pressesprompt()only calls.strip()which does not filter control characterssave_env_value()strips non-ASCII but ESC (0x1b) is valid ASCII — it passes through_configure_provider()to catch malformed valuesFix: Three-Layer Defense
Layer 1 — Input Sanitization (
config.py):_strip_control_chars(): strips C0 (0x00–0x1F except TAB 0x09) and C1 (0x80–0x9F) control characterssave_env_value()before writing to.env— single point of defense for all env writesLayer 2 — Business Validation (
tools_config.py):_configure_provider()for env vars ending in_URL,_HOST, or_ENDPOINTLayer 3 — Regression Safety:
test_control_char_stripping.pycovering ESC, arrow keys, mixed control chars, TAB preservation, etc.test_non_ascii_credential.pyto clarify scopeTest Results
Files Changed
hermes_cli/config.py_strip_control_chars()+ integration insave_env_value()hermes_cli/tools_config.py_configure_provider()tests/hermes_cli/test_control_char_stripping.pytests/hermes_cli/test_non_ascii_credential.py