anthropics / anthropics/claude-code-action
Image downloads use a shared /tmp directory and collision-prone filenames across concurrent runs
- Dominant language
- TypeScript
- Stars
- 8.9k
- Forks
- 2.1k
- PR merge metrics
- PR metrics pending
Description
## Summary
Image downloads are written to a process-wide `/tmp/github-images` directory using filenames based only on `Date.now()` and the image index. On a persistent self-hosted runner, concurrent action jobs can overwrite one another's files.
## Reproduction
1. Run two Claude Code Action jobs concurrently on the same self-hosted runner.
2. Have both jobs process a comment or PR body containing an image.
3. If both downloads reach the filename expression in the same millisecond, or if the same generated name is reused by concurrent invocations, both jobs target the same path such as `/tmp/github-images/image--0.png`.
4. Let one job finish writing while the other job is still using the path supplied in its image URL map.
A deterministic unit test can reproduce the collision by mocking `Date.now()` to return the same value for two concurrent calls to `downloadCommentImages`.
## Expected behavior
Each action invocation should use an isolated temporary directory and collision-resistant filenames. A job should never be able to replace an image file that another job is about to send to Claude.
## Actual behavior
`src/github/utils/image-downloader.ts:95` hard-codes `/tmp/github-images`, and `src/github/utils/image-downloader.ts:264-267` creates and writes `image-${Date.now()}-${i}${extension}`. The per-invocation URL-to-path map does not prevent another invocation from writing the same path. Files are also not removed after the invocation, so persistent runners accumulate prior job artifacts.
## Why this matters
The wrong image can be supplied to Claude for a different repository or workflow run, producing incorrect analysis. On shared self-hosted runners, this also breaks job isolation and can leave user-provided issue/PR attachments in a shared directory after the job ends.
## Suggested fix
Create a per-invocation directory below `RUNNER_TEMP` (for example with `mkdtemp`), use a UUID/random component or exclusive file creation for each filename, and clean the directory in a `finally` block after all consumers have finished reading the images. Add a concurrent-invocation regression test.
## Related
This is separate from #702 and #1351, which concern the image MIME type, and from the merged #1588, which concerns pairing source URLs with signed asset URLs.
Contributor guide
Assessment
This issue has not been assessed yet.