Protect customer files from upload to download
Secure customer documents in an AI-built product. Review upload validation, workspace permissions, private downloads and safe processing with Supabase.

An upload is the beginning of a file’s life in your product. The same document may be stored, parsed, sent to a model and downloaded later. Protect the customer at every step, including the steps that happen after the upload succeeds.
Map where one uploaded file goes
A customer uploads a private report and sees a success message. Behind that button, the application may create an object, write a database record, start a worker, extract text and send it to a model. Later it might produce a preview and a downloadable answer. Each copy needs an owner and a purpose.
Trace one document through that path. Record the workspace it belongs to, where each representation lives and which service can read it. Include temporary files, extracted text, previews and generated results. Protecting the original while leaving its text in a broadly accessible location does not protect the customer.
Decide what happens when a stage fails or the customer deletes the file. Keep those decisions in the workflow, rather than relying on someone to notice orphaned objects or pending jobs later. More uploads multiply unfinished states as well as storage.
Accept the inputs the product actually supports
If the product reads a particular document format, define that format and a usable maximum size. A file-picker restriction helps customers choose correctly, but the server must enforce the actual rule. Another client can send a different request without using your interface.
OWASP recommends layered validation. The supplied content-type header is untrusted, a filename extension is not proof of contents and a matching file signature is not a complete safety check. Check the bytes with appropriate maintained tooling and reject unsupported inputs before expensive processing.
Generate the stored object name rather than treating a customer’s filename as a storage path. Preserve a safe display name separately when needed. Tell the customer why an upload cannot be used and what they can change; silently accepting a file the parser cannot handle only delays the failure.
Contain the work hidden inside a file
A small compressed file can expand into a much larger workload. A document can contain many pages or unusually complex content. Bound the extracted size, processing time, concurrency and downstream model input as well as the initial upload bytes.
Run untrusted parsing with restricted access and resource limits appropriate to the format. Keep parsers current, and use scanning or content reconstruction where suitable. No individual check guarantees a safe file. The aim is layered protection and a controlled failure when an input exceeds the supported workflow.
If processing happens in a background job, record a clear state for rejected or failed work. Do not let repeated retries consume unlimited resources on a file that will never parse. Customers need to distinguish waiting from an input that needs replacing.
Check ownership for every operation
Signing in does not entitle a person to every uploaded file. Verify the workspace and role for creating, listing, viewing, replacing and deleting objects. Test a request from a second workspace, including a direct request with a known file identifier.
Supabase Storage uses RLS policies for object operations. Uploading a new object and overwriting an existing one need different permissions. Review the operations your application actually uses; a policy that allows insertion does not establish the right read, update or delete behavior.
Workers and server credentials may have broader access than a browser user. Keep that access limited and enforce the job’s intended owner and destination in trusted server logic. Never place elevated credentials in the browser to make an inconvenient permission check go away.
Give downloads the same attention as uploads
A public bucket can serve a file to anyone who has its URL. Supabase documents that public retrieval bypasses bucket access controls. An obscure URL is not a private-file policy. Choose private storage for documents that should remain within a customer’s authorized account.
For private objects, use authorized downloads or deliberately issued signed links. Check permission before issuing a link, choose a lifetime that fits the task and treat the URL as temporary access to the file. Avoid placing signed URLs in analytics, logs or messages that unnecessarily widen access.
If access must be revoked immediately, verify the actual retrieval mechanism supports that requirement. A link that remains usable until expiry behaves differently from a fresh authorization check on every download. Choose the behavior before promising it to customers.
Test the lifecycle with disposable files
Use an isolated environment and harmless fixtures to check supported files, rejected types, oversized input and interrupted uploads. Confirm that rejection does not start paid model work. Check an upload that saves the object but fails before its database record is written.
Then test permission boundaries and deletion. A second workspace should not list, replace, download or process the first workspace’s file. A cancelled or deleted item should not reappear because an old worker completed later. Check derived outputs and temporary copies as well as the original.
Keep these checks tied to the customer journey when changing storage, parsing or workers. If documents are central to the product people pay for, a reliable private-file workflow is part of the product itself, not a separate feature to add when you have more time.
Frequently asked questions
Is a private Supabase bucket enough to protect customer files?
It is a useful storage choice, but the application still needs correct policies for each operation, ownership checks in workers and controlled access to derived files and outputs.
Can I trust the file type sent by the browser?
No. Treat the supplied content-type and filename as untrusted. Validate supported contents on the server using layered checks, with size and processing limits.
Are signed download URLs private?
They grant temporary access to whoever holds the link. Check authorization before issuing one, limit its lifetime and avoid exposing it unnecessarily. Verify revocation behavior if immediate access removal is required.