We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

File Upload Security

File uploads accept large amounts of user-controlled data in formats that may later be parsed, served, or executed. A safe upload boundary cannot trust the filename or content type supplied by the client.

Trusting Upload Metadata

This handler writes an upload under its original name without inspecting the contents:

file, header, err := request.FormFile("file")
if err != nil {
    return err
}
defer file.Close()

contents, err := io.ReadAll(file)
if err != nil {
    return err
}
return os.WriteFile(filepath.Join("public/uploads", header.Filename), contents, 0o644)

The attacker still chooses the filename and extension, and a multipart Content-Type header is only another client claim. A name collision can overwrite an earlier upload, and renaming a script to image.png does not turn its bytes into an image.

Detect Before Storing

A safer handler inspects the bytes, generates its own storage name, and writes outside public asset directories:

contentType, extension, valid := detectDocumentType(contents)
if !valid {
    return errors.New("unsupported file type")
}
identifier, err := identifiers.NewUUID()
if err != nil {
    return err
}
storagePath := filepath.Join("data/uploads", identifier+extension)

Useful upload boundaries include:

  • Size limits: bound memory, disk, and parsing work
  • File-signature inspection: identify supported formats from their bytes
  • Server-generated names: prevent collisions and detach storage paths from attacker-controlled names
  • Private storage: keep uploads outside directly served application assets

See OWASP's File Upload Cheat Sheet for a broader defense-in-depth checklist.

Assignment

Bearly Secure already receives tax-document bytes in memory and persists their metadata, but StoreDocument accepts any bytes and gives every file a generic name. Archive imports also trust file extensions. Detect each file's type before persistence and generate a safe storage name.

With Bearly Secure still running, run and submit the CLI tests from the project root.