feat: implement sensitive field masking in configuration management - #63
Merged
Conversation
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.
The
GET /api/configendpoint (and related config endpoints) returned the fullAppConfigviamodel_dump()without filtering sensitive fields, exposingapi.auth.api_keys,analysis.cve.nvd_api_key, andanalysis.cve.vulners_api_keyin plaintext to any authenticated user.Centralizes sensitive-field sanitization in
ConfigServiceso 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_SENSITIVE_FIELDSconstant 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.is_sensitive_key(key)public utility function for use by CLI._sanitize_config_dict()static method that recursively replaces sensitive values with"***"(lists become["***", ...],NonestaysNone)._sanitize_value()static method for single-value masking inget().get_all(),get_section(),get(), andload().set()to avoid leaking values in logs.export_config()andsave()intentionally keep real values — the export/save are local operations.src/ciberwebscan/cli/commands/config.pyis_sensitive_keyfromconfig_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.pyTestIsSensitiveKey(7 tests): verifiesis_sensitive_keyfor known sensitive paths, non-sensitive paths, and leaf-pattern matching.TestGetAllSanitization(4 tests): verifiesget_all()masksapi_keys,nvd_api_key,vulners_api_keyand preserves non-sensitive values.TestGetSectionSanitization(3 tests): verifiesget_section()masks sensitive fields inapiandanalysissections.TestGetSanitization(3 tests): verifiesget()masks sensitive values and defaults.TestLoadSanitization(1 test): verifiesload()masks sensitive fields.TestExportPreservesValues(1 test): verifiesexport_config()does NOT mask values.tests/unit/api/routes/test_config_routes.pyTestSensitiveFieldMaskingclass (3 tests): verifiesGET /api/config,GET /api/config/sections/{section}, andGET /api/config/valuereturn masked sensitive fields in the HTTP response.What is masked
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.