From soundcheck
Audits file upload handlers for vulnerabilities like unrestricted uploads, path traversal, executable files, and size issues. Suggests fixes with extension allowlists, renaming, secure storage outside webroot, and MIME validation.
npx claudepluginhub thejefflarson/soundcheck --plugin soundcheckThis skill uses the workspace's default tool permissions.
Protects against unrestricted file upload attacks where an attacker uploads executable
Handles secure file uploads to S3 and Cloudflare R2 using presigned URLs, multipart uploads, and image optimization. Addresses pitfalls like file type validation, size limits, and path traversal.
Implements secure file upload handling with validation, virus scanning, storage management, and serving across Flask, Express, FastAPI. Use for file upload features, document management, and media storage.
Implements file upload endpoints in ASP.NET Core Minimal APIs (.NET 8+): IFormFile binding, size limits, multipart handling, validation, and common pitfalls.
Share bugs, ideas, or general feedback.
Protects against unrestricted file upload attacks where an attacker uploads executable files (web shells, scripts, HTML with embedded JS) that the server later serves or executes. Exploitation leads to remote code execution, stored XSS, or full server compromise.
file.save(os.path.join('uploads/', file.filename)) — user-controlled filename stored directly, enabling path traversal and extension bypassPath(uploadDir).resolve().toString() + originalFilename — original filename preserved, no extension allowlistio.Copy(dst, file) with destination in webroot — uploaded content served directly by the web serverContent-Length or stream-size check — attacker uploads multi-GB file to exhaust diskFlag the vulnerable code and explain the risk. Then suggest a fix that establishes these properties:
.phtml, .phar, .svg) and case variations. An
allowlist of expected types (.png, .jpg, .pdf) fails closed.../../etc/passwd), overwrites of existing files, and
filename-based XSS on download.Content-Type and Content-Disposition: attachment, never inferred from the
filename.Content-Type header the client sent — the header is attacker-controlled.Anchor — shape, not implementation:
require(ext(upload.filename) in ALLOWED_EXT)
require(magic_bytes_match(upload.stream, ALLOWED_MIMES))
name = csprng_hex() + ext(upload.filename)
save(upload.stream, UPLOAD_DIR_OUTSIDE_WEBROOT / name) # size cap set in framework
Confirm the following properties hold (language-agnostic):
Content-Disposition: attachment and a safe, explicit Content-Type — never inferred from the filename