argoproj/argo-workflows · error
Invalid filename
Error message
Invalid filename
What it means
The uploaded filename is sanitized with path.Base (after normalizing Windows backslashes) to prevent path traversal. If the resulting base name is ".", "/", or empty, the server refuses the upload with HTTP 400 "Invalid filename". This blocks filenames like "..", "./", or a filename consisting only of separators.
Source
Thrown at server/artifacts/artifact_server.go:235
"artifactName": artifactName,
}).Info(ctx, "Resolved artifact location from default repository")
}
}
// Check if the artifact has a location configured (S3, GCS, etc.)
if !artifactCopy.HasLocation() {
http.Error(w, fmt.Sprintf("Artifact '%s' does not have a storage location configured (s3, gcs, azure, oss). Please configure a storage location in the WorkflowTemplate or set up a default artifact repository.", artifactName), http.StatusBadRequest)
return
}
// Generate unique key for the artifact
uploadUUID := uuid.NewString()
originalKey, _ := artifactCopy.GetKey()
// Sanitize filename to prevent path traversal attacks. path.Base only
// recognises '/' as a separator, so normalise Windows-style '\' first.
sanitizedFilename := path.Base(strings.ReplaceAll(header.Filename, "\\", "/"))
if sanitizedFilename == "." || sanitizedFilename == "/" || sanitizedFilename == "" {
http.Error(w, "Invalid filename", http.StatusBadRequest)
return
}
// Replace the key with uploaded file path under uploads/
newKey := fmt.Sprintf("uploads/%s/%s/%s", namespace, uploadUUID, sanitizedFilename)
if validateErr := sutils.ValidateUploadedArtifactKey(namespace, newKey); validateErr != nil {
a.serverInternalError(ctx, fmt.Errorf("generated artifact key failed self-validation: %w", validateErr), w)
return
}
// Create a copy of the artifact for uploading (using artifactCopy which has resolved location)
outputArtifact := artifactCopy.DeepCopy()
if setErr := outputArtifact.SetKey(newKey); setErr != nil {
http.Error(w, fmt.Sprintf("Failed to set artifact key: %v", setErr), http.StatusInternalServerError)
return
}
a.logger.WithFields(logging.Fields{
"originalKey": originalKey,View on GitHub (pinned to 35bff19146)
Solutions
- Send a real, non-empty base filename in the multipart part (e.g. file=@data.bin, not a directory path).
- Strip trailing slashes and pass only the base name explicitly if your client builds the multipart part manually.
- If uploading a directory, iterate files and upload each with its own basename.
Example fix
// before (client sends a directory-like name)
writer.CreateFormFile("file", "mydir/")
// after
writer.CreateFormFile("file", "myfile.txt") Defensive patterns
Strategy: validation
Validate before calling
const base = filename.replaceAll('\\', '/').split('/').pop() || '';
if (!base || base === '.' || base === '..') {
throw new Error(`invalid upload filename: ${JSON.stringify(filename)}`);
}
form.append('file', file, base); Type guard
function isValidUploadFilename(name) {
const base = String(name).replaceAll('\\', '/').split('/').pop();
return typeof base === 'string' && base.length > 0 && base !== '.' && base !== '..';
} Try / catch
if (!isValidUploadFilename(file.name)) {
return reject(new Error('client-side: filename normalizes to empty path, refusing upload'));
} Prevention
- Never upload directory entries or names ending in '/' or '\\'.
- Normalize to the basename client-side before building the multipart part.
- Treat traversal-shaped filenames ('../..') as input-validation failures, not something to send.
- For directory uploads, iterate real files and send each with its own basename.
When it happens
Trigger: Uploading a file part whose filename is ".." or "."; a client that sends a filename ending in a separator (e.g. "dir/"); a filename that reduces to empty after backslash-to-slash normalization and base extraction; maliciously crafted multipart parts attempting path traversal (../../etc/passwd).
Common situations: Directory uploads where directory entries are sent with trailing slashes; scripted uploads using an empty or placeholder filename; security scanners probing the endpoint with traversal payloads.
Related errors
- artifact key %q must not contain '..'
- illegal file path: %s
- illegal symlink target: %s -> %s
- illegal file path after symlink resolution: %s resolves outs
- %s: Illegal file path
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/d9b7e57d452396f3.
Report an issue: GitHub.