Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/routes/dashboard/projects/[id]/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,12 @@ export const actions = {
// Remove Exif metadata and save (we don't want another Hack Club classic PII leak :D)
const imageBuffer = Buffer.from(await imageFile.arrayBuffer());

const imageBody = imageFile.type === 'image/gif' ? imageBuffer : await sharp(imageBuffer).toBuffer();

This comment was marked as outdated.


const imageCommand = new PutObjectCommand({
Bucket: env.S3_BUCKET_NAME,
Key: imagePath,
Body: await sharp(imageBuffer).toBuffer()
Body: imageBody
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

Skipping Sharp processing for GIFs means the server no longer validates that the uploaded bytes are actually an image; it relies solely on imageFile.type (client-controlled), so a forged MIME type could upload arbitrary content to the images/ bucket. It also bypasses the intended metadata-stripping step mentioned in the comment. Consider performing server-side type sniffing/decoding for GIFs as well (e.g., decode + re-encode with Sharp in animated mode, or validate via magic bytes) so invalid/non-image payloads are rejected and metadata is normalized.

Copilot uses AI. Check for mistakes.
});
await S3.send(imageCommand);

Expand Down
4 changes: 2 additions & 2 deletions src/routes/dashboard/projects/[id]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,11 @@
/>
{#if form?.invalid_image_file}
<p class="mt-1 text-sm">
Invalid file, must be a PNG or JPEG file under {MAX_UPLOAD_SIZE / 1024 / 1024} MiB
Invalid file, must be a PNG, JPEG or GIF file under {MAX_UPLOAD_SIZE / 1024 / 1024} MiB
</p>
{:else}
<p class="mt-1 text-sm opacity-50">
Must be a PNG or JPEG file under {MAX_UPLOAD_SIZE / 1024 / 1024} MiB
PNG, JPEG or GIF (up to {MAX_UPLOAD_SIZE / 1024 / 1024} MiB)
</p>
{/if}
</label>
Expand Down
2 changes: 1 addition & 1 deletion src/routes/dashboard/projects/[id]/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const MAX_UPLOAD_SIZE = 30 * 1024 * 1024; // 30 MiB

export const ALLOWED_IMAGE_TYPES = ['image/png', 'image/jpeg'];
export const ALLOWED_IMAGE_TYPES = ['image/png', 'image/jpeg', 'image/gif'];
export const ALLOWED_MODEL_TYPES = [
'model/stl',
'application/sla',
Expand Down
Loading