Skip to content

[Bug][Windows]: elevated Task Scheduler staging is unreadable under alternate-credential UAC #4779

Closed

Description

@lidge-jun

Client or integration

OpenCodex CLI

Area

Installation or packaging

Summary

Follow-up to #4692. That fix stages the elevated Task Scheduler XML to an ACL-hardened private file instead of inlining two base64 payloads into the command line. The staging uses the existing hardenSecretPath/hardenSecretDir helpers, which grant the current effective token SID full control and then strip inheritance, removing SYSTEM and Administrators.

That is correct for the common case: a split-token elevation of the same user carries the same SID, so the elevated process reads the payload. It is not correct for an elevation answered with a different administrator's credentials — the over-the-shoulder prompt a standard user gets. That elevated process runs as the other admin and cannot open the staged file.

The inline form had no such dependency, so this is a behavioural narrowing introduced by the fix. #4692 mitigates the diagnosability half: the read failure has its own protocol exit code and the parent reports the cause and the remedy instead of a bare number. What is left open is the policy question.

The decision to make: should the staged payloads also grant SYSTEM (S-1-5-18) and Administrators (S-1-5-32-544)?

Arguments for: it restores alternate-credential elevation, and the staged content is a scheduled-task definition pointing at the user's own launcher — not a credential. Tamper-evidence does not depend on the ACL, because the elevated script verifies a SHA-256 over the bytes it reads, which is what covers a same-SID rewrite that no ACL can prevent.

Arguments against: it widens read access to every administrator on the machine, it adds a second ACL shape to src/lib/windows-secret-acl.ts, and that module is security-sensitive enough that MAINTAINERS.md requires explicit security review for changes to it. The current helpers are used for real secrets, so a variant that grants more must not be reachable from those call sites by accident.

Reproduction

  1. Windows host where the opencodex-proxy task file is owned by Administrators, so a non-elevated schtasks /create /f is denied and every repair funnels into the elevated fallback.
  2. Sign in as a standard user, so UAC prompts for an administrator's credentials rather than consent.
  3. Run ocx service repair.
  4. The elevated process runs as the supplied administrator account and cannot read the staged payload. With [Bug]: Elevated Task Scheduler re-registration exceeds command-line limit — ENAMETOOLONG (uv_spawn) with double base64 XML payloads #4692 applied it exits with the staging-unreadable protocol code and the parent explains the cause; the repair still does not complete.

Version

