Repository navigation
Windows: ancestor walk refuses app container / capability SIDs, so 0.10.0 cannot start inside a containerized host #1533
Description
Summary
On Windows, win_private_directory_tree_secure walks every ancestor of the runtime directory and refuses any that grants mutation rights to an identity it does not trust. App container and capability SIDs (S-1-15-2-*, S-1-15-3-*) are not on the trusted list, so when the process runs inside a containerized host application the walk refuses the container's own AppData and no endpoint can be created.
The result is that 0.10.0 cannot start at all from inside such a host, with no remedy available to the user: the offending ACE is on a directory the container owns, not on anything the user can edit.
Evidence
Instrumented build from main, printing ipc_validation_detail_buffer at the failing gate in cbm_daemon_ipc_endpoint_new:
DIAG gate=final dir=1 wide=1 names=1 pipe=1 mutex=1 tree_secure=0 err=0
runtime_dir=C:\Users\petro\AppData\Local/cbm-daemon-c888acc3ae367a1e
DIAG detail=C:\Users\petro\AppData: DACL entry 0 grants mutation rights 0x000d0152
to untrusted identity (other S-1-15-3-3557520199-3666692283-3112367039-3524159787-2791857073-3163583606-3692855932)
Every other condition in that gate passes. The refusal is on an ancestor (C:\Users\petro\AppData), not on the runtime directory itself.
Without instrumentation the only surfaced message is:
codebase-memory-mcp: secure CLI coordination could not be created (endpoint)
CBM_LOG_LEVEL=debug adds nothing, because the failure happens before the log layer is initialized.
Environment
- Windows 11 26200, non-elevated standard token
- codebase-memory-mcp 0.10.0 (also reproduced with a local build of
main) - Host application runs the MCP server inside an app container, so its
%LOCALAPPDATA%resolves to a container-owned object whose DACL carries the capability SID above - The same binary run from an ordinary terminal on the same machine works: that
AppDatahas no such ACE
Version boundary
0.9.0 works from inside the same host. The ancestor walk is part of the strict permission gate introduced in 0.9.1-rc (#1416), so the regression window is 0.9.0 → 0.9.1-rc.
Why this differs from #1416
#1416 covers trees carrying Authenticated Users:(M) from a drive root, where both documented workarounds apply: move the install under the user profile, or strip the inherited grant. Neither works here.
- The install is already under the user profile. The refused path is
%LOCALAPPDATA%itself. - The runtime parent is not configurable.
cbm_daemon_ipc_endpoint_newaccepts aruntime_parent, but every production call site passesNULL(main.c:1486,2399,2559), and the only override is compile-gated behindCBM_ENABLE_TEST_SEAMS. - The ACE belongs to the container, not to the user, so there is nothing for the user to strip.
Proposal
Treat app container SIDs (S-1-15-2-*) and capability SIDs (S-1-15-3-*) as trusted in the ancestor walk only, leaving the final runtime directory under the existing exact-owner rule.
The argument for it: neither is a login-capable account. A grant to a capability SID is a statement about which packaged identity the OS will hand the token to, not a second user who can tamper with the tree. That is the threat the gate exists to stop, and it is not what these ACEs represent.
Two things I could not settle myself, which is why this is an issue rather than a PR:
- Whether an arbitrary local process can assume a chosen capability SID. If it can, the exemption is not safe and this should stay refused, in which case the request becomes "make the runtime parent configurable" instead.
- Whether the exemption should be ancestors-only. That is sufficient for this failure, and it is the narrower change.
Happy to write the patch either way once you have ruled on the direction.
Activity
mwgrant21 commentedon Aug 11, 2026
Independent reproduction on 0.10.2, with evidence that the trigger is broader than the title suggests — and that this and #1529 are the same defect seen from two angles.
Environment: Windows 11 26200, non-elevated standard token, 0.10.2, GitHub release archive.
Same gate, same symptom.
daemon statusfails with only:and
CBM_LOG_LEVEL=debugadds nothing, exactly as you describe — the failure precedes log-layer init, so there is no diagnostic surface without an instrumented build.The difference: the untrusted identity is not an app container or capability SID. On this machine the offending ACE on
%USERPROFILE%\AppDatais a non-inherited grant to a local group:No
S-1-15-2-*orS-1-15-3-*SID is present anywhere onAppData. So the ancestor walk inwin_private_directory_tree_secureis refusing an ordinary local group, which means the fix cannot be limited to trusting app container / capability SIDs — the general shape is any non-inherited mutation grant on an ancestor of the runtime directory, from any identity not on the trusted list.This connects #1529. The OpenAI Codex desktop sandbox creates the local
CodexSandboxUsersgroup and grants itModifyon several shared paths. On this machine that is%TEMP%,~/.cache, and%USERPROFILE%\AppData. The consequence is a two-stage failure that reads as two unrelated bugs:acl-grants-cross-account-mutationon the staging dir — this is Windows installer fails with CodexSandboxUsers ACL in %TEMP% #1529. Staging somewhere private clears it.AppDataancestor — this issue.CBM_CACHE_DIRdoes not help, because the runtime directory is%LOCALAPPDATA%\cbm-daemon-<hash>, whose ancestor chain is untouched by relocating the cache.So #1529's workaround gets a user past the installer and straight into this, with a different and much less informative error. Worth noting on that issue too — a user who applies the documented temp workaround will reasonably conclude the fix didn't work.
Why this is not user-remediable here either. Your original report notes the ACE sits on a directory the container owns. Same conclusion by a different route: the grant belongs to another vendor's sandbox, on the user's own
AppData. Removing it to satisfy this tool would risk breaking Codex CLI's sandbox — trading one working tool for another.Happy to run an instrumented build and post the
ipc_validation_detail_bufferoutput for the local-group case if that would help distinguish it from the capability-SID path.mwgrant21 commentedon Aug 11, 2026
Resolved on my machine, and the cause narrows usefully: the ACEs were orphaned by an uninstall.
Follow-up to my earlier comment. Codex turned out not to be installed on this box at all — no executable, no
~/.codex/config, no uninstall registry entry. What remained were theCodexSandboxUserslocal group and its ACL grants, left behind when the app was removed.Each of the three affected directories carried exactly two non-inherited
Modifygrants:%USERPROFILE%\AppDataCodexSandboxUsers%LOCALAPPDATA%\TempCodexSandboxUsers%USERPROFILE%\.cacheCodexSandboxUsersThe second grant in each case resolves to no principal on the machine — a different foreign-domain SID per directory, consistent with per-install sandbox accounts orphaned across several install/uninstall cycles.
Removing those six ACEs fixed both failures.
install.ps1then completed with no custom temp directory, anddaemon statusreturned normally (daemon: not running) instead of the endpoint error. Indexed a 128-file repo immediately afterward with no further changes.CBM_CACHE_DIRwas not needed and has been reverted to the default.Two things this suggests for the fix:
An unresolvable SID is a strictly safer case to tolerate than a live one. An ACE naming a principal that no longer exists cannot actually be exercised by anyone, so refusing on it is a false positive with no security benefit. Filtering ACEs whose SID fails to resolve would clear a meaningful share of real-world machines without loosening the guarantee at all.
The diagnostic is the expensive part. Reaching this took reading source, an ancestor-by-ancestor ACL walk, and finally this issue — the surfaced message names neither the path nor the identity. Even without any policy change, printing the refusing ancestor and the offending SID in the default error (as your instrumented build already computes into
ipc_validation_detail_buffer) would turn a multi-hour investigation into a one-line fix. That alone would likely close most reports of this shape.Happy to test a build that relaxes the unresolvable-SID case if useful.
rtellez91 commentedon Aug 12, 2026
This is also reproducible with the released Windows UI-capable binary v0.10.2 when the installation and cache are kept on a non-system drive.
Environment
Reproduction
Result:
The same happens with daemon-backed CLI commands such as codebase-memory-mcp cli list_projects. Moving the cache to a D: location gets past the cache-private check, but the daemon endpoint still cannot be created. Before moving the cache, the failure identified an inherited Authenticated Users mutation grant on D:\tools.
Expected behavior
A supported custom runtime/IPC directory should allow the complete installation to operate from a user-controlled non-system drive, without changing unrelated ACLs on the existing install tree or relying on %LOCALAPPDATA%\codebase-memory-mcp.
Please consider exposing a production CBM_RUNTIME_DIR/runtime-parent setting or an equivalent CLI option. In v0.10.2, the runtime parent appears to remain tied to Windows Local AppData even when the executable and cache are configured elsewhere.
This seems related to #1416, but the key request here is the configurable runtime parent described in this issue.
DeusData commentedon Aug 12, 2026
Thank you @mwgrant21 and @rtellez91 for narrowing the additional cases. The current product paths still have no runtime-parent setting: the only environment override is the test-only
CBM_TEST_DAEMON_RUNTIME_PARENT, and production endpoint call sites otherwise passNULL.The narrower remediation is now tracked explicitly in #1574 and proposed in #1576 as
CBM_RUNTIME_DIR, with the same private-directory validation retained at the selected location. That avoids broadening the trusted-SID policy merely to make one ancestry usable. The implementation PR is security-sensitive and also needs to be unstacked from #1561 before review, but these reports are now cross-linked to the concrete product path. Thank you for testing the ACL repair and relocation cases separately.ozkanmelen commentedon Aug 13, 2026
Still reproducible in v0.10.3 — and the offending ACE is created by the Claude Desktop app itself
Fresh data point from a clean install on Windows 10 Pro 10.0.19045 (x64):
install.ps1 --skip-configsucceeded (v0.10.3, checksum verified).codebase-memory-mcp cli <any tool>→secure CLI coordination could not be created (endpoint)secure daemon endpoint could not be createdconfig listfails the same way, so there is no way to reconfigure around it (cf. No product-build way to relocate the daemon runtime directory when %LOCALAPPDATA% has a capability-SID ACE #1574).%USERPROFILE%\AppData, inherited down the tree:HKCR\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer\Mappings, that package SID resolves to the Anthropic Claude desktop app (DisplayNameClaude, monikerclaude_pzs8sxrjxfjjc). Its sandbox grants itself this ACE on install, so the condition is not exotic: it exists on any machine running Claude Desktop — likely a large share of this project's MCP audience, given Claude Code is one of the auto-configured clients.Since the ACE belongs to a legitimately installed host application's AppContainer and end users cannot reasonably remove it, +1 for the proposed fix of treating
S-1-15-2-*/S-1-15-3-*as trusted during the ancestor walk (or providing an explicit override).DeusData commentedon Aug 13, 2026
@ozkanmelen, thank you for the clean v0.10.3 reproduction and for resolving the SID back to the installed Claude Desktop AppContainer. That is a material distinction from the orphaned-SID cases: this ACE belongs to a live, relevant host application and cannot reasonably be removed as user remediation.
This leaves a real security-policy choice rather than a missing diagnostic. The existing
CBM_RUNTIME_DIRdirection in #1574/#1576 preserves the current trust rule by moving the private endpoint to a usable ancestry. ExemptingS-1-15-2-*orS-1-15-3-*during the ancestor walk would be more automatic, but it changes which mutation-capable principals the endpoint validator trusts and requires a dedicated security decision.I am keeping this
priority/highand security-labeled. Triage will not choose between those threat-model options. No additional diagnostics are needed from you; thank you for establishing that the v0.10.3 failure affects a normal Claude Desktop installation rather than an exotic container setup.fix(windows): tolerate AppContainer SIDs on ancestors, keep the runti…
fix(cli): name the rule that refused CLI coordination, not just the s…
DeusData commentedon Sep 26, 2026
Thank you, @Kiborgik, for the instrumented diagnosis, and @mwgrant21, @rtellez91 and @ozkanmelen for the additional cases! Tracing the SID back to the Claude Desktop AppContainer is what settled the policy question.
Two changes shipped in v0.10.5:
S-1-15-2-*,S-1-15-3-*). A process can't choose which AppContainer grants those. The private runtime directory itself keeps the strict check.CBM_RUNTIME_DIRis a supported production setting, so you can put the rendezvous on an ancestry you own, for example on another drive (seedocs/CONFIGURATION.md).An orphaned local-group grant, such as leftover
CodexSandboxUsersACEs, is still refused on purpose, because trusting an arbitrary live group would weaken the check. For that case, and for the D:\ install layout,CBM_RUNTIME_DIRis the intended remedy. Could you confirm that v0.11.0 now starts inside your containerized host?Kiborgik commentedon Sep 26, 2026
I had no problem with this since 0.11.0 @DeusData
github-actions commentedon Sep 26, 2026
Thanks for the report! To move this forward we need a bit more so we can reproduce it ourselves:
codebase-memory-mcp --versionyou're onOnce that's here we'll pick it straight back up. Heads-up: issues left
awaiting-reporterare automatically closed after a few weeks of silence, but a comment reopens the door anytime.