Skip to content

feat: implement sensitive field masking in configuration management - #63

Merged
HC-ONLINE merged 1 commit into
mainfrom
fix/config-sensitive-fields-mask
Sep 6, 2026
Merged

feat: implement sensitive field masking in configuration management#63
HC-ONLINE merged 1 commit into
mainfrom
fix/config-sensitive-fields-mask

Conversation

@HC-ONLINE

Copy link
Copy Markdown
Owner

The GET /api/config endpoint (and related config endpoints) returned the full AppConfig via model_dump() without filtering sensitive fields, exposing api.auth.api_keys, analysis.cve.nvd_api_key, and analysis.cve.vulners_api_key in plaintext to any authenticated user.

Centralizes sensitive-field sanitization in ConfigService so that all API and CLI read paths return masked values ("***") while preserving real values in disk writes (config file, exports).

Changes

src/ciberwebscan/services/config_service.py

  • Added _SENSITIVE_FIELDS constant listing dot-notation paths that must never be returned in plaintext: api.auth.api_keys, analysis.cve.nvd_api_key, analysis.cve.vulners_api_key.
  • Added is_sensitive_key(key) public utility function for use by CLI.
  • Added _sanitize_config_dict() static method that recursively replaces sensitive values with "***" (lists become ["***", ...], None stays None).
  • Added _sanitize_value() static method for single-value masking in get().
  • Applied sanitization in get_all(), get_section(), get(), and load().
  • Sanitized the log line in set() to avoid leaking values in logs.
  • export_config() and save() intentionally keep real values — the export/save are local operations.

src/ciberwebscan/cli/commands/config.py

  • Imported is_sensitive_key from config_service.
  • config get: displays "***" for sensitive values instead of the raw value.
  • config set: displays "***" in the success message for sensitive keys.

tests/unit/services/test_config_service.py

  • Added TestIsSensitiveKey (7 tests): verifies is_sensitive_key for known sensitive paths, non-sensitive paths, and leaf-pattern matching.
  • Added TestGetAllSanitization (4 tests): verifies get_all() masks api_keys, nvd_api_key, vulners_api_key and preserves non-sensitive values.
  • Added TestGetSectionSanitization (3 tests): verifies get_section() masks sensitive fields in api and analysis sections.
  • Added TestGetSanitization (3 tests): verifies get() masks sensitive values and defaults.
  • Added TestLoadSanitization (1 test): verifies load() masks sensitive fields.
  • Added TestExportPreservesValues (1 test): verifies export_config() does NOT mask values.

tests/unit/api/routes/test_config_routes.py

  • Added TestSensitiveFieldMasking class (3 tests): verifies GET /api/config, GET /api/config/sections/{section}, and GET /api/config/value return masked sensitive fields in the HTTP response.

What is masked

Field Before After
api.auth.api_keys ["key1", "key2"] ["***", "***"]
analysis.cve.nvd_api_key "abc123" "***"
analysis.cve.vulners_api_key "xyz789" "***"

What is NOT masked (intentional)

  • export_config() — exported files contain real values (user saves to their own disk).
  • save() — config file on disk retains real values.
  • set() — returns the value that was just written.
  • _get_all_keys() — only returns key names, not values.

Verification

ruff check . → All checks passed
ruff format --check . → 201 files already formatted
pyright → 0 errors, 0 warnings
pytest tests/unit/ → 1292 passed, 0 failed

Manual verification against running API and CLI confirmed all three sensitive fields are masked in every read path.

@HC-ONLINE
HC-ONLINE merged commit 585a93e into main Sep 6, 2026
0 of 3 checks passed
@HC-ONLINE
HC-ONLINE deleted the fix/config-sensitive-fields-mask branch September 6, 2026 16:35
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.

1 participant