Follow-ups from the fresh-context review of PR #2665 (closes #1262), none of which block that PR: the PR fixes the write-before-chmod TOCTOU and gives NEW connector-key files an owner-only DACL on Windows and an exact 0600 on Unix, by a faithful copy of the API's FirstRunBootstrapper.WriteRestrictedFile (PR #1267). Three MEDIUM and one LOW finding stay open here.
1. Forward remediation of key files created before PR #2665 (MEDIUM)
CliFirstRunBootstrapper.EnsureKeyOnDisk returns as soon as ReadExisting finds a key, so PersistKey never runs against an existing appsettings.local.json. A Windows user who ran the CLI before this fix keeps a key file with the directory's inherited DACL (typically BUILTIN\Users read) forever. The API shipped an explicit remediation path for exactly this (FirstRunBootstrapper.RestrictFileToCurrentUser / RestrictExistingLocalConfigFile, #1241); the CLI has none.
Ask: on the existing-key path, restrict the existing file to the current user (owner-only protected DACL on Windows, 0600 on Unix), best-effort with a stderr warning on failure, never a fatal error; mirror the API's helper and its test (RestrictFileToCurrentUser_LocksFileToCurrentUserOnly).
2. Drift guard between the API and CLI copies of the helper (MEDIUM)
backend/src/Taskdeck.Cli/RestrictedFileWriter.cs says "keep the two in sync" but nothing enforces it; the CLI structural test pins four substrings in the CLI copy only. A future hardening of the API helper (for example an ACE-count assertion) would leave the CLI copy silently weaker.
Ask: a structural parity test that reads both sources, strips comments and blank lines, and asserts the shared method bodies (WriteRestrictedFile both overloads, CreateRestrictedNewFile, CreateOwnerOnlyFileWindows, BuildOwnerOnlyFileSecurity) are identical, so any divergence is a red on the side that changed. The PR's own parity check was done by hand (verification item 8 in the PR body).
3. Document the new fail-closed behaviour on non-ACL filesystems (MEDIUM)
The CLI resolves its key file next to the data directory (TASKDECK_CONNECTION_STRING), a user-chosen location that can be a FAT32/exFAT drive or an SMB share without security-descriptor support. There, CreateOwnerOnlyFileWindows now refuses (the read-back DACL is unprotected), PersistKey throws IOException, and EnsureKeyOnDisk warns and falls back to a per-run transient key, which means connector secrets encrypted in one run cannot be read in the next. This is the same posture the API takes for its own config file and the thrown message names FAT32/exFAT, but no operator doc records it.
Ask: one paragraph in docs/platform/CONFIGURATION_REFERENCE.md (and the Windows quick start if it mentions the data directory) saying the data directory must live on a filesystem that can store owner-only permissions, what happens otherwise, and how to move it.
4. Reconcile the accepted-risk record (LOW)
docs/COURSE_CORRECTION.md section 3 lists #1262 (with #1242 and #1261) as an explicit accepted-risk write-off under the single-user threat model, while docs/analysis/2026-08-23-realignment/open-issues.tsv re-lists #1262 as pending Priority II security work. PR #2665 follows the later record. Ask: a dated note on the COURSE_CORRECTION entry saying #1262 shipped in PR #2665 and whether #1242 and #1261 remain written off (maintainer wording; the beta lane does not decide the threat-model boundary).
Refs #1262, PR #2665, #1241, #1264, PR #1267.
Follow-ups from the fresh-context review of PR #2665 (closes #1262), none of which block that PR: the PR fixes the write-before-chmod TOCTOU and gives NEW connector-key files an owner-only DACL on Windows and an exact 0600 on Unix, by a faithful copy of the API's
FirstRunBootstrapper.WriteRestrictedFile(PR #1267). Three MEDIUM and one LOW finding stay open here.1. Forward remediation of key files created before PR #2665 (MEDIUM)
CliFirstRunBootstrapper.EnsureKeyOnDiskreturns as soon asReadExistingfinds a key, soPersistKeynever runs against an existingappsettings.local.json. A Windows user who ran the CLI before this fix keeps a key file with the directory's inherited DACL (typically BUILTIN\Users read) forever. The API shipped an explicit remediation path for exactly this (FirstRunBootstrapper.RestrictFileToCurrentUser/RestrictExistingLocalConfigFile, #1241); the CLI has none.Ask: on the existing-key path, restrict the existing file to the current user (owner-only protected DACL on Windows, 0600 on Unix), best-effort with a stderr warning on failure, never a fatal error; mirror the API's helper and its test (
RestrictFileToCurrentUser_LocksFileToCurrentUserOnly).2. Drift guard between the API and CLI copies of the helper (MEDIUM)
backend/src/Taskdeck.Cli/RestrictedFileWriter.cssays "keep the two in sync" but nothing enforces it; the CLI structural test pins four substrings in the CLI copy only. A future hardening of the API helper (for example an ACE-count assertion) would leave the CLI copy silently weaker.Ask: a structural parity test that reads both sources, strips comments and blank lines, and asserts the shared method bodies (
WriteRestrictedFileboth overloads,CreateRestrictedNewFile,CreateOwnerOnlyFileWindows,BuildOwnerOnlyFileSecurity) are identical, so any divergence is a red on the side that changed. The PR's own parity check was done by hand (verification item 8 in the PR body).3. Document the new fail-closed behaviour on non-ACL filesystems (MEDIUM)
The CLI resolves its key file next to the data directory (
TASKDECK_CONNECTION_STRING), a user-chosen location that can be a FAT32/exFAT drive or an SMB share without security-descriptor support. There,CreateOwnerOnlyFileWindowsnow refuses (the read-back DACL is unprotected),PersistKeythrowsIOException, andEnsureKeyOnDiskwarns and falls back to a per-run transient key, which means connector secrets encrypted in one run cannot be read in the next. This is the same posture the API takes for its own config file and the thrown message names FAT32/exFAT, but no operator doc records it.Ask: one paragraph in
docs/platform/CONFIGURATION_REFERENCE.md(and the Windows quick start if it mentions the data directory) saying the data directory must live on a filesystem that can store owner-only permissions, what happens otherwise, and how to move it.4. Reconcile the accepted-risk record (LOW)
docs/COURSE_CORRECTION.mdsection 3 lists #1262 (with #1242 and #1261) as an explicit accepted-risk write-off under the single-user threat model, whiledocs/analysis/2026-08-23-realignment/open-issues.tsvre-lists #1262 as pending Priority II security work. PR #2665 follows the later record. Ask: a dated note on the COURSE_CORRECTION entry saying #1262 shipped in PR #2665 and whether #1242 and #1261 remain written off (maintainer wording; the beta lane does not decide the threat-model boundary).Refs #1262, PR #2665, #1241, #1264, PR #1267.