Skip to main content

Secure Image Uploads in a Shopify Form Builder

Updated 3 min readMarkdown
Secure Image Uploads in a Shopify Form Builder

Image uploads can make a form more useful and visually appealing. Merchants may want a background image, a side image, or images associated with individual options.

However, accepting uploaded files introduces security and resource-management challenges. A reliable upload workflow must validate what it receives, enforce limits, and store assets safely.

Why checking file extensions is not enough

A filename such as background.jpg does not prove that the file contains a valid JPEG image.

A user can rename a file without changing its contents. If an application trusts the extension or the browser-provided MIME type alone, it may accept unexpected file formats.

A stronger approach examines the file's contents to identify its actual type.

Validate the file contents

In Node.js, libraries such as file-type can inspect file signatures and identify supported formats.

A simplified example is:

import { fileTypeFromBuffer } from "file-type";

const detected = await fileTypeFromBuffer(buffer);

const allowedTypes = new Set([
  "image/jpeg",
  "image/png",
  "image/webp",
]);

if (!detected || !allowedTypes.has(detected.mime)) {
  throw new Error("Unsupported image format");
}

This is illustrative code, not the application's exact upload implementation. The buffer must be obtained safely, and the application should enforce size limits before reading an unbounded upload into memory.

Signature detection is also not a complete guarantee that an image is harmless. Depending on the threat model, applications may need image decoding, re-encoding, or additional validation.

Enforce size limits on the server

Client-side file-size checks improve usability, but they should not be the only restriction.

The server should enforce maximum upload size before accepting and processing the entire file. It should also reject unsupported formats and malformed requests.

These checks help control memory consumption and reduce the risk of unexpected content reaching storage.

Store images separately from form configuration

Image files and form settings have different storage requirements.

A form's configuration might contain text, field definitions, and references to images. The actual image bytes are better handled by an object-storage service.

Cruxtab Contact Form Builder stores uploaded design images in Amazon S3 under a shop-specific path:

form-builder/{shop}/…

This separates asset storage from the application's ordinary form configuration.

Treat upload endpoints as security boundaries

A secure upload workflow should authenticate the merchant, derive the shop identity from trusted session context, validate the requested asset type, and enforce applicable storage limits.

The application should not trust a client-supplied shop identifier as proof of authorization.

Conclusion

Secure image uploads require more than accepting a file and sending it to storage.

Content-based type detection, server-side size checks, authorization, and controlled storage all contribute to a safer implementation.

Cruxtab Contact Form Builder supports images for form backgrounds, side images, and option images, using S3 for storage and content-based file-type checks.

The broader lesson is to validate files based on what they contain, enforce limits before expensive processing, and treat every upload as untrusted input.

No comments yet. Be the first to comment.

More from this blog