Back to Home

Secure file upload in Go: 7 attacks

The article describes protection of file upload in Go from 7 attacks: type spoofing magic bytes, DoS via MaxBytesReader+slots, path traversal with fixed paths. Used ECDSA-identification of devices without accounts for browser extension.

7 attacks on file upload in Go and their protection
Advertisement 728x90

Securing File Uploads in Go: Defending Against 7 Common Attacks

In systems without traditional authentication, file uploads require robust request source identification. For a browser extension that converts PDF to Markdown, an ECDSA P-256-based model using the WebCrypto API is implemented. On first launch, a non-exportable key pair is generated:

const keyPair = await crypto.subtle.generateKey(
  { name: 'ECDSA', namedCurve: 'P-256' },
  false,  // extractable = false
  ['sign', 'verify']
);

The public key is registered on the server, returning a device_id and device_token. Every API request includes:

  • Authorization: Bearer <token>
  • X-Timestamp (±5 minutes)
  • X-Nonce (anti-replay)
  • X-Body-SHA256
  • X-Signature (ECDSA signature over METHOD+PATH+TIMESTAMP+NONCE+BODY_HASH)

The server verifies the signature using the public key, ensuring:

Google AdInline article slot
  • Rate limiting per device
  • Protection against replay attacks
  • Slot control (max 3 active tasks)
  • Registration limits (5/IP/hour)

This model increases attack cost—emulation requires full ECDSA signature implementation.

Attack 1: File Type Spoofing

An attacker disguises an executable as a PDF. Defense is layered across three levels.

Frontend: MIME type and extension validation:

Google AdInline article slot
const ALLOWED_TYPES = ['application/pdf'];
const ALLOWED_EXTENSIONS = ['.pdf'];

function validateFile(file) {
  const isPdf = ALLOWED_TYPES.includes(file.type) ||
                ALLOWED_EXTENSIONS.some(ext =>
                  file.name.toLowerCase().endsWith(ext));
  if (!isPdf) return { valid: false, error: 'PDF only' };
}

Backend: Route based on Content-Type. Critical: Magic bytes:

pdfMagicBytes := "%PDF"
header4 := make([]byte, 4)
_, err := file.Read(header4)
if string(header4) != pdfMagicBytes {
    respondError(w, http.StatusBadRequest,
        models.ErrCodeValidationError,
        "File is not a valid PDF")
}
file.Seek(0, 0)

Checking the first bytes bypasses headers and extensions. Polyglot files (valid PDFs with malicious content) require additional signatures.

Attack 2: Disk Exhaustion (DoS)

Denial-of-service via large files. Mitigation includes:

Google AdInline article slot
  • http.MaxBytesReader(w, r.Body, MaxFileSize + 1MB) — halts reading at limit.
  • Per-device slots: max 3 active tasks (queued, processing, ready, error).
  • Rate limits on registration and requests.

Device identification renders IP or token rotation ineffective.

Attack 3: Path Traversal

An attacker uses ../../../etc/passwd. Solution: Fixed path {UUID}/input.pdf. User input in paths is completely ignored.

Frontend sanitization (additional layer):

function sanitizeFileName(name) {
  return name
    .replace(/[/\\?%*:|"<>]/g, '-') 
    .replace(/^\.+/, '')
    .replace(/\.$/, '')
    .substring(0, 255)
    .trim();
}

Backend generates the path independently of the filename.

Attack 4: SSRF via URL Upload

For the "upload from URL" feature, the following are blocked:

  • DNS resolution before download
  • Redirects
  • Private IPs (denylisted: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)

Attack 5: Replay Attacks

X-Nonce + X-Timestamp + signature. Nonce is stored per device; timestamp is validated within ±5 minutes.

Attack 6: Device Impersonation

extractable: false ensures the private key cannot be exported. Stealing device_token is useless without valid signatures.

Attack 7: Application-Level Abuse

Rate limits + slot controls + cryptographic signing. Max 3 slots, 5 registrations/IP/hour.

Key Takeaways

  • Cryptographic device-level identification replaces accounts for rate limiting.
  • Magic bytes (%PDF) are the only reliable way to verify file type.
  • MaxBytesReader + slot management prevent DoS.
  • Fixed paths eliminate traversal risks.
  • ECDSA P-256 with nonce/timestamp blocks replay and impersonation.

— Editorial Team

Advertisement 728x90

Read Next