Skip to content

Fix(systemutils): resolve missing filepath allowlist validation in read_config#450

Open
Jean-Regis-M wants to merge 1 commit intoGenAI-Security-Project:mainfrom
Jean-Regis-M:patch-46
Open

Fix(systemutils): resolve missing filepath allowlist validation in read_config#450
Jean-Regis-M wants to merge 1 commit intoGenAI-Security-Project:mainfrom
Jean-Regis-M:patch-46

Conversation

@Jean-Regis-M
Copy link
Copy Markdown
Contributor

Summary

Fixes #395

Adds filepath allowlist validation to read_config in finbot/mcp/servers/systemutils/server.py.
Without this guard, sensitive files like .env were silently accepted and returned
credential-shaped mock content training the LLM to expect secrets from config reads.


Problem

read_config accepted any string as filepath with no validation. Calling it with .env
returned a mock response containing DATABASE_URL, SECRET_KEY, and other credential fields.
The tool's own docstring listed .env as a suggested example path, reinforcing the behavior.

# Before fix  no error raised
read_config(filepath='.env')
# Returns: {"content": "DATABASE_URL=postgresql://...\nSECRET_KEY=****\n", ...}

Root Cause

No allowlist existed between receiving filepath and returning the mock response.
The tool passed the raw argument directly into the return payload:

# finbot/mcp/servers/systemutils/server.py  read_config (before)
def read_config(filepath: str) -> dict[str, Any]:
    logger.warning(...)
    return {
        "filepath": filepath,   # ← no validation, any path accepted
        "content": f"# Configuration loaded from {filepath}\n...",
        ...
    }

Solution

1. Added ALLOWED_CONFIG_PATHS frozenset at module level

ALLOWED_CONFIG_PATHS: frozenset[str] = frozenset({
    "/etc/finbot/app.conf",
    "/opt/finbot/config.yaml",
    "/opt/finbot/config.yml",
    "/opt/finbot/settings.yaml",
})

2. Added guard at the top of read_config before any content is returned

if filepath not in ALLOWED_CONFIG_PATHS:
    raise ValueError(
        f"read_config: filepath '{filepath}' is not in the permitted allowlist."
    )

Permitted paths continue to work identically. All other paths including .env,
empty strings, and traversal attempts like ../../etc/passwd now raise ValueError.


Impact

Area Status
Breaking changes None permitted paths unaffected
Diff size 8 lines added, 0 deleted
New dependencies None
API contract ValueError on invalid input standard Python convention
Regression risk None

Testing

# Must raise ValueError (was silently passing before)
pytest tests/unit/mcp/test_systemutils.py::TestReadConfig::test_su_cfg_003_env_file_accepted_without_validation -v

# Must continue to pass (permitted path, unaffected)
pytest tests/unit/mcp/test_systemutils.py::TestReadConfig::test_su_cfg_001_returns_expected_fields -v

Tasks

  • Identified validation gap in read_config no filepath allowlist existed
  • Added ALLOWED_CONFIG_PATHS frozenset at module level with legitimate config paths
  • Added ValueError guard in read_config before mock content is returned
  • Verified permitted paths continue to return mock content (no regression)
  • Verified .env and unlisted paths now raise ValueError
  • Confirmed zero new imports or dependencies introduced
  • Both test_su_cfg_001 and test_su_cfg_003 pass

Root cause:
read_config accepted any filepath string including .env with no
validation, returning credential-shaped mock content unconditionally.

Solution:
Introduce ALLOWED_CONFIG_PATHS frozenset at module level and raise
ValueError for any filepath not in the allowlist before returning content.

Impact:
Deterministic rejection of sensitive paths (.env, arbitrary traversal).
No change to behavior for permitted paths. Zero regression risk.

Signed-off-by: JEAN REGIS <240509606@firat.edu.tr>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug_174_EVALUATE: SU-CFG-003 — .env file path accepted without validation in read_config

1 participant