Skip to content

Hold-mode recording has no maximum-duration safeguard after a missed key release #25

Description

@MaxiKingXXL

Summary

In hold-to-record mode, a recording has no built-in maximum duration. If the global keyboard listener observes a hotkey press but not the corresponding release, the microphone remains active until another code path stops the shared recorder or the process exits.

A later hotkey event can then flush the accumulated audio through the wrong pipeline. This may cause unintended background audio to be transcribed, processed or pasted into the currently focused application.

Affected configuration

HOLD_TO_RECORD = True

Hold-to-record is the default mode.

The issue is independent of the specific keys assigned to Dictation and Assistant.

Reproduction

The operating-system-level loss of a release event may be environment-dependent, but the resulting application behavior can be reproduced deterministically:

  1. Enable hold-to-record mode.
  2. Start either Dictation or Assistant recording.
  3. Allow the press callback to execute without delivering the matching release callback.
  4. Wait longer than MAX_RECORD_SECONDS.
  5. Observe that the recorder remains active because no timeout is armed in hold mode.
  6. Optionally start the other recording mode and release it.
  7. Observe that the shared recorder’s accumulated buffer can be processed by the second mode.

Actual behavior

  • A hold-mode recording has no upper time limit.
  • The microphone and recording UI can remain active indefinitely.
  • A later stop callback can process the entire accumulated audio buffer.
  • Audio started under Assistant can be delivered to the Dictation pipeline, or vice versa.
  • Dictation may paste the resulting transcript into an unrelated focused window.
  • The reported duration may be incorrect because both modes share the same start timestamp.

Expected behavior

A missed key-release must not allow an unbounded recording.

An abnormally terminated or ambiguous recording should be stopped and discarded without transcription, Assistant processing or clipboard injection.

Events belonging to an older recording session must not be able to stop or flush a newer session.

Root cause

1. No safety timer in hold mode

_start_timeout() returns immediately when config.HOLD_TO_RECORD is true.

As a result, MAX_RECORD_SECONDS only arms a timer in toggle mode. Nothing bounds a hold-mode recording when its release event is not observed.

2. The force-stop methods do not handle hold mode

force_stop_dictation() and force_stop_assistant() only check the toggle-mode state:

_dict_recording
_assist_recording

Hold mode instead tracks:

_dict_pressed
_assist_pressed

The current force-stop methods therefore cannot stop an active hold-mode recording.

3. Dictation and Assistant share one recorder and start timestamp

Both modes use the same Recorder instance and the same global _rec_start, while maintaining separate hotkey state and timers.

There is no recording-session owner or generation identifier. Both modes can therefore believe they are active simultaneously, and a stale release or timer can affect a newer recording.

4. Recorder.start() silently preserves an active session

When recording is already active, Recorder.start() performs:

if self.recording:
    return

It does not reject, clear or explicitly transfer ownership of the existing buffer.

The caller nevertheless updates its mode state, UI and start timestamp as if a new recording had started. A later stop callback from that mode can consequently flush audio belonging to the earlier recording.

Impact

This is a privacy and failure-containment issue.

A single missed key-release can leave the microphone recording for an unbounded period without further user interaction. Depending on which stop callback eventually reaches the shared recorder, accumulated audio may be:

  • transcribed as Dictation,
  • sent through the Assistant pipeline,
  • pasted into an unrelated focused window,
  • written to transcript recovery or log files.

The problem does not depend on a particular hotkey, application, conferencing platform or recording duration.

Suggested direction

The implementation design is up to the project, but the fix should provide the following guarantees:

  • Apply a hard maximum-recording limit in both hold and toggle modes.
  • Treat the hard safety limit as an abnormal abort:
    • stop and close the microphone stream,
    • discard the buffered audio,
    • perform no transcription, Assistant processing or paste.
  • Allow the safety path to stop hold-mode recordings.
  • Give the shared recorder a single active owner and recording-session identifier.
  • Ignore stale timers and release events belonging to an older session.
  • Prevent Recorder.start() from silently inheriting an existing session’s buffer.
  • Safely discard ambiguous audio when Dictation and Assistant overlap.
  • After a hold-mode safety abort, ignore repeated press events until a real release is observed.

Suggested regression coverage

Tests should verify that:

  1. A hold-mode recording is stopped and discarded at the hard limit.
  2. A repeated press after timeout cannot restart recording before a release.
  3. An Assistant recording with a missed release cannot leak into Dictation.
  4. A stale Assistant timer or release cannot stop a newer Dictation session.
  5. A stale Dictation timer or release cannot stop a newer Assistant session.
  6. Simultaneous timeout and release result in at most one stop.
  7. Safety tests do not access a real microphone or produce desktop side effects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions