Skip to content

Comments

🛡️ Sentinel: Fix file upload vulnerability by verifying magic bytes#58

Open
Krosebrook wants to merge 2 commits intomainfrom
sentinel/fix-file-upload-validation-11126110579953094161
Open

🛡️ Sentinel: Fix file upload vulnerability by verifying magic bytes#58
Krosebrook wants to merge 2 commits intomainfrom
sentinel/fix-file-upload-validation-11126110579953094161

Conversation

@Krosebrook
Copy link
Owner

@Krosebrook Krosebrook commented Feb 17, 2026

Vulnerability: The /api/audio/generate-with-reference endpoint relied on file.mimetype (client-controlled) to validate uploads, allowing potential malicious file uploads (e.g. executables).

Fix:

  1. Refactored detectAudioFormat from server/replit_integrations/audio/client.ts to server/utils.ts.
  2. Enhanced detectAudioFormat to support FLAC and AAC magic bytes.
  3. Updated server/routes.ts to use detectAudioFormat to verify the actual file buffer before processing.
  4. Ensured backward compatibility for server/replit_integrations/audio/client.ts.

Verification:

  • Verified with server/test_audio_detect.ts (7/7 passed for WAV, MP3, FLAC, AAC, EXE, Empty, Short).
  • Ran pnpm check to ensure type safety.

PR created automatically by Jules for task 11126110579953094161 started by @Krosebrook


Summary by cubic

Secures /api/audio/generate-with-reference by verifying uploaded files with magic bytes instead of mimetype. Blocks non-audio files and adds FLAC/AAC support.

  • Bug Fixes

    • Validate file buffers with detectAudioFormat; return 400 on unknown formats with a clear error.
    • Hardened WAV detection to require the RIFF...WAVE signature.
  • Refactors

    • Moved detectAudioFormat to server/utils and re-exported from audio/client for compatibility.
    • Updated ensureCompatibleFormat and tests (7 cases).

Written for commit a30ec5a. Summary will update on new commits.

Summary by CodeRabbit

  • Bug Fixes

    • Audio generation endpoint now validates uploaded audio and rejects unknown formats with a clear 400 error, reducing failed processing and improving error clarity.
  • New Features

    • Improved audio format detection with support for WAV, MP3, WebM, MP4, OGG, FLAC, and AAC.
    • Audio format detection is now available for reuse across the server.

- Refactored detectAudioFormat to server/utils.ts
- Added FLAC and AAC support to magic byte detection
- Enforced magic byte validation on /api/audio/generate-with-reference endpoint

Co-authored-by: Krosebrook <214532761+Krosebrook@users.noreply.github.com>
Copilot AI review requested due to automatic review settings February 17, 2026 05:57
@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @Krosebrook, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request implements a critical security enhancement by addressing a file upload vulnerability in the audio generation endpoint. It centralizes and significantly improves audio file format detection using magic bytes, moving away from unreliable client-provided MIME types. This robust server-side validation prevents the upload and processing of invalid or malicious files, thereby bolstering the application's security posture.

Highlights

  • Vulnerability Fix: Addressed a file upload vulnerability in the /api/audio/generate-with-reference endpoint by replacing client-controlled file.mimetype validation with robust server-side magic byte verification.
  • Code Refactoring: Relocated the detectAudioFormat function and AudioFormat type definition from server/replit_integrations/audio/client.ts to server/utils.ts to centralize utility functions and improve modularity.
  • Enhanced Audio Detection: Extended the detectAudioFormat utility to support FLAC and AAC audio formats, in addition to existing WAV, MP3, WebM, MP4, and OGG formats, for more comprehensive file identification.
  • Security Integration: Integrated the enhanced detectAudioFormat into server/routes.ts to perform content-based validation of uploaded audio files, ensuring only legitimate audio formats are processed and rejecting unknown or potentially malicious files.
  • Backward Compatibility: Maintained backward compatibility for server/replit_integrations/audio/client.ts by re-exporting the moved detectAudioFormat function and AudioFormat type, preventing breaking changes.
Changelog
  • server/replit_integrations/audio/client.ts
    • Removed the AudioFormat type definition.
    • Removed the detectAudioFormat function implementation.
    • Imported and re-exported detectAudioFormat and AudioFormat from ../../utils.
    • Updated comments in ensureCompatibleFormat to reflect newly supported formats (FLAC, AAC).
  • server/routes.ts
    • Imported detectAudioFormat from ../utils.
    • Added a new validation step in the /api/audio/generate-with-reference endpoint to verify uploaded audio files using detectAudioFormat and reject unknown formats.
  • server/utils.ts
    • Imported Buffer from node:buffer.
    • Defined the AudioFormat type, including new "flac" and "aac" options.
    • Implemented the detectAudioFormat function, which identifies audio formats based on magic bytes, now supporting WAV, MP3, WebM, MP4, OGG, FLAC, and AAC.
Activity
  • Verified the fix using server/test_audio_detect.ts, with all 7 tests passing for various audio formats and edge cases (WAV, MP3, FLAC, AAC, EXE, Empty, Short).
  • Confirmed type safety by running pnpm check.
  • The pull request was automatically created by Jules for task 11126110579953094161.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Feb 17, 2026

📝 Walkthrough

Walkthrough

Centralizes audio format detection by adding detectAudioFormat and AudioFormat in server/utils.ts, re-exports them from server/replit_integrations/audio/client.ts, and adds an upload-time format verification in server/routes.ts that rejects unknown audio formats.

Changes

Cohort / File(s) Summary
Audio utilities
server/utils.ts
Adds AudioFormat type and detectAudioFormat(buffer: Buffer) that detects wav, mp3, webm, mp4, ogg, flac, aac or returns unknown. Exports made public.
Client re-exports
server/replit_integrations/audio/client.ts
Removes local detectAudioFormat/AudioFormat implementations and re-exports them from ../../utils. Keeps ensureCompatibleFormat but now uses imported detectAudioFormat.
Route validation
server/routes.ts
In POST /api/audio/generate-with-reference, calls detectAudioFormat on uploaded buffer and returns 400 with "Invalid audio file format (verification failed)" when format is unknown.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I sniff the bytes with twitchy nose,
Magic headers tell me how it goes,
Shared tools now hop from file to file,
I guard uploads with a careful smile,
Hooray — formats found, and bugs beguiled. 🎶

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding magic byte verification to fix a file upload vulnerability, which aligns with the core objective of the PR.

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

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sentinel/fix-file-upload-validation-11126110579953094161

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
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

The pull request successfully addresses the file upload vulnerability by implementing magic byte verification for audio uploads. Moving the detection logic to a centralized utility and expanding support for FLAC and AAC are excellent improvements for both security and maintainability. I have provided a suggestion to refine the WAV detection logic to ensure it specifically identifies WAV files among other RIFF-based formats, which further strengthens the security gate.

Comment on lines +64 to +67
if (
(buffer[0] === 0xff && (buffer[1] === 0xfb || buffer[1] === 0xfa || buffer[1] === 0xf3)) ||
(buffer[0] === 0x49 && buffer[1] === 0x44 && buffer[2] === 0x33)
) {
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The MP3 detection logic is quite restrictive, checking only for specific frame sync patterns and ID3 tags. Because the AAC check (line 84) is broader and follows this check, many valid MP3 files that don't match these specific patterns will be misidentified as aac. While this still passes the security gate, it will cause ensureCompatibleFormat to unnecessarily convert these MP3 files to WAV, impacting performance.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 417ae85f07

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
// AAC: ADTS header (FFF1 or FFF9 usually)
// Sync word 111111111111 (12 bits)
if (buffer[0] === 0xff && (buffer[1] & 0xf0) === 0xf0) {

Choose a reason for hiding this comment

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

P1 Badge Tighten AAC signature check to block forged uploads

The new upload guard in server/routes.ts accepts any file when detectAudioFormat(...) !== "unknown", but this AAC branch treats any buffer starting with 0xFF plus a high nibble of 0xF as valid AAC. That pattern is broad enough that a crafted non-audio payload can be prefixed to satisfy the check and bypass the intended hardening, so the vulnerability fix is still bypassable for this endpoint when attackers control upload bytes and MIME type.

Useful? React with 👍 / 👎.

Copy link

@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.

🧹 Nitpick comments (2)
server/routes.ts (1)

1151-1155: Good security fix — but consider using the detected format for the data URL too.

Line 1163 still uses the client-controlled file.mimetype to build the dataUrl. After validating magic bytes, you could derive the correct MIME type from detectedFormat instead, closing the remaining gap where a user could supply a misleading MIME type (e.g., audio/wav for an actual MP3).

♻️ Suggested improvement
+      const mimeMap: Record<string, string> = {
+        wav: "audio/wav",
+        mp3: "audio/mpeg",
+        webm: "audio/webm",
+        mp4: "audio/mp4",
+        ogg: "audio/ogg",
+        flac: "audio/flac",
+        aac: "audio/aac",
+      };
+
       const base64 = file.buffer.toString("base64");
-      const dataUrl = `data:${file.mimetype};base64,${base64}`;
+      const dataUrl = `data:${mimeMap[detectedFormat] ?? file.mimetype};base64,${base64}`;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/routes.ts` around lines 1151 - 1155, After verifying audio magic bytes
with detectAudioFormat and assigning detectedFormat, stop using the
client-supplied file.mimetype when constructing the data URL; instead map
detectedFormat to the correct MIME type and use that value for the dataUrl.
Locate where dataUrl is built (references to dataUrl and file.mimetype) and
replace the mimetype source with a safe mapping derived from detectedFormat
(e.g., "audio/mpeg" for "mp3", "audio/wav" for "wav"), preserving the base64
encoding logic.
server/utils.ts (1)

63-86: MP3 frame-sync and AAC ADTS detection overlap.

The MP3 check at lines 64-68 only covers three specific sync-word second bytes (0xFB, 0xFA, 0xF3). Other valid MP3 frame-sync patterns (e.g., 0xFF 0xF2 for MPEG 2.5 Layer III) will fall through and be misidentified as AAC by the broader check at line 84. This doesn't affect the security goal (both are valid audio), but could cause incorrect format labeling downstream.

A more precise ADTS check would also verify that the layer bits (bits 1–2 of byte 1) are 00:

♻️ Optional: tighten the AAC check
-  // AAC: ADTS header (FFF1 or FFF9 usually)
-  // Sync word 111111111111 (12 bits)
-  if (buffer[0] === 0xff && (buffer[1] & 0xf0) === 0xf0) {
+  // AAC: ADTS sync word (12 bits = 0xFFF) with layer bits == 00
+  if (buffer[0] === 0xff && (buffer[1] & 0xf6) === 0xf0) {
     return "aac";
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/utils.ts` around lines 63 - 86, The MP3 detection is too narrow (only
checks buffer[1] === 0xFB/0xFA/0xF3) and the subsequent AAC ADTS check
((buffer[0] === 0xff && (buffer[1] & 0xf0) === 0xf0)) will mislabel some MP3
variants as AAC; update the checks in the detection block so MP3 frame-sync
covers all valid second-byte sync patterns (e.g., any 0xE0-0xFF values with
appropriate MPEG/version/layer bits) or tighten the AAC ADTS check by verifying
the ADTS layer bits are 00 (bits 1–2 of buffer[1]) before returning "aac";
locate and modify the existing MP3/ADTS conditionals in server/utils.ts (the
buffer[...] checks) to implement one of these fixes so MP3 variants like 0xFF
0xF2 are correctly identified as "mp3".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@server/routes.ts`:
- Around line 1151-1155: After verifying audio magic bytes with
detectAudioFormat and assigning detectedFormat, stop using the client-supplied
file.mimetype when constructing the data URL; instead map detectedFormat to the
correct MIME type and use that value for the dataUrl. Locate where dataUrl is
built (references to dataUrl and file.mimetype) and replace the mimetype source
with a safe mapping derived from detectedFormat (e.g., "audio/mpeg" for "mp3",
"audio/wav" for "wav"), preserving the base64 encoding logic.

In `@server/utils.ts`:
- Around line 63-86: The MP3 detection is too narrow (only checks buffer[1] ===
0xFB/0xFA/0xF3) and the subsequent AAC ADTS check ((buffer[0] === 0xff &&
(buffer[1] & 0xf0) === 0xf0)) will mislabel some MP3 variants as AAC; update the
checks in the detection block so MP3 frame-sync covers all valid second-byte
sync patterns (e.g., any 0xE0-0xFF values with appropriate MPEG/version/layer
bits) or tighten the AAC ADTS check by verifying the ADTS layer bits are 00
(bits 1–2 of buffer[1]) before returning "aac"; locate and modify the existing
MP3/ADTS conditionals in server/utils.ts (the buffer[...] checks) to implement
one of these fixes so MP3 variants like 0xFF 0xF2 are correctly identified as
"mp3".

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a critical file upload security vulnerability in the /api/audio/generate-with-reference endpoint by implementing magic byte validation. Previously, the endpoint relied solely on client-controlled MIME types, which could allow malicious file uploads. The fix refactors the detectAudioFormat function from a specialized module to a shared utility, extends it to support FLAC and AAC formats, and applies it to verify uploaded file signatures before processing.

Changes:

  • Centralized audio format detection by moving detectAudioFormat from server/replit_integrations/audio/client.ts to server/utils.ts
  • Enhanced format detection to support FLAC and AAC magic bytes
  • Added magic byte verification to the file upload endpoint to prevent malicious uploads

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
server/utils.ts Added detectAudioFormat function with magic byte detection for WAV, MP3, WebM, MP4, OGG, FLAC, and AAC formats
server/routes.ts Implemented file signature validation using detectAudioFormat before processing uploaded audio files
server/replit_integrations/audio/client.ts Refactored to import and re-export detectAudioFormat from utils.ts for backward compatibility

Comment on lines +83 to +84
// Sync word 111111111111 (12 bits)
if (buffer[0] === 0xff && (buffer[1] & 0xf0) === 0xf0) {
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

The AAC detection pattern (checking if buffer[0] is 0xff and buffer[1] & 0xf0 equals 0xf0) can false-positive on MP3 files that start with frame sync patterns like 0xFFFA, 0xFFFB, or 0xFFF3. Since MP3 is checked earlier, this won't cause misidentification, but it means some MP3 files could theoretically match both patterns. Consider adding a comment explaining that the order of checks matters, or make the AAC check more specific by excluding known MP3 sync patterns.

Suggested change
// Sync word 111111111111 (12 bits)
if (buffer[0] === 0xff && (buffer[1] & 0xf0) === 0xf0) {
// Sync word 111111111111 (12 bits). Exclude known MP3 sync patterns already handled above.
if (
buffer[0] === 0xff &&
(buffer[1] & 0xf0) === 0xf0 &&
buffer[1] !== 0xfa &&
buffer[1] !== 0xfb &&
buffer[1] !== 0xf3
) {

Copilot uses AI. Check for mistakes.
Comment on lines 52 to 89
export function detectAudioFormat(buffer: Buffer): AudioFormat {
if (buffer.length < 12) return "unknown";

// WAV: RIFF....WAVE
if (buffer[0] === 0x52 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x46) {
return "wav";
}
// WebM: EBML header
if (buffer[0] === 0x1a && buffer[1] === 0x45 && buffer[2] === 0xdf && buffer[3] === 0xa3) {
return "webm";
}
// MP3: ID3 tag or frame sync
if (
(buffer[0] === 0xff && (buffer[1] === 0xfb || buffer[1] === 0xfa || buffer[1] === 0xf3)) ||
(buffer[0] === 0x49 && buffer[1] === 0x44 && buffer[2] === 0x33)
) {
return "mp3";
}
// MP4/M4A/MOV: ....ftyp
if (buffer[4] === 0x66 && buffer[5] === 0x74 && buffer[6] === 0x79 && buffer[7] === 0x70) {
return "mp4";
}
// OGG: OggS
if (buffer[0] === 0x4f && buffer[1] === 0x67 && buffer[2] === 0x67 && buffer[3] === 0x53) {
return "ogg";
}
// FLAC: fLaC
if (buffer[0] === 0x66 && buffer[1] === 0x4c && buffer[2] === 0x61 && buffer[3] === 0x43) {
return "flac";
}
// AAC: ADTS header (FFF1 or FFF9 usually)
// Sync word 111111111111 (12 bits)
if (buffer[0] === 0xff && (buffer[1] & 0xf0) === 0xf0) {
return "aac";
}

return "unknown";
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

The new detectAudioFormat function lacks test coverage. The existing utils.test.ts file contains tests for sanitizeLog, demonstrating that utility functions in this file are tested. While the PR description mentions a test_audio_detect.ts file with 7/7 tests passing, this test file is not included in the repository. Consider adding tests for detectAudioFormat to utils.test.ts to ensure all supported formats (WAV, MP3, WebM, MP4, OGG, FLAC, AAC) are correctly detected and that unknown formats return "unknown".

Copilot uses AI. Check for mistakes.

// Sentinel: Verify file content matches audio signature (prevent malicious uploads)
const detectedFormat = detectAudioFormat(file.buffer);
if (detectedFormat === "unknown") {
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

Security-critical validation failures like file signature mismatches should be logged with sanitized metadata for security monitoring and incident response. According to established codebase conventions, such failures should be logged with information like userId, fileSize, mimeType, and originalName using the sanitizeLog utility. Consider adding logging here similar to: console.warn("File signature validation failed:", sanitizeLog({ userId: req.user.claims.sub, fileSize: file.size, mimeType: file.mimetype, originalName: file.originalname })).

Suggested change
if (detectedFormat === "unknown") {
if (detectedFormat === "unknown") {
console.warn(
"File signature validation failed:",
sanitizeLog({
userId: req.user?.claims?.sub,
fileSize: file.size,
mimeType: file.mimetype,
originalName: file.originalname,
})
);

Copilot uses AI. Check for mistakes.
Comment on lines 55 to 58
// WAV: RIFF....WAVE
if (buffer[0] === 0x52 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x46) {
return "wav";
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

The WAV format detection only checks for the RIFF header (bytes 0-3) but does not verify the WAVE signature at bytes 8-11. A complete WAV file should have "RIFF" at bytes 0-3 and "WAVE" at bytes 8-11. Other RIFF-based formats (like AVI video files) also start with RIFF but have different format identifiers. Consider adding a check for the WAVE signature to prevent false positives: if (buffer[0] === 0x52 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x46 && buffer[8] === 0x57 && buffer[9] === 0x41 && buffer[10] === 0x56 && buffer[11] === 0x45)

Copilot uses AI. Check for mistakes.
return res.status(400).json({ message: "Reference audio file is required" });
}

// Sentinel: Verify file content matches audio signature (prevent malicious uploads)
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

The comment prefix "Sentinel:" violates the codebase convention. According to established guidelines, branded prefixes like "Tool:", "AI:", or "Sentinel:" should not be used. Use a simple descriptive comment instead.

Copilot generated this review using guidance from repository custom instructions.
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 3 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="server/utils.ts">

<violation number="1" location="server/utils.ts:56">
P2: WAV detection only checks the RIFF container header, so non-audio RIFF files (e.g., AVI/WEBP) would be misclassified as WAV. Verify the "WAVE" identifier at bytes 8–11 to avoid accepting non-audio files.</violation>

<violation number="2" location="server/utils.ts:84">
P1: The AAC signature check is too permissive - it accepts any buffer starting with `0xFF` followed by a byte with high nibble `0xF`. This pattern is broad enough that a crafted malicious payload can be prefixed to satisfy the check, bypassing the intended security hardening. Consider implementing stricter ADTS frame validation (e.g., verify the full sync word and check frame header fields like profile, sample rate).</violation>
</file>

<file name="server/routes.ts">

<violation number="1" location="server/routes.ts:1152">
P2: The new magic-byte check only rejects `unknown`, but it doesn't validate that the detected format matches the client-provided `file.mimetype`. A spoofed MIME can still pass verification and produce a mismatched data URL. Validate that the MIME is consistent with `detectedFormat` (or derive the MIME from `detectedFormat`) before proceeding.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

}
// AAC: ADTS header (FFF1 or FFF9 usually)
// Sync word 111111111111 (12 bits)
if (buffer[0] === 0xff && (buffer[1] & 0xf0) === 0xf0) {
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 17, 2026

Choose a reason for hiding this comment

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

P1: The AAC signature check is too permissive - it accepts any buffer starting with 0xFF followed by a byte with high nibble 0xF. This pattern is broad enough that a crafted malicious payload can be prefixed to satisfy the check, bypassing the intended security hardening. Consider implementing stricter ADTS frame validation (e.g., verify the full sync word and check frame header fields like profile, sample rate).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/utils.ts, line 84:

<comment>The AAC signature check is too permissive - it accepts any buffer starting with `0xFF` followed by a byte with high nibble `0xF`. This pattern is broad enough that a crafted malicious payload can be prefixed to satisfy the check, bypassing the intended security hardening. Consider implementing stricter ADTS frame validation (e.g., verify the full sync word and check frame header fields like profile, sample rate).</comment>

<file context>
@@ -40,3 +42,48 @@ export function sanitizeLog(data: any): any {
+  }
+  // AAC: ADTS header (FFF1 or FFF9 usually)
+  // Sync word 111111111111 (12 bits)
+  if (buffer[0] === 0xff && (buffer[1] & 0xf0) === 0xf0) {
+    return "aac";
+  }
</file context>
Fix with Cubic

Comment on lines +1152 to +1155
const detectedFormat = detectAudioFormat(file.buffer);
if (detectedFormat === "unknown") {
return res.status(400).json({ message: "Invalid audio file format (verification failed)" });
}
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 17, 2026

Choose a reason for hiding this comment

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

P2: The new magic-byte check only rejects unknown, but it doesn't validate that the detected format matches the client-provided file.mimetype. A spoofed MIME can still pass verification and produce a mismatched data URL. Validate that the MIME is consistent with detectedFormat (or derive the MIME from detectedFormat) before proceeding.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/routes.ts, line 1152:

<comment>The new magic-byte check only rejects `unknown`, but it doesn't validate that the detected format matches the client-provided `file.mimetype`. A spoofed MIME can still pass verification and produce a mismatched data URL. Validate that the MIME is consistent with `detectedFormat` (or derive the MIME from `detectedFormat`) before proceeding.</comment>

<file context>
@@ -1147,6 +1148,12 @@ Also suggest a fitting title for the song.`;
       }
 
+      // Sentinel: Verify file content matches audio signature (prevent malicious uploads)
+      const detectedFormat = detectAudioFormat(file.buffer);
+      if (detectedFormat === "unknown") {
+        return res.status(400).json({ message: "Invalid audio file format (verification failed)" });
</file context>
Suggested change
const detectedFormat = detectAudioFormat(file.buffer);
if (detectedFormat === "unknown") {
return res.status(400).json({ message: "Invalid audio file format (verification failed)" });
}
const detectedFormat = detectAudioFormat(file.buffer);
const allowedMimesByFormat: Record<string, string[]> = {
wav: ["audio/wav", "audio/x-wav"],
mp3: ["audio/mpeg", "audio/mp3"],
ogg: ["audio/ogg"],
flac: ["audio/flac"],
mp4: ["audio/mp4"],
aac: ["audio/aac"],
};
if (detectedFormat === "unknown" || !allowedMimesByFormat[detectedFormat]?.includes(file.mimetype)) {
return res.status(400).json({ message: "Invalid audio file format (verification failed)" });
}
Fix with Cubic

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Copy link

@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

🧹 Nitpick comments (1)
server/utils.ts (1)

55-56: Remove the duplicate comment.

// WAV: RIFF....WAVE appears on both Line 55 and Line 56.

🔧 Proposed fix
-  // WAV: RIFF....WAVE
   // WAV: RIFF....WAVE
   if (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/utils.ts` around lines 55 - 56, There is a duplicated inline comment
"// WAV: RIFF....WAVE" in server/utils.ts; remove the redundant occurrence so
only a single "// WAV: RIFF....WAVE" comment remains (leave one copy to preserve
the intent), ensuring no other nearby comments or code are altered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@server/utils.ts`:
- Around line 68-73: The MP3 frame-sync check in server/utils.ts currently
matches only a few literal second-byte values and misses MPEG2.5/other Layer3
variants; replace the literal checks in the condition that returns "mp3" with a
bitmask-based test: when buffer[0] === 0xff, test (buffer[1] & 0xE6) === 0xE2 to
match all MPEG Layer3 combinations (covers 0xE2/0xE3/0xF2/0xF3/0xFA/0xFB),
leaving version and CRC bits unconstrained; keep the existing ID3 check and
ensure this bitmask check remains before the AAC classification.

---

Nitpick comments:
In `@server/utils.ts`:
- Around line 55-56: There is a duplicated inline comment "// WAV: RIFF....WAVE"
in server/utils.ts; remove the redundant occurrence so only a single "// WAV:
RIFF....WAVE" comment remains (leave one copy to preserve the intent), ensuring
no other nearby comments or code are altered.

Comment on lines +68 to +73
if (
(buffer[0] === 0xff && (buffer[1] === 0xfb || buffer[1] === 0xfa || buffer[1] === 0xf3)) ||
(buffer[0] === 0x49 && buffer[1] === 0x44 && buffer[2] === 0x33)
) {
return "mp3";
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

MPEG2.5 Layer3 MP3 files are incorrectly rejected as "unknown", blocking valid uploads.

The frame-sync check only covers three specific second-byte values:

  • 0xFB → MPEG1 Layer3, no CRC
  • 0xFA → MPEG1 Layer3, with CRC
  • 0xF3 → MPEG2 Layer3, no CRC

Two additional families are missing:

  • 0xFF 0xF2 (MPEG2 Layer3 with CRC) — skips the MP3 branch and is silently mislabeled as AAC (still accepted, just wrong label).
  • 0xFF 0xE3 and 0xFF 0xE2 (MPEG2.5 Layer3) — skips both the MP3 branch (0xE? & 0xF0 = 0xE0 ≠ 0xF0) and the AAC branch, and falls through to return "unknown", causing legitimate MPEG2.5-encoded MP3 uploads to be rejected with a 400.

MPEG 2.5 is an unofficial extension of MPEG 2 to support even lower sampling rates, so it appears in the wild on low-bitrate recordings. A frame sync byte sequence means finding a byte with value 255 followed by a byte with its three (or four) most significant bits set, which is why the version bits must be considered separately from the sync bits.

Replace the frame-sync literal list with a bitmask that checks only the sync field (top 3 bits of buffer[1]) and the layer field (bits 2–1 of buffer[1]), leaving the version bits and CRC bit free:

🛡️ Proposed fix — cover all MPEG Layer3 variants via bitmask
   // MP3: ID3 tag or frame sync
   if (
-    (buffer[0] === 0xff && (buffer[1] === 0xfb || buffer[1] === 0xfa || buffer[1] === 0xf3)) ||
-    (buffer[0] === 0x49 && buffer[1] === 0x44 && buffer[2] === 0x33)
+    // ID3v2 tag header
+    (buffer[0] === 0x49 && buffer[1] === 0x44 && buffer[2] === 0x33) ||
+    // MPEG frame sync (11 bits) + Layer III (bits 2-1 = 01), all versions (MPEG1/2/2.5) and CRC variants
+    (buffer[0] === 0xff && (buffer[1] & 0xe6) === 0xe2)
   ) {
     return "mp3";
   }

The mask 0xE6 (0b1110_0110) checks sync[7:5]=111 and layer[2:1]=01; 0xE2 is the expected result. This matches 0xE2, 0xE3, 0xF2, 0xF3, 0xFA, and 0xFB, covering every defined MPEG Layer3 combination. Placing this before the AAC check (as it already is) ensures there is no false AAC classification either.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/utils.ts` around lines 68 - 73, The MP3 frame-sync check in
server/utils.ts currently matches only a few literal second-byte values and
misses MPEG2.5/other Layer3 variants; replace the literal checks in the
condition that returns "mp3" with a bitmask-based test: when buffer[0] === 0xff,
test (buffer[1] & 0xE6) === 0xE2 to match all MPEG Layer3 combinations (covers
0xE2/0xE3/0xF2/0xF3/0xFA/0xFB), leaving version and CRC bits unconstrained; keep
the existing ID3 check and ensure this bitmask check remains before the AAC
classification.

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