2.56.0 (behaviour introduced by the fix for #4692)

Operating system

Windows, Task Scheduler backend

Provider and model

Not provider-specific

Logs or error output

Background service install failed: the elevated process could not read the staged task
definition in <temp>\opencodex-service-stage-XXXXXX. That directory is readable only by
the account that staged it, so this happens when the UAC prompt was answered with a
different administrator account. Approve the prompt as the signed-in user, or run the
command again from a session already elevated as that user.

Screenshots and supporting files

Relevant code: stageElevatedSchedulerRegistration and describeElevatedRegistrationFailure in src/service/windows-ops.ts, OCX_ELEVATED_STAGING_UNREADABLE and runWindowsElevatedScheduledTaskRegistration in src/lib/windows-elevation.ts, and hardenSecretPath/hardenSecretDir in src/lib/windows-secret-acl.ts.

Workaround for an affected host, unchanged from #4692: delete the admin-owned task once from an elevated prompt (schtasks /delete /tn opencodex-proxy /f), then let repair re-create it as the current user.

Redacted configuration

{}

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. added
    bugSomething isn't working
    platformOS/service/tray/ACL (Windows-heavy, not Windows-only)
    serviceService lifecycle (WinSW/launchd/scheduler)
    on Sep 16, 2026
  2. lidge-jun commented on Sep 16, 2026

    @lidge-jun
    OwnerAuthor

    리뷰 · 우선순위 69 / 80

    이 이슈는 #4692 후속이다. elevated Task Scheduler 등록이 XML을 커맨드라인에 인라인하지 않고 ACL로 굳힌 스테이징 파일로 넘기는데, 그 ACL이 ‘지금 토큰 SID만 Full Control + inheritance strip’이라 over-the-shoulder UAC(다른 관리자 자격으로 상승)에서는 elevated 프로세스가 스테이징을 못 읽는다. 인라인 시절에는 SID 의존이 없었다. 고쳐진 보안/길이 문제가 새 정책 구멍을 만든 형태다.

    현재 dev HEAD b3035fe292에는 #4692 본수정이 아직 없다. 열린 Windows 스택이 #4746 → #4749 → #4759(fix(service): stage elevated Task Scheduler XML instead of inlining it)다. #4759 diff에 stageElevatedSchedulerRegistration, describeElevatedRegistrationFailure, OCX_ELEVATED_STAGING_UNREADABLE = 14가 들어간다. tip의 src/service/windows-ops.ts에는 이미 hardenSecretDir/hardenSecretPath로 스테이징하는 stageWindowsSchedulerRestoreXml(약 436–450행대)가 있어 같은 ACL 모양이 보인다.

    src/lib/windows-secret-acl.ts 머리 주석(약 1–29행)과 구현은 effective token SID에만 grant하고 inheritance를 벗긴다. SYSTEM(S-1-5-18)·Administrators(S-1-5-32-544)는 없다. 같은 사용자 split-token 상승에는 맞고, 다른 관리자 계정 상승에는 틀리다. #4692/#4759는 읽기 실패를 프로토콜 코드로 설명하게 만들어 진단은 좋아졌지만, repair 자체는 여전히 실패한다.

    정책 질문만 남았다. 스테이징에 SYSTEM·Administrators read를 줄까? 찬성: alternate-credential UAC가 다시 되고, 내용은 자격증명이 아니라 사용자 launcher를 가리키는 작업 정의이며, elevated 스크립트가 SHA-256로 바이트를 검증하니 같은 SID 변조는 ACL로도 막지 못한다. 반대: 머신 모든 관리자에게 읽기가 열리고, windows-secret-acl.ts에 두 번째 ACL 모양이 생기며, MAINTAINERS.md가 이 모듈을 security review 대상으로 둔다. 진짜 시크릿 호출부가 실수로 넓은 변형을 타면 안 된다.

    워크어라운드는 이슈에 적힌 대로 admin-owned task를 elevated에서 한 번 지우고 현재 사용자로 다시 만들면 된다. types/config 스플릿과 무관하다. #4759가 착륙하기 전에 ACL을 넓히면 스택이 꼬이니 순서가 중요하다.

    경로 src/lib/windows-secret-acl.ts hardenSecretPath/hardenSecretDir - effective SID만 grant. SYSTEM/Administrators 없음.
    경로 PR #4759 stageElevatedSchedulerRegistration / OCX_ELEVATED_STAGING_UNREADABLE - #4692 스테이징 본문. tip dev에는 아직 없음.
    경로 tip src/service/windows-ops.ts stageWindowsSchedulerRestoreXml (436–450) - 같은 hardenSecret* 스테이징 모양의 선례.
    스택 #4746→#4749→#4759 - Windows schtasks 레인. #4779는 #4759 착륙 후속 정책.

    메인테이너의 판단이 필요한 지점

    너의 추천
    받아라. #4759를 먼저 랜딩한 뒤, 스테이징 전용 harden 변형(시크릿 API와 호출부 분리 + SHA-256 유지)으로 alternate-credential을 복구하는 후속 PR을 받아라. 시크릿용 hardenSecret* 기본값은 넓히지 마라.

    이 댓글은 grok-bot이 작성했습니다

  3. added
    priority: P1High: reproducible failure in a core path (routing, failover, account pool, streaming, usage, auth,
    on Sep 24, 2026
  4. devin-ai-integration commented on Sep 25, 2026

    @devin-ai-integration
    Contributor

    New matched pull request: #5825 (would resolve this issue) — fix: P0 #5369 spill growth + P1 bug batch [priority: P0]

  5. added a commit that references this issue on Sep 25, 2026
  6. lidge-jun commented on Sep 25, 2026

    @lidge-jun
    OwnerAuthor

    Fixed by #5825 (22b22ae): the scheduler staging payload is now hardened with a dedicated ACL shape that gives SYSTEM and BUILTIN\Administrators read-only access, so an elevation approved with a different administrator's credentials can read it. Secret paths still use the owner-only ACL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinginstallInstallation or packagingplatformOS/service/tray/ACL (Windows-heavy, not Windows-only)priority: P1High: reproducible failure in a core path (routing, failover, account pool, streaming, usage, auth,serviceService lifecycle (WinSW/launchd/scheduler)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions