Skip to content

0.10.2: cache ACL grants an ephemeral logon-session SID (S-1-5-5-X-Y) instead of the user SID, so the cache becomes unreadable after reboot (likely incomplete fix for #1351) #1601

Description

@SQLBImhugh

Summary

codebase-memory-mcp hardens its cache files with an ACE granting the current logon-session SID (S-1-5-5-X-Y) instead of the user account SID. Logon-session SIDs are ephemeral — Windows mints a new one at every logon and the old one ceases to exist at reboot.

When the cache file's owner is BUILTIN\Administrators (which happens if the file was created by an elevated process), the logon-session ACE is the only user-side grant. After the next reboot that ACE is dead, leaving no ACE matching the interactive user and an owner a UAC-filtered token cannot exercise. The file becomes permanently inaccessible non-elevated, and the daemon can no longer start.

This is not corruption. The affected file is byte-intact and opens fine when elevated.

Relationship to #1351

This looks like the same defect as #1351 ("daemon leaves existing cache files unreadable (empty ACL)"), which was closed as completed on 2026-08-12 00:04 UTC. Two reasons to think it is not fully fixed:

  • I am on 0.10.2, and the _config.db that broke was created at 2026-08-12 17:57:55 UTC — after that issue was closed.
  • The identical failure signature appears: daemon.runtime_config_open_failed reason=config_db_unavailable, with the current user unable to read _config.db.

The one thing I would refine is the diagnosis. The ACL is not empty — it is well-formed and non-trivial. The defect is that it names the wrong principal: an ephemeral logon-session SID rather than the user account. A fix aimed at "don't write an empty ACL" would not address this.

That distinction also reconciles the two reports. In #1351 access was lost immediately; for me it survived until a reboot. Both follow from the same mechanism — it depends on whether the process writing the ACL shares the interactive user's logon session. If it does, the grant appears to work until that session ends; if it does not, the user is locked out right away.

Environment

Version codebase-memory-mcp 0.10.2
OS Windows 11, NTFS
Client GitHub Copilot CLI (stdio MCP)
CBM_CACHE_DIR D:\CBM (non-default, on a second physical volume)
Account Domain user, member of Administrators, UAC enabled (so the normal token is filtered)

Symptom

After a reboot, every MCP handshake fails. The client reports only:

Failed to connect to MCP server "codebase-memory-mcp"

The actual cause appears only in <CBM_CACHE_DIR>\logs\cbm-daemon.log, repeated once per retry:

level=error msg=daemon.runtime_config_open_failed reason=config_db_unavailable
level=error msg=daemon.start_failed component=application

Non-elevated, every operation on _config.db fails — including ones that only need READ_CONTROL:

Get-Acl    -> Attempted to perform an unauthorized operation.
[IO.File]::Open -> Access to the path '...\_config.db' is denied.
icacls     -> Access is denied.  (Successfully processed 0 files; Failed processing 1)
takeown    -> Access is denied.
Rename/Delete of the FILE -> Access is denied.

Root cause — evidence

Elevated SDDL dump of the broken _config.db:

O:BA
D:AI(A;;FA;;;SY)(A;;FA;;;BA)(A;;0x1200a9;;;S-1-5-5-0-1065411)

Decoded:

Principal Rights
Owner BUILTIN\Administrators
NT AUTHORITY\SYSTEM Full Control
BUILTIN\Administrators Full Control
NT AUTHORITY\LogonSessionId_0_1065411 ReadAndExecute

There is no ACE for the user account. icacls itself resolves S-1-5-5-0-1065411 to NT AUTHORITY\LogonSessionId_0_1065411, confirming it is a logon-session SID.

A healthy file in the same cache, created by a non-elevated run:

O:<user-sid> G:<user-sid>
D:AI(A;;FA;;;SY)(A;;0x1200a9;;;S-1-5-5-0-1284670)(A;;FA;;;<user-sid>)
Principal Rights
Owner <DOMAIN>\<user>
NT AUTHORITY\SYSTEM Full Control
NT AUTHORITY\LogonSessionId_0_1284670 ReadAndExecute
<DOMAIN>\<user> Full Control ← the durable grant that saves it

The logon-session rollover across the reboot is directly observable in the cache: every file written before the reboot carries ...0_1065411, every file written after carries ...0_1284670.

USN journal (fsutil usn readjournal D: csv, filtered) shows the daemon rewriting the security descriptor on essentially every run — 11 Security change records against a single _config.db in one day:

903328960,"_config.db",20,0x00000800,"Security change","8/13/2026 9:34:20",...
903330128,"_config.db",20,0x00000800,"Security change","8/13/2026 9:34:20",...
903331296,"_config.db",20,0x00000800,"Security change","8/13/2026 9:34:21",...
903337600,"_config.db",20,0x00000800,"Security change","8/13/2026 9:34:58",...
...
904175928,"_config.db",20,0x00000800,"Security change","8/13/2026 13:31:06",...

The file itself is undamaged — read elevated, the first 16 bytes are 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 (SQLite format 3.), and fsutil file layout shows normal attributes and a consistent 12,288-byte $DATA stream. No NTFS, disk, or bugcheck events were logged, because nothing was corrupt.

Why it only affects some files

Windows sets the owner of a file created by an elevated process to BUILTIN\Administrators, not the creating user. In my cache exactly one file — _config.db, created at 17:57:55Z during an elevated session — had that owner. The other five files were user-owned and carried an explicit <user>:(F) ACE, so their stale logon-session ACEs were harmless.

So the hardening logic appears to grant owner + SYSTEM + current logon session. When the owner is already Administrators, that produces zero durable access for the actual user, and the file works only until the logon session ends.

Reproduction

  1. Set CBM_CACHE_DIR to a fresh directory.
  2. Trigger cache creation from an elevated process, so _config.db is owned by BUILTIN\Administrators.
  3. Use the MCP server normally, non-elevated — it works for the rest of the logon session.
  4. Reboot.
  5. Every daemon start now fails with config_db_unavailable; non-elevated the file is untouchable.

Impact

  • Complete, silent loss of the MCP server after an unrelated reboot.
  • Unrecoverable non-elevated by ordinary means — takeown and icacls both fail because the user is neither owner nor granted.
  • The surfaced error names neither the file nor a permission problem, so the failure is very hard to attribute. (In my case the client displayed an unrelated level=info ... version_cohort.claimed_unheld line, which sent me down the wrong path entirely.)

Suggested fix

  1. Grant the user account SID, never a logon-session SID. Use the token user (TokenUser) rather than any S-1-5-5-* group when building the DACL. A logon-session SID is by definition invalid after logoff.
  2. Ensure a durable owner. If the owner resolves to BUILTIN\Administrators, explicitly add an ACE for the real user (or set the owner to the user), so the cache survives a reboot regardless of how it was first created.
  3. Fail loudly. config_db_unavailable should distinguish access denied from missing/corrupt and log the full path plus the effective error, so the log points at the actual problem.
  4. Optionally, self-heal: on ACCESS_DENIED opening _config.db, log a clear remediation hint — the config DB is regenerable, so the daemon could rename-aside and rebuild rather than hard-failing forever.

Workaround (no elevation required)

You cannot delete or rename the file — that needs rights on the file, which is exactly what is broken. But you can rename its parent directory, since that only needs DELETE on the directory, which the user still holds:

Move-Item D:\CBM D:\CBM-broken-<timestamp>     # rename the DIRECTORY
New-Item -ItemType Directory D:\CBM
# move only the project graph .db files across - NOT _config.db
Get-ChildItem D:\CBM-broken-<timestamp>\*.db |
  Where-Object Name -ne '_config.db' |
  Move-Item -Destination D:\CBM

The daemon regenerates a clean _config.db on next start. All project graphs are preserved — no re-indexing needed (mine was ~41,800 nodes).

Preventive rule

Never run codebase-memory-mcp, its installer, or its indexer elevated. Doing so stamps BUILTIN\Administrators as the cache owner and arms this failure for the next reboot.

Metadata

Metadata

Assignees

No one assigned

    Labels

    editor/integrationEditor compatibility and CLI integrationwindowsWindows-specific issues

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions