agentsclimarketplace

File upload security

Skill ShieldNet-360/secure-vibe/skills/file-upload-security

Validate user uploads: MIME magic bytes, filename sanitization, size limits, separate serving domain, AV scanning, polyglot detectionFrom its SKILL.md

Install
npx -y skills add ShieldNet-360/secure-vibe --skill file-upload-security

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 15 stars15 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

7.7 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it

File Upload Security

Rules (for AI agents)

ALWAYS

  • Verify magic bytes of every upload server-side. Content-Type and file extension are attacker-controlled and never sufficient. Use libmagic, file-type (Node), mimetypes-magic (Python), or Tika.
  • Maintain an allowlist of accepted types per endpoint (image/png, image/jpeg, application/pdf, …). Deny everything else, including text/html, image/svg+xml (carries <script>), text/xml, and application/octet-stream.
  • Sanitize filenames: strip directory components, normalize Unicode, reject .., NUL byte, control chars, reserved Windows names (CON, PRN, AUX, NUL, COM1-9, LPT1-9), and any non [a-zA-Z0-9._-] characters. Store as a UUID / hash and keep the original filename in a separate, escaped metadata column.
  • Enforce a size limit at the proxy / API gateway and at the application — at least double-layer. The proxy limit prevents bandwidth DoS; the app limit prevents memory exhaustion when a proxy is misconfigured.
  • Store uploads outside the document root and serve them from a separate domain (usercontent.example.net) on a CDN. Set Content-Disposition: attachment for non-image types and a Content-Security-Policy: default-src 'none'; sandbox header to neutralize any inline-rendered HTML/SVG.
  • Run a virus scanner (ClamAV, VirusTotal, Sophos) on every upload before making it accessible to other users — out of band so the request itself isn't latency-bound.
  • Re-encode media server-side: convert in.jpg out.jpg (ImageMagick with a strict policy.xml), ffmpeg -i for video, pdftocairo for PDFs. Re-encoding strips most polyglot / steganographic payloads and exotic codec exploits.
  • For SVG specifically: either render server-side to a raster format, or pass through a strict allowlist sanitizer (DOMPurify in Node, lxml.html.clean in Python) that strips <script>, <iframe>, <foreignObject>, xlink:href with javascript:, and CSS expression / url() with non-data URIs.

NEVER

  • Trust Content-Type from the client. The mime sniffer in IE / older Chrome reads the body for type clues — an HTML payload disguised as image/png will run as HTML when served same-origin.
  • Construct the storage path with the user-supplied filename. Path traversal (../../etc/passwd) and the Windows reserved-name class both reduce to "let attacker pick where to write."
  • Serve uploads from the same origin as the application. Serving on api.example.com/uploads/x.html means a malicious HTML upload runs with full access to api.example.com cookies and CORS.
  • Use a stack that processes uploads with ImageMagick / libraw / ExifTool / ffmpeg without strict policy.xml / sandbox / version control. ImageTragick (CVE-2016-3714) and GitLab ExifTool (CVE-2021-22205) both relied on a server happily handing user-controlled bytes to a media library.
  • Allow PDF upload + render in-browser without verifying the PDF passes structural validation (e.g. pdfinfo). Malicious PDFs are a common JavaScript-in-PDF / XFA RCE primitive against Adobe Reader on the recipient side, even when the server is safe.
  • Use .docx / .xlsx / .zip extraction with unzip or python -m zipfile without a path-traversal-safe extractor. Zip slip (CVE-2018-1002201) extracted files outside the target directory through ../ entries.
  • Use S3 / GCS presigned upload URLs without a strict Content-Type signed condition and a fixed object-key prefix. Without the conditions, the client can upload anything to any key.

KNOWN FALSE POSITIVES

  • Internal-only admin uploads (e.g. an ops dashboard) may legitimately trust file extension because the trust boundary is the SSO + IP allowlist. Document this as a deliberate decision in the endpoint.
  • Some integrations (e.g. exporting CSV from BI tools) need to round-trip user-supplied filenames; preserve them in metadata, but the on-disk name must still be a UUID.
  • Tarballs / DEBs / RPMs in a build pipeline don't need AV scan — the trust boundary is the build pipeline's signing key, not the AV.

Context (for humans)

File upload is the persistent rich-target attack surface. Every real-world breach lab includes a "find an upload form" early-game move because the path from upload to RCE is usually short: upload an HTML file with a JavaScript credential stealer, upload a PHP / JSP shell to a misconfigured doc-root, upload an SVG with a SAML-stealer <script>, upload an EXIF-payloaded image to a vulnerable ImageMagick service.

The defenses are well-understood and inexpensive — the bug is that they have to be applied in combination. A magic-byte allowlist is trivially bypassed by a polyglot (a file that is simultaneously a valid PNG and a valid HTML page). A separate serving domain neutralizes the polyglot's HTML execution. A virus scanner catches known malware. Re-encoding strips weird codec payloads. Each defense is a layer; missing one layer turns most uploads from "stored data" into "stored RCE."

Verify & lock (triaging a finding)

A scanner/review hit is a candidate, not a confirmed bug. Confirm it, fix it, then lock it so it can't come back.

  1. Confirm it's real (probe the suspect endpoint). POST a payload the allowlist should reject and watch where it lands: a shell.php/shell.jsp with a real magic-byte mismatch, an image/png content-type wrapping HTML/SVG-with-<script>, or a filename like ../../shell.php. Real if the upload is accepted and the stored object is reachable from an executable/same-origin path, the traversal escapes the upload dir, or the SVG/HTML renders script when fetched. False positive if magic bytes are verified server-side, the name is replaced with a UUID, and the file serves from a separate sandboxed domain as attachment — the probe is rejected or served inert.
  2. Fix, then lock with a regression test (unit or integration — dev's call): feed the validator the disallowed cases and assert each is rejected — .php/.jsp/.svg/.html extensions, spoofed Content-Type whose magic bytes don't match, oversize body past the limit, and a ../../ / NUL / reserved-name filename (assert the on-disk key is a sanitized UUID, never the input). Then assert a benign image/png with valid magic bytes still uploads and serves. Commit it to CI so the guard can't be silently dropped in a later refactor.

References

What ships with it: 2 files

9.3 KB alongside SKILL.md

tests/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.