diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c706c48..0538a34 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: actions/setup-node@v4 with: diff --git a/src/lib/stores/reportStore.js b/src/lib/stores/reportStore.js index ee8623f..9b06c2f 100644 --- a/src/lib/stores/reportStore.js +++ b/src/lib/stores/reportStore.js @@ -36,9 +36,23 @@ export const useReportStore = create((set) => ({ // Upload photo if present if (reportData.photo) { const file = reportData.photo - const fileExt = file.name.split('.').pop() + const fileExt = file.name.split('.').pop().toLowerCase() + + // Sanitize: only allow safe image extensions, block path traversal + const allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'] + if (!allowedExtensions.includes(fileExt)) { + set({ isSubmitting: false }) + return { success: false, error: 'Invalid file type. Only JPG, PNG, GIF, and WebP are allowed.' } + } + const fileName = `${Date.now()}.${fileExt}` + // Guard against path traversal (e.g. "../" in file name) + if (fileName.includes('..') || fileName.includes('/') || fileName.includes('\\')) { + set({ isSubmitting: false }) + return { success: false, error: 'Invalid file name.' } + } + const { data: uploadData, error: uploadError } = await supabase.storage .from('report-photos') .upload(fileName, file) diff --git a/vercel.json b/vercel.json index 07832dd..cbb66c7 100644 --- a/vercel.json +++ b/vercel.json @@ -12,7 +12,7 @@ "headers": [ { "key": "Content-Security-Policy", - "value": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://*.tile.openstreetmap.org https://*.supabase.co; font-src 'self'; connect-src 'self' https://*.supabase.co wss://*.supabase.co; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action 'self'" + "value": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://*.tile.openstreetmap.org https://*.supabase.co; font-src 'self'; connect-src 'self' https://*.supabase.co wss://*.supabase.co; frame-src 'none'; frame-ancestors 'none'; object-src 'none'; base-uri 'self'; form-action 'self'" }, { "key": "X-Content-Type-Options",