← Back to PRs

#21901: fix: guard writeConfigFile against persisting redaction sentinels

by Protocol-zero-0 open 2026-02-20 14:15 View on GitHub →
docs size: XS
## Summary Closes #18102. `writeConfigFile` had no safety check for the `__OPENCLAW_REDACTED__` redaction sentinel. While the gateway's config write handlers (`config.set`, `config.apply`, `config.patch`) call `restoreRedactedValues` before writing, other callers such as `doctor --fix` pass config objects directly to `writeConfigFile` without sentinel detection. If a redacted placeholder ever reached the write path, it would be serialized to disk, permanently destroying the original credential. This PR adds a **universal pre-write guard** inside `writeConfigFile` that: - Scans the final serialized JSON for `REDACTED_SENTINEL` after all transformations (merge-patch, validation, env-var restoration) - Throws with a descriptive error **before any file I/O**, keeping the on-disk config intact - Logs the blocked write via `deps.logger.error` for forensic visibility This protects **all** callers of `writeConfigFile` (doctor, onboarding, security fix, CLI config set, etc.), not just the gateway path. ## TL;DR for maintainers One sentinel string check (`json.includes(REDACTED_SENTINEL)`) right after `JSON.stringify` and before any disk write. ~15 lines of guard code + ~30 lines of test. Zero behaviour change for configs that don't contain the sentinel. ## Test plan - [x] New test: `writeConfigFile` rejects a config where `botToken` is set to `__OPENCLAW_REDACTED__` - [x] New test: on-disk config file is verified unchanged after the rejected write - [x] All existing `io.write-config.test.ts` tests pass (9/9) - [x] `redact-snapshot.test.ts` tests pass (57/57) - [x] `env-preserve-io.test.ts` tests pass (4/4) <!-- AI-assisted (protocol-zero + Claude) --> Made with [Cursor](https://cursor.com) <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR adds a universal pre-write guard to prevent the redaction sentinel `__OPENCLAW_REDACTED__` from being persisted to disk. While the gateway's config handlers already call `restoreRedactedValues` before writing, other code paths like `doctor --fix` pass config objects directly to `writeConfigFile` without sentinel detection. The fix adds a simple string check after `JSON.stringify` and before any file I/O. If the sentinel is found, the function logs an error and throws, keeping the on-disk config unchanged. - Prevents credential destruction across all `writeConfigFile` callers - Test verifies both rejection and disk preservation - Zero behavior change for configs without the sentinel <h3>Confidence Score: 5/5</h3> - This PR is safe to merge with minimal risk - The change is a defensive guard that only throws when a bug would otherwise destroy credentials. The implementation is simple (a string check after JSON.stringify), well-tested (verifies rejection and disk preservation), and cannot introduce regressions since it only activates when the sentinel is present (which should never happen in valid flows). The fix protects all writeConfigFile callers universally. - No files require special attention <sub>Last reviewed commit: 8e87d93</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs