dutchcoders/transfer.sh · error

err.Error()

Error message

err.Error()

What it means

virusTotalHandler uploads a just-received file to VirusTotal for scanning. virustotal.NewVirusTotal(key) validates the API key; if it is empty/invalid the constructor errors and the raw error text is returned with HTTP 500. Note the code does not return immediately, so execution may continue into vt.Scan with a nil vt — a latent nil-pointer risk in this source.

Source

Thrown at server/virustotal.go:48

	"github.com/gorilla/mux"

	"github.com/Aetherinox/go-virustotal"
)

func (s *Server) virusTotalHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)

	filename := sanitize(vars["filename"])

	contentLength := r.ContentLength
	contentType := r.Header.Get("Content-Type")

	s.logger.Printf("Submitting to VirusTotal: %s %d %s", filename, contentLength, contentType)

	vt, err := virustotal.NewVirusTotal(s.VirusTotalKey)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	reader := r.Body

	result, err := vt.Scan(filename, reader)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	s.logger.Println(result)
	_, _ = w.Write([]byte(fmt.Sprintf("%v\n", result.Permalink)))
}

View on GitHub (pinned to c37bfd9579)

Solutions

  1. Set the VIRUS_TOTAL_KEY environment variable (or equivalent config) with a valid VirusTotal API key and restart the server
  2. Verify the key is active on the VirusTotal account dashboard
  3. If VirusTotal scanning is not wanted, disable the integration instead of leaving an empty key
  4. As a hardening fix, add `return` after http.Error so the nil vt is never used
  5. Check container/secret configuration so the env var actually reaches the process

Example fix

// before
vt, err := virustotal.NewVirusTotal(s.VirusTotalKey)
if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
}
// after
vt, err := virustotal.NewVirusTotal(s.VirusTotalKey)
if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
}
Defensive patterns

Strategy: validation

Validate before calling

# fail fast at deploy time if the VirusTotal key is missing
[ -n "$VIRUS_TOTAL_KEY" ] || { echo 'VIRUS_TOTAL_KEY not set'; exit 1; }
curl -s -o /dev/null -w '%{http_code}' "https://www.virustotal.com/vtapi/v2/url/report?apikey=$VIRUS_TOTAL_KEY&resource=example.com" | grep -q 200

Type guard

null

Try / catch

try {
  const res = await fetch(uploadUrl, {method:'POST', body:form});
  if (!res.ok) throw new Error('upload rejected: ' + await res.text());
} catch (err) {
  if (/apikey|VirusTotal/i.test(String(err))) { /* fix VIRUS_TOTAL_KEY config */ }
}

Prevention

When it happens

Trigger: POST upload with the VirusTotal integration enabled while VIRUS_TOTAL_KEY is unset, empty, or malformed such that virustotal.NewVirusTotal returns an error.

Common situations: Missing VIRUS_TOTAL_KEY environment variable in the deployment; key rotated/revoked; config file not passed to the server process; Docker/K8s secret not wired into the container environment.

Understand the failure class

Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.

Related errors


AI-assisted analysis of dutchcoders/transfer.sh@c37bfd9579 (2026-09-05). Data as JSON: /api/errors/59304a1c8891542d. Report an issue: GitHub.