Skip to content

Commit ce13df5

Browse files
liangweifengclaude
andcommitted
fix: prevent stale stopRecording from nullifying new recorder
Adversarial user audit found: rapid hotkey presses (record→stop→record) could cause stopRecording's `await recorder.stop()` to resolve after a new startRecording created a fresh recorder. The old stopRecording then set `recorderRef.current = null`, orphaning the new recorder and leaving the app permanently stuck in recording state. Fix: capture recorder in local variable at stopRecording start, release recorderRef immediately. The awaited stop() operates on the local reference, never touching the new recorder. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent bf0a8f2 commit ce13df5

1 file changed

Lines changed: 6 additions & 3 deletions

File tree

src/hooks/useRecorder.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,11 @@ export function useRecorder() {
135135
}, []);
136136

137137
const stopRecording = useCallback(async () => {
138-
if (!recorderRef.current) return;
138+
// Capture recorder locally — prevents a concurrent startRecording() from
139+
// creating a new recorder that we then accidentally null out after await
140+
const recorder = recorderRef.current;
141+
if (!recorder) return;
142+
recorderRef.current = null; // release ref immediately so startRecording can proceed
139143

140144
if (timerRef.current) {
141145
clearInterval(timerRef.current);
@@ -152,8 +156,7 @@ export function useRecorder() {
152156
setState((s) => ({ ...s, status: 'processing', audioLevel: 0 }));
153157

154158
try {
155-
const audioBuffer = await recorderRef.current.stop();
156-
recorderRef.current = null;
159+
const audioBuffer = await recorder.stop();
157160

158161
// Save audio to file (not inline base64 — keeps config.json small)
159162
let audioPath: string | undefined;

0 commit comments

Comments
 (0)