← Back to blog
Blog Detail

Unsafe File Upload Testing: Proving Web Shell Impact

An agent hitting your upload form is a candidate, not a finding. This is the test path that turns it into a replayable proof of server-side execution.

Trusteed Team
Trusteed Editorial
Written On
Oct 20, 2026
Category
Research
Read Time
8 min read
  • Unsafe File Upload
  • Web Shell
  • Penetration Testing
  • Vulnerability Validation
  • OWASP WSTG
  • AppSec
Unsafe File Upload Testing: Proving Web Shell Impact

Unsafe File Upload Testing: Proving Web Shell Impact

TL;DR

Automated intrusion campaigns now work from a short, familiar list: SQL injection, unsafe file uploads, insecure deserialization, authentication bypass, and server-side template injection — followed by a web shell planted for persistence. None of those classes is novel, which is the point: the flaws being automated are configuration and code-level mistakes you can test this week. The question is not whether something flagged an upload form, but whether you can prove a file you control is stored and interpreted by the server, with a request and response a second researcher can replay. That proof is what separates a finding from a queue entry.

What this is

Agent-driven attack spree. Automation that runs a chain rather than a task: choose targets, find a weakness, exploit it, then establish persistence. Published research on one such campaign describes exactly that shape — targets prioritized by traffic, browser automation used to confirm an e-commerce site could actually process orders, then agents dispatched against the listed vulnerability classes, with some instructions explicitly directing a web shell deployment.

Proof of impact for an upload. Three artifacts you hold at the end: the exact request the server accepted, the stored file you can fetch back, and evidence the file was interpreted rather than served as bytes. A 200 on a multipart POST is none of those. Neither is a scanner template name in a report.

Validation is the reverse direction of the attack. The attacker needs the shell to keep working; you need the smallest demonstration that proves the same code path is reachable — then you remove it.

Why it matters

Anything that accepts a file and renders user content is in scope: avatar and attachment uploads, invoice and CSV imports, product image pipelines, support portals, marketing microsites. The reported victims show the spread — Reuters, coordinating disclosure with the research firm behind the tooling, named John Deere, SharkNinja, and Cummins; SharkNinja described the affected system as a standalone product-support site, and Cummins was investigating a third-party vendor's website. Ancillary properties are not harmless: they hold session cookies, support email, and often credentials reused on the systems that matter.

The economics are the part worth internalizing. The reporting quotes a rough per-task cost of about $5, a figure the researchers themselves describe as uncertain, and notes that an agent can pursue a candidate for hours with little human direction. When the cost of trying collapses, the long tail of sites previously judged "not worth attacking" becomes worth attacking. Your staging host and your regional microsite are on that list now.

What fails if you ignore it: an upload form that accepts a script extension but stores files outside the webroot looks identical, in a scanner report, to one that stores them inside it and lets the web server execute them. The gap between those two is an incident.

How it works

The upload decision has three independent parts, and exploitation needs all three to line up badly:

  • Trust boundary on the type. Does the server use the client-declared Content-Type, the file extension, or an allowlist it enforces itself? Mismatched pairs are the cheapest test you can run.
  • Landing directory. A file written to /var/uploads is data. The same file written under the document root with an executable extension is code. Path, mount, and server config decide this, not the application code you are reading.
  • Name control. If the stored filename derives from user input, traversal, double extensions, trailing dots, and case variants become relevant.

Adjacent sinks belong in the same test pass. The instructions observed in the campaign named deserialization endpoints and template injection alongside uploads, which makes sense: session cookies, view state, message queues, and invoice or email rendering often sit on the same feature. All three follow the same validation logic — find the sink, send the smallest input that changes server behavior, capture the response, remove the artifact.

There is no CVE or version range to cite for this class. These are configuration and code-level behaviors, so the authoritative procedure is OWASP's Web Security Testing Guide case for malicious file uploads and the File Upload Cheat Sheet, both linked in Sources. Cite your own captured traffic for the target-specific claim.

Illustrative example of a completed proof, using a token instead of a functional shell: upload probe.php containing an echo of the string 7f3a91c2; the POST returns {"url":"/uploads/probe.php"}; a GET to that URL returns exactly 7f3a91c2 with no PHP source in the body. Execution confirmed. Delete the file, re-request the URL, record the 404, and attach the whole sequence.

Detection and response

Trusteed insight card: a file-upload signal ladder running from a 200 on a multipart POST, to a script path missing from the deploy artifact, to a web user spawning a shell, with an artifact-diff proof panel and the evidence needed to replay it.

The upload case leaves unusually concrete telemetry, which is why it is worth rehearsing before you need it:

  • Access logs. A multipart POST that returns 200/201, followed by a GET to a script-extension path that does not exist in the release artifact.
  • Webroot integrity. Files newer than the last deploy, or a hash comparison against the build artifact — the single highest-signal check available.
  • Process telemetry on the web tier. The web user spawning sh, cmd.exe, or an interpreter is close to conclusive.
  • Egress. A web server opening outbound connections it never opens in normal operation.
  • WAF. Traversal sequences in filenames, double extensions, script content inside SVG.

Defender check you can run today: list every upload endpoint from the last 30 days of traffic, enumerate the files those endpoints created, and diff that list against your deploy artifact. Anything unexplained gets pulled, hashed, and read.

One more: if your team or a vendor runs agent tooling, the campaign exposed operator instructions and secrets on internet-reachable dashboards. Inventory them, and treat every API key stored in one as leaked.

What to do

  1. Enumerate the upload surface. Multipart endpoints from proxy logs and from the app's own routes — including admin-only, API-based, and legacy paths nobody maintains.
  2. Baseline with two accounts. One authenticated, one not. Same request, compare status codes and bodies. The difference tells you whether authorization is enforced on the handler or only in the UI.
  3. Test extension and Content-Type independently. Allowed extension with a wrong MIME; blocked extension with an image MIME. Record the response body, not just the code.
  4. Confirm the landing path. Fetch the file by URL. Does the returned path match what the server told you it stored?
  5. Prove execution with a marker, not a shell. A file that echoes a unique token is sufficient. Fetch it once, capture the response, delete it, and record the 404.
  6. Probe name handling. Traversal sequences, double extensions, trailing dots, case variants — but stop at the first proof and record it.
  7. Check the adjacent sinks. Deserialization parameters and template-rendered fields on the same feature get the same treatment.
  8. Attach evidence to the finding. Raw request, raw response, timestamp, the marker value, and the removal proof. A second researcher should reproduce it from the write-up alone.
  9. Retest after remediation with the identical request. A fix that only blocks the filename you used is not a fix.

FAQ

Did this campaign rely on a zero-day? No. The reported classes — SQL injection, unsafe upload, insecure deserialization, auth bypass, template injection — are long-documented. The change is throughput and persistence intent, not novelty.

Is an AI agent finding a bug proof of impact? No. A hit means a candidate worth testing. Proof requires a controlled demonstration: a request you sent, a response you captured, and an artifact you removed afterward.

What is the safest way to prove an upload executes? A minimal file that returns a unique token, requested once and deleted. Do not leave an interactive shell on any system, including your own staging environment, and never on a client's.

How do I tell a scanner's "possible upload vulnerability" from a real one? Replay the exact request. If you cannot retrieve the stored file and cannot show it was interpreted, you have a configuration question, not a finding.

Do exposed operator dashboards matter if I don't run agent tooling myself? They matter to whoever does — including your vendors. Secrets in those panels are the same keys the agents harvested and the same keys that unlock other systems.

Sources

Join Our Newsletter

Trusteed keeps you informed: emerging risks, platform updates, and practical guides for faster defense.