Safeguard
Application Security•

ASVS 5.0 V3.5.3: Use POST, PUT, PATCH or DELETE for Sensitive Actions

ASVS V3.5.3 (Level 1): sensitive functionality must not hang off GET, HEAD or OPTIONS, or must validate Sec-Fetch headers. Examples and how to test method handling.

Safeguard Security Team
2 min read

ASVS 5.0 requirement V3.5.3 says requests to sensitive functionality must use appropriate HTTP methods such as POST, PUT, PATCH or DELETE, and not the "safe" methods GET, HEAD or OPTIONS. As an alternative, you can strictly validate Sec-Fetch-* request headers to make sure the request did not come from an inappropriate cross-origin call, a navigation, or a resource load. It is a Level 1 requirement.

Why it matters

Safe methods can be triggered by anything: an image tag, a link prefetch, a script source, a chat preview bot. If GET /account/delete removes the account, then <img src="https://app.example.com/account/delete"> on any page does it. CSRF defenses are usually applied to unsafe methods, so a state change on GET also skips them.

How to implement it

Register state changing routes only for unsafe methods:

app.post("/account/delete", requireAuth, csrfCheck, deleteAccount);   // yes
// app.get("/account/delete", ...)                                    // never

Django:

from django.views.decorators.http import require_POST

@require_POST
def delete_account(request): ...

Where a legacy route must stay on GET, validate fetch metadata:

function sameSiteOnly(req, res, next) {
  const site = req.get("Sec-Fetch-Site");
  const mode = req.get("Sec-Fetch-Mode");
  if (site === "same-origin" && mode !== "navigate") return next();
  res.status(403).end();
}

Browsers set Sec-Fetch-* and scripts cannot override them. Treat a missing header as a refusal for sensitive routes, or accept it only for clients you know do not send it.

How to test it

for m in GET HEAD OPTIONS; do
  curl -s -o /dev/null -w "$m %{http_code}\n" -X $m https://app.example.com/account/delete -b cookies.txt
done

Expect 405 or 403, and verify nothing changed. Then crawl your route list for GET handlers that write data.

Common mistakes

Logout or unsubscribe by GET. Both are state changes.

Framework "any method" routes. Restrict methods explicitly.

Treating Sec-Fetch as optional. An absent header must not mean allowed.

Quick check

Is GET with a token in the URL acceptable?

It avoids forgery, but URL tokens leak through logs and Referer headers. Use POST.

Sources

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.