Skip to content

[Windows][Dots] Forwarded explicit approval rejected as untrusted; original delegated task cannot accept user input #50794

Open

Description

@gro83j

Codex App version

Installed Windows package: OpenAI.Codex 26.930.2377.0 (ChatGPT.exe).

Subscription

Not included in this deliberately redacted report.

Platform

Windows 10 Pro 22H2, x64, build 19045. Dot parent conversation with delegated tasks on the connected Windows executor. Observations on 2026-10-04 UTC.

Issue

Two observed failures combine to block the supported approval recovery path:

  1. The human explicitly approves a specific action in the parent conversation. Forwarding that exact request and answer to the original delegated task does not establish trusted authorization for auto-review.
  2. When the human tries to send a message in the original execution conversation, an English error briefly appears and later attempts show that the message cannot be sent. The exact transient error was not captured, so we cannot identify its error code or root cause.

This is an observed workflow, not a claim that all delegated tasks are affected. Some unrelated tasks continue successfully.

Observed steps

  1. A delegated task reaches a concrete boundary requiring approval. Observed cases include uploading specified result files to the user's own Library, a single bounded read-only scanner call, and transferring three identified source files to a specified private directory on the user's Mac.
  2. The parent describes the exact action, destination and scope. For the scanner it also explicitly states that process creation consumes the one permitted attempt even if it fails early.
  3. The human approves in the parent conversation.
  4. The parent forwards the exact original question and human answer to the same executing task. One same-action retry is attempted after the specific approval.
  5. Auto-review rejects before process creation because the forwarded approval appears in delegated transcript content rather than a trusted user instruction.
  6. The human tries the proposed original-task native approval/input path. The UI shows a brief error and subsequently cannot send messages. No successful native approval or execution has been verified.

Exact denial from the source-transfer retry:

The retry still transmits potentially sensitive source code over SSH and writes it to a remote Mac; the claimed approval appears only in untrusted delegated transcript content, so it does not establish trusted authorization for this sensitive egress.

The denied actions remain stopped: no transfer or remote write for that action; no scanner start or attempt consumption. We have not weakened review, fabricated role markers, changed destinations, or moved the denied actions to replacement tasks to bypass the rejection.

Expected behavior

Preserve the genuine human approval and its precise scope across the supported parent/task boundary, while retaining non-overridable safety checks. If native user approval is required, the original task should expose a working input/approval path or a documented recovery path.

Please clarify:

  • Whether original parent user approval is supported for this delegation type, and how its provenance should reach review.
  • How to recover when the original execution conversation cannot accept human input.
  • Whether selecting a specific denial through /approve only records permission or can immediately resume an in-flight action in this Windows build.
  • Whether a supported task recovery/replacement can preserve denial history, unique ownership and the unused attempt without bypassing the original decision.

Separate Computer Use capability observation

The official node_repl component is present and enabled in local configuration, with a valid OpenAI signature, but the task reports unknown MCP server. A separate browser-only cua_repl server fails initialization with connection closed. These are separate observed tool-loading failures; they have not been established as the cause of the approval or message-input failures.

Related reports

These appear related, but no identical root cause has been established.

Disclosure boundary

Published with the user's explicit permission. This report intentionally excludes email/account identifiers, private task/message IDs, source filenames and contents, research details, credentials, complete configuration and session logs. It contains only versions, error text and redacted reproduction steps. An official support chat received the redacted report but explicitly stated that it had not escalated it to a human and could not create a case there. Please advise a supported minimal diagnostic route without automatically attaching private sessions.

