Repository navigation
feat(config): make Windows cache-dir DACL hardening configurable (env var + CLI config key) — opt-out for hosts where it breaks MoveFileExW #1624
Copy link
Copy link
Open
Labels
enhancementNew feature or requestNew feature or requestpriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.securitySecurity vulnerabilities, hardeningSecurity vulnerabilities, hardeningux/behaviorDisplay bugs, docs, adoption UXDisplay bugs, docs, adoption UXwindowsWindows-specific issuesWindows-specific issues
Description
Feature request
Make the Windows cache-directory DACL hardening configurable, via:
- CLI configuration:
codebase-memory-mcp config set windows-dacl-hardening false(persisted) - Environment variable:
CBM_SKIP_DACL_HARDENING=1(kill switch, overrides the config)
This is the opt-out path requested as fix option #2 in #1620 — on hosts where the protected owner-only DACL conflicts with local security policy (EDR/minifilter), indexing is currently impossible and there is no escape hatch.
Why this is needed (verified root cause, details in #1620)
- Since v0.9.1-rc.1 every CBM process re-applies a protected owner-only DACL to the cache dir at startup (
win_runtime_directory_secure,src/daemon/ipc.c:4121). - On some hosts,
MoveFileExW(MOVEFILE_REPLACE_EXISTING)returnsERROR_ACCESS_DENIEDinside protected-DACL directories (reproduced withcmd move /y, P/Invoke and synthetic dirs — independent of CBM). - CBM publishes the index DB via rename-replace (
publish_writer_output,src/sqlite_writer.c) → the pipeline fails silently → generic "Pipeline failed". - Proof: with the dir ACL in the normal inherited state, the identical run succeeds (
status:"indexed").
Analysis: points to modify
| Site | Function | Change |
|---|---|---|
src/main.c |
main_build_identity() |
Read effective setting (env > config) and gate the cbm_daemon_ipc_private_directory_secure() call |
src/daemon/ipc.c |
win_runtime_directory_secure() |
Skip the unconditional SetSecurityInfo(... PROTECTED_DACL_SECURITY_INFORMATION ...) when disabled |
src/daemon/ipc.c |
win_file_security_secure() validators |
When disabled, accept the OS-default (inherited) DACL instead of requiring the one-ACE owner-only form — otherwise the daemon fails closed at startup |
src/foundation/compat_fs.c |
cbm_windows_stamp_dir_owner() |
Skip the protected-DACL stamp on freshly created dirs when disabled |
src/ui/config.c |
CONFIG_KEYS[] |
Add windows-dacl-hardening (default true) — automatically supported by config list/get/set/reset |
Notes:
- Both sides must be gated. Disabling only the write side makes the strict validators reject the inherited DACL and the daemon refuses to start (fail-closed — observed while debugging Windows: index always fails with generic 'Pipeline failed' — protected-DACL cache dir breaks MoveFileExW(REPLACE_EXISTING) on this host #1620).
- Owner checks (
win_file_owner_secure) can stay active even when DACL hardening is off; the conflict is only with the protected-DACL shape, not with ownership validation. - The
--index-workerprocess inherits the behavior for free because it also passes throughmain_build_identity. - Precedence: env var > config value. The env var is read via
getenv(same pattern asCBM_CACHE_DIR,CBM_LOG_LEVEL); the config value viacbm_config_get(cfg, key, default)(same pattern asui_portetc.). The read must happen before the hardening call; the config DB lives in the cache dir, so there is no circular dependency.
Security tradeoff (for the record)
The protected DACL defends the daemon's cache/IPC boundary against other local users. Disabling it is safe on single-user machines (the affected use case) and not recommended on multi-user/terminal-server hosts — the config default stays true.
Testing suggestions
config set windows-dacl-hardening false→ index any repo →status:"indexed"(on an affected host; regression-check on a normal host that default behavior is unchanged)CBM_SKIP_DACL_HARDENING=1overridestruein config- Daemon startup: with the option off, no
ui.config.write_fail reason=atomic_publish, and the walk accepts the inherited DACL - Unit tests: gate the
win_file_security_securerelaxation path (tests exist intests/perMakefile.cbm)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or requestpriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.securitySecurity vulnerabilities, hardeningSecurity vulnerabilities, hardeningux/behaviorDisplay bugs, docs, adoption UXDisplay bugs, docs, adoption UXwindowsWindows-specific issuesWindows-specific issues
Activity
roosteer commentedon Aug 14, 2026
Implemented in PR #1649.
What shipped
CBM_SKIP_DACL_HARDENING=1— effective from the very first run (read before any directory creation).windows-dacl-hardening(defaulttrue) viaconfig set/get/list/reset— effective from the second run (the store lives inside the cache dir).Key implementation note (tradeoff) — the unprotect supplies a real DACL (a copy of the parent directory's DACL) and clears
SE_DACL_PROTECTED. Passing a NULL pDacl withDACL_SECURITY_INFORMATIONwould create a NULL DACL (full access to everyone) per the SetSecurityInfo contract — avoided deliberately.Verification
roosteer commentedon Sep 1, 2026
Additional sanitized evidence supporting a configurable diagnostic/escape hatch:
index_repositoryattempt returns the generic pipeline failure after the supervised worker exits cleanly with code 0.full/fast, MCP/CLI, a normal source tree, and a three-file source directory with a short explicit project name.config listdoes not exposewindows-dacl-hardening, so the proposed switch is not available on this affected host.No repository paths, account/domain identifiers, SIDs, process IDs, or source details are included in this report.
DeusData commentedon Sep 1, 2026
Thank you for the fresh, sanitized v0.10.8 evidence. It strengthens the case for a supported diagnostic and escape hatch, while the manual inheritance experiment not changing the result means it does not yet isolate DACL hardening as the cause. Because any opt-out changes the local-user security boundary, we need more time to review the design. No further information is requested from you at this stage.
feat(config): make Windows cache-dir DACL hardening configurable
roosteer commentedon Sep 3, 2026
Additional sanitized v0.10.8 evidence has been consolidated in #1620: #1620 (comment)
It covers the still-silent inner writer-publication path, the native MoveFileExW ERROR_ACCESS_DENIED discriminator, and the results of the CBM_CACHE_DIR / CBM_RUNTIME_DIR workaround attempts on a managed-profile host. This is relevant here because the cache override retained the owner-only DACL and the profile-based runtime override was rejected before daemon startup.
All account, domain, SID, PID, cache-fingerprint, and real-path identifiers remain omitted.