Skip to content

Operational follow-ups for paste-image endpoint (#84) #88

@Ark0N

Description

@Ark0N

Operational gaps in the paste-image endpoint introduced in #84 — non-security, but worth filing so they don't get lost.

1. No rate-limit and no GC for .claude-images/

The endpoint enforces a 10MB per-request cap (src/web/server.ts:929-936) but no aggregate cap, no per-IP token-bucket, and cleanup only runs when killMux=true on session destroy. Soft-closed sessions leave their image dirs on disk indefinitely. An authenticated user (or anyone if CODEMAN_PASSWORD is unset and the instance is tunneled) can loop 10MB POSTs to fill the disk.

Fix: add a per-IP token-bucket on /api/sessions/:id/paste-image (e.g., 30/min, 100MB/hr); reject if du -s .claude-images/ exceeds a per-session cap; periodic GC of files older than 7 days even without killMux=true.

2. Filename collision on same-millisecond uploads

paste-${Date.now()}${ext} (src/web/routes/session-routes.ts:~1545) collides under concurrent paste from two browser tabs. Last-write-wins overwrites the prior file silently, and the response's path still references the (now-overwritten) name — the first uploader's terminal @-mentions a file whose contents are the second uploader's image.

Fix: append randomBytes(8).toString('hex') (or use randomUUID()) so concurrent uploads never collide.

3. Bracketed-paste bypass on Ctrl+V

The Ctrl+V interceptor in src/web/public/terminal-ui.js:86-92 swallows all paste events and re-sends text via sendInput(), which strips xterm's bracketed-paste markers. Claude CLI / bash can no longer distinguish "typed" from "pasted" text — relevant to prompt-injection defences in Claude Code, which treat bracketed-paste content differently.

Fix: detect "no image" early and return true from customKeyEventHandler so xterm's native paste flow handles the text path with bracketed-paste preserved.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions