Context
PR #2191 wholesale-restored 20 files from pre-v2026.3.1 (fdcbc3bd86~1) to remediate sync regressions. This discarded legitimate upstream security improvements from v2026.3.1/v2026.3.2 that are NOT tied to gutted subsystems.
Audit report: hq/engineering/notes/post-remediation-audit-b3b4.md
Findings
1. src/commands/agent.ts — Ingress senderIsOwner enforcement (v2026.3.2)
v2026.3.2 split agentCommand into agentCommandInternal + agentCommandFromIngress. The ingress entry point throws if senderIsOwner is not explicitly set to a boolean, preventing privilege escalation where channel ingress could default to owner permissions.
What to do: Extract the agentCommandFromIngress wrapper that validates senderIsOwner is explicitly boolean. Wire ingress callers through it.
2. src/acp/client.ts — Scoped read-tool auto-approval (v2026.3.1)
~90 LoC of new functions: extractPathFromToolTitle, resolveToolPathCandidate, resolveAbsoluteScopedPath, isPathWithinRoot, isReadToolCallScopedToCwd. Adds "read" to SAFE_AUTO_APPROVE_TOOL_IDS but only auto-approves when the target path is within cwd.
What to do: Re-apply the scoped read auto-approval system. Strip memory_search (gutted). Keep read + web_search entries. Add READ_TOOL_PATH_KEYS constant. Expand shouldAutoApproveToolCall signature to accept params/toolTitle/cwd.
3. src/commands/doctor-config-flow.ts — Allowlist policy detection + repair (v2026.3.1)
detectEmptyAllowlistPolicy warns when an empty allowlist silently blocks all DMs/group messages. maybeRepairAllowlistPolicyAllowFrom auto-repairs from pairing store. Both use readChannelAllowFromStore from ../pairing/pairing-store.js (exists in fork).
What to do: Re-apply hasAllowFromEntries, maybeRepairAllowlistPolicyAllowFrom, detectEmptyAllowlistPolicy. Wire into doctor repair and diagnostic flows.
4. src/config/defaults.ts — hasConfiguredSecretInput (v2026.3.2)
Replaces naive string-based API key check with hasConfiguredSecretInput() which properly handles secret references ($ENV_VAR, op://vault/item) rather than just checking emptiness. Prevents false negatives.
What to do: Import hasConfiguredSecretInput from its module (exists in fork). Replace the string check in applyProviderDefaults.
Exit Criterion
All 4 security improvements re-applied. No new @ts-expect-error suppressions introduced.
Context
PR #2191 wholesale-restored 20 files from pre-v2026.3.1 (
fdcbc3bd86~1) to remediate sync regressions. This discarded legitimate upstream security improvements from v2026.3.1/v2026.3.2 that are NOT tied to gutted subsystems.Audit report:
hq/engineering/notes/post-remediation-audit-b3b4.mdFindings
1.
src/commands/agent.ts— IngresssenderIsOwnerenforcement (v2026.3.2)v2026.3.2 split
agentCommandintoagentCommandInternal+agentCommandFromIngress. The ingress entry point throws ifsenderIsOwneris not explicitly set to a boolean, preventing privilege escalation where channel ingress could default to owner permissions.What to do: Extract the
agentCommandFromIngresswrapper that validatessenderIsOwneris explicitly boolean. Wire ingress callers through it.2.
src/acp/client.ts— Scoped read-tool auto-approval (v2026.3.1)~90 LoC of new functions:
extractPathFromToolTitle,resolveToolPathCandidate,resolveAbsoluteScopedPath,isPathWithinRoot,isReadToolCallScopedToCwd. Adds"read"toSAFE_AUTO_APPROVE_TOOL_IDSbut only auto-approves when the target path is within cwd.What to do: Re-apply the scoped read auto-approval system. Strip
memory_search(gutted). Keepread+web_searchentries. AddREAD_TOOL_PATH_KEYSconstant. ExpandshouldAutoApproveToolCallsignature to acceptparams/toolTitle/cwd.3.
src/commands/doctor-config-flow.ts— Allowlist policy detection + repair (v2026.3.1)detectEmptyAllowlistPolicywarns when an empty allowlist silently blocks all DMs/group messages.maybeRepairAllowlistPolicyAllowFromauto-repairs from pairing store. Both usereadChannelAllowFromStorefrom../pairing/pairing-store.js(exists in fork).What to do: Re-apply
hasAllowFromEntries,maybeRepairAllowlistPolicyAllowFrom,detectEmptyAllowlistPolicy. Wire into doctor repair and diagnostic flows.4.
src/config/defaults.ts—hasConfiguredSecretInput(v2026.3.2)Replaces naive string-based API key check with
hasConfiguredSecretInput()which properly handles secret references ($ENV_VAR,op://vault/item) rather than just checking emptiness. Prevents false negatives.What to do: Import
hasConfiguredSecretInputfrom its module (exists in fork). Replace the string check inapplyProviderDefaults.Exit Criterion
All 4 security improvements re-applied. No new
@ts-expect-errorsuppressions introduced.