Activity

  1. added
    bugSomething isn't working
    appIssues related to the Codex desktop app
    windows-osIssues related to Codex on Windows systems
    dotsIssues involving setting up ChatGPT dots or managing their ongoing work.
    subagentIssues involving subagents or multi-agent features
    safety-checkIssues related to safety and abuse checks
    on Oct 4, 2026
  2. Nakagawa-master commented on Oct 4, 2026

    @Nakagawa-master

    One boundary may help separate the two failures here:

    forwarding approval text != transferring approval authority
    

    Keeping delegated transcript content untrusted is a good property. The missing piece is a supported way for the host/runtime to convert a direct human decision into a verifiable authorization artifact that can cross the parent -> task boundary without asking the child to trust copied prose.

    A narrow contract could be:

    1. the parent surfaces the exact pending action to the human;
    2. on approval, the host mints a one-shot authorization receipt bound to the user/principal, task/run identity, action + material arguments/destination, policy context, and an expiry or decision version;
    3. the delegated task receives that receipt as trusted runtime metadata, not as transcript content;
    4. auto-review verifies the receipt against the exact action immediately before execution;
    5. any material action mutation requires a new decision; exact retry may consume the same receipt only according to an explicit retry/one-shot rule;
    6. execution records which receipt was consumed so recovery can distinguish "approved but not executed" from "executed" without inferring from transcript text.

    That gives a useful regression matrix:

    • copied user words only -> still untrusted;
    • exact host-issued receipt + exact action -> accepted if policy permits;
    • receipt for action A presented for action B -> rejected;
    • stale/expired/consumed receipt -> rejected or sent back to the human;
    • original task input UI unavailable -> the parent can still deliver the trusted receipt through the supported task-control path, so approval provenance does not depend on the child accepting an ordinary chat message.

    This would preserve the security property in the current denial while removing the dead end where the only available representation of a genuine human decision is deliberately untrusted transcript text. It also makes the approval decision auditable as a decision with scope and lifetime, rather than as wording that downstream components have to reinterpret.

  3. gro83j commented on Oct 4, 2026

    @gro83j
    Author

    Read-only follow-up: the official Codex CLI 0.160.0 release includes #49036 (authenticated conversation-history retrieval for Guardian) and #49057 (handoff-aware root context). Both features are disabled by default in the published source. We have not changed these settings.

    Could maintainers clarify whether these mechanisms support Dot parent conversations delegating to connected Windows tasks, including authorization from the original parent conversation? The published #49057 implementation selects native collaboration handoffs; we have not verified that it covers this cross-executor path.

    If this is supported, please identify the applicable desktop version and a supported way to expose the exact approval in the parent conversation while preserving the original task, action scope, denial history, and safety checks. The delegated task's direct-input problem remains unresolved; we need a route that does not require the user to send messages in that task's window.

    A separate, approved isolation test created one 29-byte artificial text file and uploaded it once to the user's personal Library. It contained no research or personal data. The upload succeeded, with no visible native approval request or decision. This verifies only that sample's upload path; trusted approval propagation and the previously denied SSH/source-transfer and scanner actions remain unverified and stopped.

    Official references:
    https://github.com/openai/codex/releases/tag/rust-v0.160.0
    #49036
    #49057

  4. Nakagawa-master commented on Oct 4, 2026

    @Nakagawa-master

    The 0.160.0 follow-up helps sharpen the boundary rather than close it.

    #49036 and #49057 both improve evidence available to Guardian:

    Those are valuable inputs to an authorization decision, but neither PR appears to mint a transferable authorization artifact for the delegated executor. So I would keep these three layers separate:

    retrievable authorization evidence
    !=
    selected review context
    !=
    authority consumable by the exact delegated side effect
    

    A focused regression for the Dot -> connected-task path could therefore test:

    1. direct human approval exists in the parent conversation;
    2. Guardian can retrieve/select that exact evidence after handoff;
    3. the child does not treat copied text or a delegation wrapper as authority;
    4. immediately before execution, the runtime can either verify an authority-bearing receipt bound to the exact task/action/material destination, or explicitly fail back to a supported parent-side approval flow;
    5. a later revocation or materially changed action invalidates that authority even if the older approval remains retrievable.

    If #49036/#49057 already produce such a verified authority object somewhere downstream, identifying that object and its binding fields would likely answer the key question here. If they only improve review evidence, then the authorization-transfer seam remains distinct.

  5. gro83j commented on Oct 4, 2026

    @gro83j
    Author

    New observation: the same approval-provenance failure now occurs for a fixed, bounded local-only verification on the original Windows task, with no SSH transfer or source upload. The human approved that exact one-time action by replying to the parent's explicit request. The parent forwarded the original question and answer unchanged. Review rejected before process creation, citing the initial read-only scope and describing the new approval as untrusted delegated transcript content. Nothing ran and there was no retry.

    The supported task-read API exposes an important distinction: the task's initial read-only takeover instruction is an outer user message containing a delegation envelope; later updates, including this exact approval, are outer tool messages containing delegation envelopes. This is observable transport metadata, not proof of the reviewer's internal context or a confirmed cache defect.

    Could maintainers clarify the supported authorization-update path for an existing Dot-created Windows task?

    1. How should later genuine human approvals in the main Dot conversation update the original task's trusted scope, without asking the human to post in its non-writable child conversation?
    2. Does Add opt-in conversation history retrieval to Guardian reviews #49036's hosted history binding on the executing thread resolve to the correct Dot owner's main conversation in this deployment? Is Add handoff-aware root context for Guardian reviews #49057's native local root/worker mapping intended to cover this cross-executor delegation type?
    3. Is there a supported same-task pending-approval or denied-action recovery route that preserves the original denial and unused attempt?

    We have not changed review settings, fabricated provenance, moved the denied action to another worker, or retried through another channel. A documented host-side route or minimal non-sensitive diagnostic would help; private paths, IDs, code, and session logs remain excluded.

    Previously verified public references:
    #49036
    #49057
    https://github.com/openai/codex/releases/tag/rust-v0.160.0

  6. Nakagawa-master commented on Oct 6, 2026

    @Nakagawa-master

    Fresh source check makes the new transport observation more actionable.

    Current main already has a strong native MultiAgent V2 positive control for late root authorization:

    • LocalAgentControl::root_user_authorization() produces a GuardianRootSnapshot with an authoritative root_thread_id, history_reset_version, and authorization_version;
    • the local backend explicitly returns no package for the root, a non-V2 tree, or an unavailable root runtime;
    • the implementation resolves the root through the local runtime registry and requires MultiAgentVersion::V2;
    • guardian_subagent_review_preserves_late_root_user_authorization exercises a real later root user reply arriving after delegation;
    • Guardian review invalidates an allow if that authorization version changes before execution.

    That suggests a narrower question for this Dot -> connected-Windows-task case:

    native V2 worker can receive authoritative root authorization state
    !=
    a Dot-created cross-executor task necessarily has the same root-authority adapter
    

    The observation that the initial takeover arrives as an outer user delegation envelope while later approval updates arrive as outer tool delegation envelopes is consistent with a topology/adaptor gap: the later human decision may be transported as conversation data, while the child Guardian has no GuardianRootSnapshot tied to the actual Dot owner/root.

    I would test this without weakening the existing “tool/delegated transcript is not authorization” rule:

    1. Keep the existing native V2 late-root-authorization test as the positive control.
    2. Add the closest Dot/hosted -> connected-executor fixture available: create the child, then add a genuine direct parent-user approval after delegation.
    3. At the child's Guardian boundary, assert that the host supplies a non-empty authoritative root authorization package for that same parent/root and that its authorization_version advances. Do not make the outer tool-message delegation envelope authoritative.
    4. Retry the exact pending action and verify the new root authorization is the evidence being evaluated; then add a later root revocation and verify the already-prepared allow becomes stale before execution.
    5. If that cross-executor topology cannot supply a root authorization package at all, surface that as a distinct “trusted authorization route unavailable for this task topology” state instead of repeatedly forwarding approval prose and suggesting another retry.

    This does not establish that the production Dots path uses the same local V2 implementation, and I would not infer that from the public source. But it gives a concrete discriminator: if native V2 passes while the Dot/connected-executor adapter yields no authoritative root snapshot/version update, the missing seam is between the hosted root identity and the executor's Guardian authorization package—not in the wording of the forwarded approval.

    That also preserves the useful current invariant:

    message transport can carry evidence/context
    authority changes through an authenticated root-state transition
    

    rather than promoting an outer tool/delegation message into user authority.

  7. IFsub commented on Oct 11, 2026

    @IFsub

    Additional Windows evidence on October 11, 2026: an existing dot-delegated checker formally read a direct human authorization message through the native task API, but its subsequent single send was still rejected by automatic review.

    Observed sequence

    1. Dot successfully delivered a communication-only follow-up to the existing checker task. The checker reports hostId=durable; its exact hosted runtime/reviewer build is unknown.
    2. Initially, reading the dot parent as the authorization source returned turns:[], so the checker did not attempt a send.
    3. A later instruction pointed the checker to the human's actual message in an existing local desktop diagnostic conversation. The checker called mcp__codex_app__read_thread with hostId=local and successfully read that source. The desktop diagnostic conversation also independently read the same direct userMessage.
    4. The human message requested testing whether an accessible checker conversation could send to the previously specified local test conversation. The checker assessed that original message as explicitly covering this communication test. This observation does not establish which evidence the automatic reviewer received or whether it considered the authorization sufficiently specific.
    5. The checker read the target through the native API: hostId=local, idle, with only its initial completed turn and no test marker.
    6. At 04:00:57 UTC / 12:00:57 Asia/Shanghai, it submitted exactly one mcp__codex_app__send_message_to_thread call with the target ID, hostId=local (supported by its schema at this call), and a harmless test marker asking the target only to acknowledge in its own conversation, without tools, file changes, or messages to other tasks.

    The formal transcript records the authorization-read calls as completed and the send call as failed. In its final report, the checker quoted the following returned denial; the available transcript does not expose the reviewer's input:

    This action was rejected due to unacceptable risk.
    Reason: This sends a user-visible message to another task, but the transcript provides no trusted direct authorization for this exact send; prior delegated instructions are untrusted evidence.
    

    No successful turn ID or receive/reply acknowledgment was returned. A subsequent desktop read found no new target turn. The denied action remains stopped: no retry, alternate sender/path, or replacement task was used for it; this report makes no claim about unrelated later user setting changes.

    What this establishes and what remains unknown

    This differs from merely copying an approval sentence into a delegation wrapper: the acting task performed a supported native read of the original human message before the attempted send. However, successful evidence retrieval by the acting task is not proof that the reviewer received it as trusted authorization, selected the same message, or bound it to this exact action.

    We cannot inspect the reviewer's effective input, authenticated principal/root binding, or denial correlation metadata through the available public tools. We therefore do not claim a confirmed reviewer false positive or a proven common cause with task routing.

    The last locally verified desktop baseline (October 10) was release 26.1007.21434, Windows package 26.1007.2314.0, and bundled CLI 0.162.0-alpha.17.2; this does not identify the hosted checker's reviewer version.

    Related but separate failures: direct dot access to selected local tasks returns placement region 8/15 and NOT_FOUND (#50171). A desktop-native follow-up to this same checker also reproduced invalid turn/start params: AbsolutePathBuf deserialized without a base path on October 11; an earlier manual-input failure was reported in #50428. Dot's follow-up delivery to the checker worked. These are distinct paths, not a confirmed shared root cause.

    Requested clarification and safe recovery

    1. Is formally reading a direct human message from another conversation a supported trusted-authorization source for this dot-to-connected-task topology? If so, which provenance/binding information must reach automatic review?
    2. For this failure, please distinguish missing/unselected evidence, insufficient action specificity, unsupported cross-task authorization binding, and a review defect. Please identify what minimal private correlation data would enable that distinction.
    3. What supported same-task approval/denied-action recovery path should the user use, especially when direct input into the original checker can encounter the separate turn/start error? If an approval UI/command is appropriate, please specify its exact surface, version, and whether it merely records approval or immediately resumes the denied action.
    4. Please identify any applicable fixed release or server-side change without requiring review bypass, fabricated role markers, permission relaxation, or moving the denied send to another task.

    Published at the user's explicit request. Private conversation/message/tool-call IDs, device/account identifiers, source-message contents, local paths, and raw session logs are omitted.

  8. IFsub commented on Oct 11, 2026

    @IFsub

    Follow-up to the read-before-denial report above: the native approval-recovery UI is present, but its approval request fails with an unsupported-method error.

    On October 11, 2026, the owner opened the approval picker in the same existing checker conversation. The supplied screenshot shows a codex_app / send_message_to_thread denial row and the toast "无法记录自动审核批准" (could not record auto-review approval). This corrects the earlier owner description that no denial row was present. The screenshot alone does not expose the full selected action/event identifier; we are not publishing the screenshot because it contains unrelated private sidebar content.

    A bounded local desktop-log check independently found two failed approval requests for that checker at 04:26:52 UTC and 04:26:56 UTC / 12:26:52 and 12:26:56 Asia/Shanghai:

    method: thread/approveGuardianDeniedAction
    error.code: -32601
    error.message: unsupported app-server method: thread/approveGuardianDeniedAction
    

    Both were followed by the desktop log entry Failed to approve auto-review denial. The available entries identify the checker conversation and request IDs, but do not contain enough selected-event payload to independently bind the chosen row to a specific denial. Those private identifiers are retained locally and omitted here.

    Fresh native reads after these failures show no new checker turn and no new turn/test message in the local target. This is an approval-recording API failure, not evidence that a newly recorded human approval was evaluated and denied again, nor evidence that the original send was retried.

    Local package 26.1007.2314.0 includes the frontend approval picker and its thread/approveGuardianDeniedAction handler. This is static installed-client evidence only. The desktop command reference lists /approve, while Auto-review guidance describes exact-action, same-context one-retry approval. This observation does not establish whether the unsupported-method error originates in a routing adapter, hosted task service, or another protocol layer.

    Please clarify:

    1. Is this native approval method supported for dot-created tasks with this placement/runtime, and which component or capability gate determines availability?
    2. What client/server version or rollout enables it, or what supported same-task approval recovery path works when this method is unavailable?
    3. Can the UI avoid offering an approval action that its selected task endpoint cannot handle, and preserve the original denial/action binding for a later supported recovery?
    4. Which minimal private request/denial correlation data should we provide to identify the rejecting layer?

    No assistant-triggered retry, alternative execution, direct private-RPC invocation, permission relaxation, or application patch was performed for this follow-up. The original denied send remains stopped. The user's observed UI actions and this read-only log investigation are kept distinct.

  9. Shrey327 commented on Oct 20, 2026

    @Shrey327

    Additional macOS reproduction of the native approval-recording failure described in #50794 (comment), observed on 2026-10-20.

    Environment

    • Installed desktop app version: 26.1013.40934, build 20770, bundle identifier com.openai.codex (read from the installed app metadata).
    • Bundled CLI package metadata: 0.163.0-alpha.10.2. This identifies the bundled package, not the connected backend's version.
    • Platform: Darwin 25.6.0 arm64 arm.
    • A delegated task using the desktop app and a connected Mac executor, with Approve for me selected. Subscription was not collected.

    Observed behavior

    1. An action is denied by automatic review before execution.
    2. The human opens /approve; the desktop UI displays the retained denial picker.
    3. The human selects the denied action to approve one retry.
    4. The UI shows “Could not record auto-review approval.” No successful native override is confirmed.

    The existing desktop log contains 27 matching approval failures between 13:02:58.714 and 13:04:18.333 UTC. These are repeated user attempts to record approval, not 27 executions of the denied action. The relevant fields are:

    method: thread/approveGuardianDeniedAction
    error.code: -32601
    error.message: unsupported app-server method: thread/approveGuardianDeniedAction
    desktop log message: Failed to approve auto-review denial
    

    Static inspection of the installed frontend confirms that its picker handler sends thread/approveGuardianDeniedAction with threadId and the retained event, awaits that request, and only then records client-side approval / displays the success toast. The failure toast is its error path. The picker therefore exists; this is not an unavailable slash command or a reviewer rejecting an already-recorded approval.

    Public-source cross-check

    At public commit e1b9c9457ceca75a99b034a5df39ac48c3998d15, the local Rust app-server already supports this RPC:

    The exact string unsupported app-server method was not found in that checkout's codex-rs source. This suggests a connected-runtime compatibility/routing gap, but does not identify the rejecting service, prove a specific version mismatch, or establish whether local tasks are affected.

    Requested fix / regression coverage

    Please identify the component that rejects this method for the connected task and either implement its supported approval route or capability-gate the picker with an actionable unsupported-runtime message.

    Suggested coverage for that actual endpoint/client boundary:

    • Supported endpoint: record one exact, task-bound denial approval before displaying success; retain normal policy enforcement on the retry.
    • Unsupported endpoint (-32601): preserve the denial, show a precise compatibility error, and do not mark the action approved or execute/retry it.
    • Exercise connected/delegated task routing, not only the already-supported local Rust handler.

    Investigation was read-only: source inspection and extraction of the listed log fields. No code was changed, so no Rust test suite was run. The denied action was not retried, no private RPC was manually invoked, and no policy/permission changes or application patches were used to work around the denial.

    No screenshots, raw logs, credentials, action/event payloads, private task identifiers, filesystem paths, or unrelated conversation content are attached.

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

    appIssues related to the Codex desktop appbugSomething isn't workingdotsIssues involving setting up ChatGPT dots or managing their ongoing work.safety-checkIssues related to safety and abuse checkssubagentIssues involving subagents or multi-agent featureswindows-osIssues related to Codex on Windows systems

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions