Skip to content

Fix security and reliability issues#401

Open
hobostay wants to merge 1 commit intosiddharthvaddem:mainfrom
hobostay:fix/bug-fixes-security-and-reliability
Open

Fix security and reliability issues#401
hobostay wants to merge 1 commit intosiddharthvaddem:mainfrom
hobostay:fix/bug-fixes-security-and-reliability

Conversation

@hobostay
Copy link
Copy Markdown

@hobostay hobostay commented Apr 9, 2026

Summary

  • Security: Validate URL scheme in open-external-url handler — The shell.openExternal(url) call accepted any URL without validation, allowing file://, javascript:, or other dangerous schemes. Now only http:, https:, and mailto: are permitted.
  • Bug: Fix latest video detection using mtimeget-recorded-video-path used lexicographic sort to find the latest recording (videoFiles.sort().reverse()[0]), which is unreliable (e.g. recording-9.webm sorts after recording-10.webm). Now sorts by file modification time.
  • Bug: Add null guard for AudioData.formatcloneWithTimestamp used a non-null assertion (src.format!) that could throw an unhelpful error if format is null. Now validates upfront with a descriptive error message.
  • Bug: Prevent encodeQueue underflow — The encodeQueue counter in VideoExporter could go negative if the encoder's output callback fires more times than expected. Added Math.max(0, ...) guard.

Test plan

  • Verify open-external-url blocks file:///etc/passwd and allows https://example.com
  • Create multiple recordings (recording-9, recording-10, etc.) and verify the latest is returned
  • Export a project with audio and verify no regression in audio processing
  • Export a video project and verify no regression in export pipeline

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Fixed video recording detection to use actual file modification times when identifying the latest recording, replacing filename-based sorting.
    • Enhanced external URL handling with validation and restricted protocol support (http, https, mailto only).
    • Fixed audio encoder format field validation to ensure required data is present.
    • Fixed video encoder queue management to prevent underflow conditions.

1. Validate URL scheme in open-external-url handler
   - Prevent opening file:// or other dangerous schemes via shell.openExternal
   - Only allow http:, https:, and mailto: protocols

2. Fix latest video detection using mtime instead of lexicographic sort
   - Lexicographic sort gives wrong results (e.g. recording-9 > recording-10)
   - Now sorts by file modification time for reliable latest-file detection

3. Add null guard for AudioData.format in cloneWithTimestamp
   - Replace non-null assertion (!) with proper validation
   - Throws descriptive error if format is unexpectedly null

4. Prevent encodeQueue counter underflow in VideoExporter
   - Use Math.max(0, ...) to prevent negative queue count

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

📝 Walkthrough

Walkthrough

Three targeted robustness improvements: video recording lookup now uses filesystem modification timestamps instead of filename sorting, the URL handler validates and restricts to safe protocols (http:, https:, mailto:), the audio encoder explicitly requires format field presence, and the video encoder prevents queue counter underflow.

Changes

Cohort / File(s) Summary
IPC Handler Updates
electron/ipc/handlers.ts
"get-recorded-video-path" handler switched from lexicographic filename sorting to filesystem mtimeMs comparison for selecting latest video; handles inaccessible files gracefully. "open-external-url" handler now validates URL format and restricts opening to http:, https:, and mailto: schemes, rejecting others.
Audio Encoder Validation
src/lib/exporter/audioEncoder.ts
cloneWithTimestamp now explicitly requires AudioData.format to be present, throwing an error if missing instead of silently accepting falsy values. Removed non-null assertion in favor of direct format field passing.
Video Encoder Queue Safety
src/lib/exporter/videoExporter.ts
Encoder output callback prevents encodeQueue counter underflow by clamping decrement to zero with Math.max(0, this.encodeQueue - 1).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🎬✨ files now sorted by their age, not their name,
urls checked before they play the game,
formats required, queues that don't go below,
electron flows safer, now we can go—
lowkey risky edge cases: handled ⚙️

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately summarizes the main changes: security validation and bug fixes for reliability. Specific enough for scanning history.
Description check ✅ Passed PR description comprehensively covers all changes with clear motivation, includes testing checklist, but doesn't follow the repo's required template structure.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@electron/ipc/handlers.ts`:
- Around line 636-648: The code validates the URL but calls
shell.openExternal(url) with the original string; instead re-serialize the
parsed URL to ensure a normalized, validated value is used—after the
ALLOWED_SCHEMES check and using the parsed variable (e.g., parsed.toString() or
parsed.href) pass that into shell.openExternal rather than the raw url string to
follow Electron's recommended pattern.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0bcf54bc-0dcf-4d1d-a577-ef47abd7f55c

📥 Commits

Reviewing files that changed from the base of the PR and between e7d5f51 and cf6dce5.

📒 Files selected for processing (3)
  • electron/ipc/handlers.ts
  • src/lib/exporter/audioEncoder.ts
  • src/lib/exporter/videoExporter.ts

Comment on lines +636 to 648
const ALLOWED_SCHEMES = ["http:", "https:", "mailto:"];
let parsed: URL;
try {
parsed = new URL(url);
} catch {
return { success: false, error: "Invalid URL" };
}

if (!ALLOWED_SCHEMES.includes(parsed.protocol)) {
return { success: false, error: `Unsupported URL scheme: ${parsed.protocol}` };
}

await shell.openExternal(url);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Electron shell.openExternal security guidance for untrusted URLs: should validated URLs be normalized/canonicalized (for example with new URL(url).toString()) before calling shell.openExternal?

💡 Result:

Electron’s own guidance is not “normalize then call shell.openExternal”; it’s don’t call shell.openExternal on untrusted input at all, and if you must support user-provided links, parse with a real URL parser and enforce a strict allowlist (protocol and often host/origin). (electronjs.org)

So: canonicalizing (e.g., new URL(url).toString()) is not a security control by itself. It may make the string more consistent, but it doesn’t address the core risk (opening attacker-chosen schemes/handlers that can lead to code execution via OS protocol/file associations). (electronjs.org)

Practical recommendation (safe pattern):

  • Parse: const u = new URL(input)
  • Allowlist: permit only the exact schemes you intend (commonly https: / http:; maybe mailto:), and ideally also allowlist hosts/origins for web links. (electronjs.org)
  • Then call shell.openExternal(u.toString()) (or u.href) only after the allowlist checks. (Re-serializing is fine for consistency, just don’t treat it as the “security step”.) (electronjs.org)

Citations:


Use the normalized URL for consistency with Electron's recommended pattern.

The allowlist check is solid, but Electron's official security guidance suggests passing parsed.toString() (or parsed.href) to shell.openExternal after validation. Since you're already parsing and checking, re-serializing the normalized version is cleaner and follows the standard pattern.

fix
 			if (!ALLOWED_SCHEMES.includes(parsed.protocol)) {
 				return { success: false, error: `Unsupported URL scheme: ${parsed.protocol}` };
 			}
 
-			await shell.openExternal(url);
+			await shell.openExternal(parsed.toString());
 			return { success: true };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@electron/ipc/handlers.ts` around lines 636 - 648, The code validates the URL
but calls shell.openExternal(url) with the original string; instead re-serialize
the parsed URL to ensure a normalized, validated value is used—after the
ALLOWED_SCHEMES check and using the parsed variable (e.g., parsed.toString() or
parsed.href) pass that into shell.openExternal rather than the raw url string to
follow Electron's recommended pattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant