Bug: WIF OIDC token refresh can recreate credentials on disk after handle.stop()

Author: SparshM8Created Sep 15, 2026Updated Sep 15, 2026
Labelsbugduplicateprovider:1pp3

Summary

In base-action/src/workload-identity.ts, the asynchronous background token refresh interval (setInterval) does not cancel in-flight HTTP requests when stop() is called. If the action concludes and src/entrypoints/run.ts executes workloadIdentity?.stop() in its finally block, a pending getIDToken() request can still resolve later, recreating the deleted .claude/ credential directory and token file on disk.

Problem & Failure Scenario

  1. Pending Token Request Continues: The 4-minute token refresh interval triggers an asynchronous OIDC request (getIDToken()).
  2. Orchestrator Shutdown: The agent run finishes while that request is still pending. src/entrypoints/run.ts executes workloadIdentity?.stop() in its finally block.
  3. Post-Cleanup Write: clearInterval() stops future intervals but cannot cancel an in-flight promise. When getIDToken() resolves, execution continues past await and executes mkdirSync and writeFileSync, recreating the credential files after cleanup.
  4. Partial Initialization Leak: If profile generation throws after the identity token has been written, orphaned token files remain without an exported cleanup handle.

Steps to Reproduce

  1. Configure workload identity federation with a delayed or mocked asynchronous getIDToken() response.
  2. Call handle.stop() while the refresh request is still in flight.
  3. Observe that stop() clears the directory and token file.
  4. Let the pending getIDToken() promise resolve.
  5. Notice that the credential directory and token file are recreated on disk.

Expected Behavior

Once handle.stop() is invoked, any in-flight or subsequent token resolution must be discarded synchronously without performing disk mutations, ensuring no credential remnants persist on the runner.

Proposed Fix / Pull Request

Resolved by #1831.

Source: anthropics/claude-code-action