# How to test file upload security in agent code

> File upload security testing checks every stage from receiving bytes to serving them again. Learn the type, size, storage, cleanup, and authorization tests to require on agent-written upload code, and how Factory security review checks them on each pull request.

URL: https://factory.com/articles/file-upload-security-testing-coding-agents
Published: 2026-09-28
Updated: 2026-10-23

To test file upload security, map every stage from the request limit to the download handler, then write fixtures that prove each prohibited file fails closed and leaves nothing behind. Check generated storage keys, cleanup after rejection, and cross-tenant retrieval as well as the accepted path. When a coding agent edits upload code, require those tests and a security review before merge.

Coding agent changes may add a new MIME type, alter object-store permissions, move validation after persistence, or expose predictable retrieval paths. A successful upload response does not prove that the workflow is safe.

The [OWASP File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html) recommends defense in depth. It covers extension allowlists, content-type validation, generated filenames, size limits, storage outside the web root, authorization, and malware or content analysis where appropriate.

## Map the upload path

Map the request limit, multipart parser, temporary storage, validation, transformation, permanent storage, metadata database, and download handler. Record where each rejection happens and which cleanup action follows.

The diagram shows that path. Each stage needs at least one test that fails there and leaves no orphaned object or database row.

Request limit</span><br/><span style='color:#8A8380 !important'>size and timeout</span>"]
    B["<span style='color:#FAFAFA !important;font-weight:600'>Multipart parser</span><br/><span style='color:#8A8380 !important'>names and boundaries</span>"]
    C["<span style='color:#FAFAFA !important;font-weight:600'>Temporary storage</span><br/><span style='color:#8A8380 !important'>generated key, private permissions</span>"]
    D["<span style='color:#FAFAFA !important;font-weight:600'>Validation</span><br/><span style='color:#8A8380 !important'>type, signature, scanner</span>"]
    E["<span style='color:#FAFAFA !important;font-weight:600'>Permanent storage</span><br/><span style='color:#8A8380 !important'>tenant prefix, outside web root</span>"]
    F["<span style='color:#FAFAFA !important;font-weight:600'>Download handler</span><br/><span style='color:#8A8380 !important'>authorization, content type, disposition</span>"]
    X["<span style='color:#FAFAFA !important;font-weight:600'>Rejected</span><br/><span style='color:#8A8380 !important'>cleanup, stable client error</span>"]
    A --> B --> C --> D --> E --> F
    A -. fail .-> X
    D -. fail .-> X
`}
/>

Set processing timeouts as well as byte limits. A compact archive or malformed document can consume disproportionate CPU, memory, or extracted storage even when the original upload stays below its size ceiling.

## Build fixtures for each failure

Use small synthetic fixtures for permitted and prohibited cases. Do not place live malware in the repository. Security scanners commonly publish harmless test signatures for integration checks, so use only the approved fixture for the deployed scanner.

Each row in the checklist should exist as an automated test before an agent-written upload change merges.

| Test case | How to build it | Expected result |
| --- | --- | --- |
| Extension and signature mismatch | Rename a file to an allowed extension | Reject, no stored object |
| Declared MIME type mismatch | Send an allowed type with other content | Reject |
| Size boundary | One byte below and one above the limit | Accept, then reject |
| Empty file | Zero-byte upload | Policy-defined result, no orphan |
| Long or Unicode name | Very long and normalization-sensitive names | Server-generated key, no path change |
| Scanner signature | The scanner's published test file | Reject and clean up |
| Cross-tenant read | Upload as one tenant, fetch as another | Deny |

## Test storage and retrieval controls

An accepted file should receive a server-generated storage key. Test that the original name cannot select a path, overwrite another tenant's object, or escape a temporary directory. Verify permissions on temporary and permanent storage.

Retrieval needs independent authorization. Test direct object URLs, thumbnail or conversion endpoints, and cached responses. Deleting a database row should not leave a public object reachable under its old URL.

When content is served inline, verify the response content type and disposition. Active formats need a documented policy because browsers may interpret uploaded HTML, SVG, or office documents in ways the application did not expect.

Run fixtures against an isolated bucket or local storage emulator. Use unique prefixes, delete test objects after assertions, and record object keys and outcomes without retaining uploaded contents in ordinary CI logs.

## How Factory reviews upload changes

Factory is a platform for running a software factory, where agents called Droids take work from a signal to a reviewed pull request. For upload code, the review step is where a moved validation call or a loosened bucket policy gets caught.

**Security review on every pull request.** Factory's [security review](https://docs.factory.com/software-factory/security-review) runs in two passes. The first finds candidate vulnerabilities, and the second re-checks each one before it is reported with a severity from P0 (critical) to P3 (low). Adding `automatic_security_review: true` to the review workflow runs it on every non-draft pull request, and commenting `@droid security` runs it on demand.

**Repository rules.** A `security-review-guidelines` skill in `.factory/skills/` can direct the reviewer to multipart parsing, object-store policy, content transformation, and download authorization. The executable fixture suite remains the source of evidence for the application's exact policy.

**Runtime evidence.** Factory's [Automated QA](https://docs.factory.com/software-factory/automated-qa) generates a project QA skill with `/install-qa` that tests web, CLI, and API surfaces, so an upload flow can be exercised against the running service and the result attached to the pull request.

To set up the same checks on your own repository, run these commands in the Droid CLI or desktop app.

<div className="not-prose my-6 flex flex-col gap-3 [&_button]:!w-auto">
  <div className="grid grid-cols-1 gap-y-5 md:grid-cols-[max-content_1fr] md:gap-x-4">
    
    <span className="text-base-300 text-sm leading-relaxed"><strong className="text-light-base-primary font-medium">On-demand audit.</strong> Reviews the entire repository or just the current diff.</span>
    
    <span className="text-base-300 text-sm leading-relaxed"><strong className="text-light-base-primary font-medium">One-time setup.</strong> Adds automated code and security review to your pull requests.</span>
  </div>
</div>

## Frequently asked questions

### What is file upload security testing?

File upload security testing verifies every stage between receiving bytes and serving them again, including the request limit, multipart parser, validation, storage, metadata, and download handler. A successful upload response does not prove that the workflow is safe.

### Which file upload test cases matter most?

Cover mismatches between extension, declared MIME type, and file signature, empty files, duplicate and very long names, nested archive names, Unicode normalization, and sizes just below and above the limit. Every prohibited fixture should fail closed with no retrievable artifact.

### How do you test malware scanning without live malware?

Do not place live malware in the repository. Security scanners commonly publish harmless test signatures for integration checks, so use only the approved fixture for the deployed scanner.

### How do you test upload authorization?

Create two users or tenants, upload as one, and attempt access as the other. Test direct object URLs, thumbnail or conversion endpoints, and cached responses, and confirm a deleted record does not leave a public object reachable.

### How does Factory review upload changes?

Factory security review runs on pull requests in two passes and reports validated findings with P0 to P3 severity. A security-review-guidelines skill can point it at multipart parsing, object-store policy, content transformation, and download authorization.

## Further reading

- [How to test Content Security Policy changes](https://factory.com/articles/content-security-policy-testing-coding-agents)
- [SSRF testing for coding agent network changes](https://factory.com/articles/ssrf-testing-coding-agent-changes)
- [Least-privilege access for coding agents](https://factory.com/articles/least-privilege-coding-agents)
- [OWASP File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html)
