Safeguard
Security Guides•

Are file uploads over GraphQL safe? Risks and a safer alternative

GraphQL file uploads bring memory, stream, CSRF and metadata risks. See the safeguards, and why a signed URL flow keeps binary data off your API.

Safeguard Security Team
4 min read

They can be, with care, but GraphQL was not designed for binary data and uploads need extra defences. The GraphQL project recommends avoiding uploads through GraphQL altogether. Instead, request a signed upload URL through a mutation, upload directly to storage, then link the file with a second mutation.

Why uploads are tricky in GraphQL

The GraphQL project's file upload guide explains that GraphQL requests are typically JSON, which cannot carry binary data directly. Base64 inside JSON is inefficient and does not suit larger files or streamed processing. A common choice is multipart form data, using a community convention called the GraphQL multipart request specification. The guide warns that people implementing it must pay close attention to avoid security or reliability problems.

Risks the guide lists

RiskWhat happensDefence
Repeated variablesAn upload variable used several times drains or re reads the stream, risking memory exhaustionAllow each upload variable once
Stream leaks on failed operationsValidation or authorization fails and streams are never consumed, leaking memoryEnd all streams when the request finishes
CSRFMultipart form data counts as a simple request in CORS and sends no preflight, so another origin may post uploadsAdd explicit CSRF protection
Oversized or extra payloadsHuge files or extra files under unused names overload the serverSet request size caps, reject unreferenced files
Untrusted metadataFile names, types and contents may be hostileSanitize names, sniff types, validate contents

The guide also mentions format specific exploits such as zip bombs and maliciously crafted PDFs. Declared MIME types should not be trusted, so detect the type from the content and reject mismatches.

The signed URL alternative

The guide calls the signed URL approach the most secure and scalable option. The flow has three steps:

  1. The client calls a mutation that asks for a signed upload URL from your storage provider.
  2. The client uploads the file straight to storage using that URL.
  3. A second mutation, or an automatic trigger, associates the uploaded file with your data.

Because steps one and two alone could be abused to fill storage, the guide says to retain such uploads for a short period so an attacker who completes just those steps cannot exhaust your space. In step three the file moves to permanent storage as appropriate.

This keeps binary handling off your GraphQL server and lets existing storage controls such as size limits and expiry do their work.

If you still need uploads through GraphQL

The guide lists a minimum set of practices:

  • Use a well maintained implementation of the multipart request spec.
  • Enforce a rule that upload variables are referenced once.
  • Stream uploads to disk or cloud storage and do not buffer in memory.
  • Always terminate streams at the end of the request.
  • Apply strict request size limits and validate every field.
  • Treat file names, types and contents as untrusted.

Add the general limits too. OWASP's API Security Top 10 uses a GraphQL upload mutation as an example of unrestricted resource consumption: an attacker batches hundreds of upload operations into one request to bypass a per request rate limit and exhaust memory. Limits on maximum upload size and operations per request apply here, as do batching limits.

Review checklist

  1. Do you really need uploads in GraphQL, or can storage take them directly?
  2. Is the multipart library maintained and up to date?
  3. Is the request size cap enforced before buffering?
  4. Does one request carry limited operations?
  5. Is CSRF protection active for form encoded posts?
  6. Are file names sanitized and types detected from content?
  7. Is temporary storage cleaned up after failed requests?

Try it yourself

Click through it at your own pace, or open it full screen.

Look at how a dynamic scan probes inputs on a live app, and consider adding oversized and malformed uploads to your own tests.

Quick check

Can I send a file as base64 inside a GraphQL JSON request?

You can, but the GraphQL guide calls it inefficient and unsuited to larger files because streaming becomes hard. Signed URLs avoid the problem.

Why is CSRF a concern for multipart uploads?

Multipart form data is a simple request under CORS, so browsers send it without a preflight check. Add explicit CSRF protection.

Safeguard scans your dependencies and SBOMs for known vulnerabilities, including multipart and GraphQL libraries. A free scan is at gold.safeguard.sh/scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.