Skip to content

[BUG] Issue/epic attachments cannot be downloaded (ServeFile rejects attachments/ paths) #135

Description

@martian56

Summary

Issue/epic attachments can never be downloaded. The file-serving endpoint only accepts object paths under uploads/, but the attachment flow stores objects under attachments/<issueId>/<assetId> and returns download URLs of the form /api/files/attachments/.... Every attachment download is therefore rejected with HTTP 400 before any lookup happens.

Severity

High — a core feature (issue attachments) is completely broken. Uploads appear to succeed, but the file can never be retrieved.

Affected code

  • api/internal/handler/upload.go:101ServeFile rejects any path not prefixed with uploads/:
    if path == "" || strings.Contains(path, "..") || !strings.HasPrefix(path, "uploads/") {
        c.Status(http.StatusBadRequest); return
    }
  • api/internal/service/attachment.go:101,136,145 — attachments are stored as attachments/<issueId>/<assetId> and the API hands the UI "/api/files/" + objectName (i.e. /api/files/attachments/...).
  • Route: GET /api/files/*path -> ServeFile (api/internal/router/router.go).

Live reproduction (verified)

Authenticated fetch against a running instance:

Path Result
GET /api/files/attachments/<uuid>/<uuid> 400 Bad Request
GET /api/files/uploads/nonexistent-key 404 Not Found

The 400-vs-404 contrast isolates the failure to the uploads/-only prefix gate (it rejects attachments/ before checking whether the object exists), so it fails for every attachment regardless of existence.

Suggested fix

Allow the attachments/ prefix in ServeFile (accept both uploads/ and attachments/) while keeping the .. traversal guard. NOTE: address the related hardening item (set X-Content-Type-Options: nosniff + Content-Disposition, constrain attachment content-type) at the same time, otherwise enabling attachments/ serving activates a latent stored-XSS vector.

Metadata

Metadata

Assignees

Labels

APIbugSomething isn't working

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions