☰ Categories

Review code with bugs separated from taste

Sorts findings by severity, demands reproduction conditions, and refuses to invent problems.

CategoryDevelopment › Coding
TagsReviewingAnalyzingDeveloperCode
Prompt
Review this code.

Sort your findings:
1. **Bugs** — wrong behavior on specific input or state. **Give the reproduction conditions.**
2. **Robustness** — missing exception handling, unreleased resources, boundary conditions
3. **Security** — input validation, authorization, anything that must not be exposed
4. **Performance** — ***only at a scale where it actually matters.*** Do not write "theoretically slow".
5. **Readability and structure** — last

Rules:
- ***Do not mix matters of taste (formatting, naming preference) with bugs.*** Group them separately and label them "taste".
- **Every finding says the situation in which it breaks.** A vague finding is worthless.
- **Do not flag behavior in code I did not show you.** Ask instead.
- **If there is nothing wrong, say so.** Do not manufacture findings.
- End with the order to fix them in.
After pasting, fill in the fields at the bottom (Language and framework · What this code does · Code)

What this prompt does

Reviews that mix formatting opinions with real bugs get skimmed. This separates them and requires a concrete failure case for each.

Model comparison

Claude is strongest in accuracy and specificity, while ChatGPT is concise but less precise about some conditions. Gemini is detailed, but includes unsupported deployment assumptions and questionable FastAPI behavior claims.

ClaudeTop overall
47/ 50

+ Most concrete on reproduction, impact, and fix priority.

- The full patch makes the review somewhat overlong.

ChatGPT
43/ 50

+ Classifies the core risks concisely and evenly.

- Some findings lack precise reproduction and size-limit analysis.

Gemini
40/ 50

+ Clearly connects each issue to conditions and outcomes.

- Claims about missing filenames, leaks, and executables are shaky.

CriterionChatGPTClaudeGeminiLeader
Instruction following9108Claude +11%
Accuracy896Claude +13%
Specificity8109Claude +11%
Structure9109Claude +11%
Right length988ChatGPT +13%

Scored 1–10 by gpt-5.6-sol with model names hidden (2026-09-24). This is an AI review, not a measurement.

Read full answers

We gave three models the same input and copied their answers unedited. Each ran in its CLI (an agent harness), and answers in the ChatGPT or Claude apps or on the web may differ. Outputs are in Korean.

Input used
Language and framework: Python 3.12 / FastAPI

What this code does: 사용자가 올린 파일을 저장하고 경로를 반환

Code: @app.post("/upload")
async def upload(f: UploadFile):
    path = f"/var/data/{f.filename}"
    with open(path, "wb") as out:
        out.write(await f.read())
    return {"path": path}
gpt-5.6-luna (codex CLI · 에이전트 하네스) · Run on 2026-09-24

1. Bugs

파일명에 ..이 포함되면 저장 경로를 탈출함 — 보안과도 관련

f.filename에 ../../etc/passwd 같은 값이 들어오면:

path = "/var/data/../../etc/passwd"

운영체제가 경로를 정규화하면서 /etc/passwd에 접근하게 됩니다. 쓰기 권한이 있다면 임의 파일을 덮어쓸 수 있습니다.

또한 a/b.txt처럼 하위 경로가 포함되면 /var/data/a 디렉터리가 없을 때 FileNotFoundError로 500 응답이 발생합니다.

동일한 파일명이면 기존 파일을 덮어씀

사용자가 report.txt를 업로드한 뒤 다른 사용자가 같은 이름으로 업로드하면 기존 파일이 그대로 덮어써집니다. 악의적인 업로드나 정상적인 동시 업로드 모두 데이터 손실을 일으킬 수 있습니다.

빈 파일명 또는 유효하지 않은 파일명이면 500 오류

filename이 빈 문자열이면 경로가 /var/data/가 되어 디렉터리를 파일처럼 열게 되므로 실패합니다. 파일명에 OS에서 허용되지 않는 문자나 존재하지 않는 하위 디렉터리가 포함된 경우에도 예외가 발생합니다.

2. Robustness

저장 실패 시 예외 처리가 없음

디렉터리가 없거나, 디스크가 가득 찼거나, 권한이 없거나, 쓰기 중 I/O 오류가 발생하면 예외가 그대로 FastAPI까지 전파되어 500 응답이 됩니다. 이미 일부 데이터가 기록된 파일이 남을 수도 있습니다.

임시 파일에 먼저 저장한 뒤 os.replace()로 원자적으로 이동하고, 실패 시 임시 파일을 정리하는 방식이 안전합니다.

업로드 전체를 메모리에 읽음

await f.read()

는 파일 전체를 메모리에 올립니다. 큰 파일 하나 또는 여러 개의 동시 업로드가 발생하면 메모리 부족으로 프로세스가 종료될 수 있습니다.

async 함수 안에서 동기 파일 I/O를 수행함

open()과 out.write()는 동기식입니다. 디스크가 느리거나 큰 파일을 저장하는 동안 이벤트 루프가 막혀 다른 요청 처리도 지연됩니다.

3. Security

사용자 제어 파일명으로 경로를 직접 생성함

위의 경로 탈출뿐 아니라, 공격자가 기존 파일명을 알고 있으면 애플리케이션이 쓰기 권한을 가진 위치의 파일을 덮어쓸 가능성이 있습니다.

파일명 대신 서버에서 생성한 UUID를 저장 이름으로 사용하고, 원본 파일명은 별도 메타데이터로 보관해야 합니다. 저장 디렉터리도 애플리케이션 전용 디렉터리로 제한하고 심볼릭 링크 공격까지 고려해야 합니다.

내부 절대 경로를 외부에 반환함

응답으로 /var/data/...를 직접 반환하면 서버의 디렉터리 구조가 노출됩니다. 클라이언트가 실제 파일 경로를 알아야 하는 요구가 없다면 파일 ID나 다운로드용 API 경로를 반환하는 편이 안전합니다.

인증·인가 여부는 제시된 코드만으로 판단할 수 없습니다. 업로드 API가 인증 없이 공개되어 있는지는 라우터 설정과 배포 구성을 추가로 확인해야 합니다.

4. Performance

큰 파일 또는 동시 업로드가 많은 경우 확장성이 낮음

대규모 파일 업로드가 동시에 발생하면 전체 파일을 메모리에 적재하고 이벤트 루프에서 동기 쓰기까지 수행하므로 메모리와 요청 처리량이 빠르게 악화됩니다. 작은 파일이 소수만 업로드되는 환경에서는 큰 문제가 아닐 수 있습니다.

5. Readability and structure

취향 수준의 포맷팅·명명 문제는 별도로 지적할 내용이 없습니다. 현재 코드는 짧지만, 경로 검증·파일명 생성·스트리밍 저장을 별도 함수로 분리하면 책임이 명확해집니다.

수정 순서

  1. 사용자 파일명으로 경로를 직접 만들지 말고 UUID 등 서버 생성 이름 사용
  2. 저장 경로 탈출과 심볼릭 링크 공격 방지
  3. 파일 크기·확장자·콘텐츠 타입 제한 추가
  4. 청크 단위 저장 및 비동기 친화적 파일 처리 적용
  5. 임시 파일과 원자적 rename으로 부분 파일 방지
  6. 저장 오류·디스크 부족·잘못된 파일명에 대한 예외 처리
  7. 내부 절대 경로 대신 파일 ID 또는 다운로드 URL 반환

More in this category

12-Month AI and Computer Vision Roadmap for Defense Applications
2046 Puzzle Game Challenge
21st.dev component prompt
3D FACTORY
3D FPS Game