Security Finding
Severity: medium
Type: unsafe-pattern (terminal escape / ANSI injection)
pluk sessions (src/sessions.ts discoverSessions + src/cli.ts cmdSessions) prints session names (derived from log filenames) and the cli/state fields parsed out of JSONL run-dir logs raw to the user's terminal. None of these values are sanitized, and JSONL logs are an open ingestion surface: anything able to append to a log file — or a hostile file planted in a directory passed via --run-dir/PLUK_RUN_DIR — controls them.
Reproduced on main (a3d2199): a log entry with "cli": "\u001b]0;PWNED\u0007claude" retitles the terminal window, and "to": "\u001b[2J\u001b[H..." clears the screen, when the victim runs pluk sessions.
Impact
Terminal escape injection against whoever runs pluk sessions: screen clearing/overwriting (spoofing status of other sessions), window retitling, and — on terminals with risky OSC support (e.g. OSC 52 clipboard write) — clipboard tampering. Historically this class has escalated to code execution on buggy terminals.
Recommendation
Strip C0 (0x00–0x1f), DEL (0x7f), and C1 (0x80–0x9f) control characters from every log- or filename-sourced field before rendering. Fix at ingestion in discoverSessions so both the table and --json paths emit clean values. Also stop advertising the shared predictable /tmp/pluk-run path in the CLI usage example (the run-dir hardening made the real default private) and fix the stale /var/run/pluk empty-state message.
Note: Subscriber's verbose logging (src/subscriber.ts) also echoes event.data['to'] raw to stderr, but that file is currently occupied by PR #59 — it should get the same sanitizeField treatment once #59 lands.
Filed by sec-check agent (ACMM L4/L5 — hold-gated mode)
🐝 Hive Agent: security | Instance: hosted-available-oke-11-placeholder-r05x | SHA: unknown
— hive: agent=sec-check backend=copilot model=claude-fable-5 copilot=1.0.88
Security Finding
Severity: medium
Type: unsafe-pattern (terminal escape / ANSI injection)
pluk sessions(src/sessions.tsdiscoverSessions+ src/cli.tscmdSessions) prints session names (derived from log filenames) and thecli/statefields parsed out of JSONL run-dir logs raw to the user's terminal. None of these values are sanitized, and JSONL logs are an open ingestion surface: anything able to append to a log file — or a hostile file planted in a directory passed via--run-dir/PLUK_RUN_DIR— controls them.Reproduced on main (a3d2199): a log entry with
"cli": "\u001b]0;PWNED\u0007claude"retitles the terminal window, and"to": "\u001b[2J\u001b[H..."clears the screen, when the victim runspluk sessions.Impact
Terminal escape injection against whoever runs
pluk sessions: screen clearing/overwriting (spoofing status of other sessions), window retitling, and — on terminals with risky OSC support (e.g. OSC 52 clipboard write) — clipboard tampering. Historically this class has escalated to code execution on buggy terminals.Recommendation
Strip C0 (0x00–0x1f), DEL (0x7f), and C1 (0x80–0x9f) control characters from every log- or filename-sourced field before rendering. Fix at ingestion in
discoverSessionsso both the table and--jsonpaths emit clean values. Also stop advertising the shared predictable/tmp/pluk-runpath in the CLI usage example (the run-dir hardening made the real default private) and fix the stale/var/run/plukempty-state message.Note:
Subscriber's verbose logging (src/subscriber.ts) also echoesevent.data['to']raw to stderr, but that file is currently occupied by PR #59 — it should get the samesanitizeFieldtreatment once #59 lands.Filed by sec-check agent (ACMM L4/L5 — hold-gated mode)
🐝 Hive Agent:
security| Instance:hosted-available-oke-11-placeholder-r05x| SHA:unknown— hive: agent=sec-check backend=copilot model=claude-fable-5 copilot=1.0.88