Broken Function Level Authorization

How to Fix Broken Function Level Authorization in Spring Boot [March 2026] [CVE-2017-8046]

[Updated March 2026] Updated CVE-2017-8046

Overview

CVE-2017-8046 describes a vulnerability where malicious PATCH requests to servers using Spring Data REST could lead to remote code execution due to unsafe deserialization of JSON payloads. The issue affected Spring Data REST versions prior to 2.6.9 (Ingalls SR9) and prior to 3.0.1 (Kay SR1), with Spring Boot versions prior to 1.5.9 and 2.0 M6 also susceptible when combined with vulnerable Data REST configurations. Attackers could craft JSON data that, when deserialized on the server, could cause arbitrary Java code execution in the application process. This falls under CWE-20 (Improper Input Validation) and specifically enables deserialization-based gadget chains when PATCH semantics are exposed on REST endpoints. The impact is severe: attacker-controlled deserialization can compromise confidentiality, integrity, and availability, potentially enabling full server takeover depending on the gadgets on the classpath. The vulnerability manifests in real Spring Boot deployments where PATCH-based partial updates are applied directly to domain objects via untrusted JSON.

Affected Versions

Spring Data REST: prior to 2.6.9 (Ingalls SR9) and prior to 3.0.1 (Kay SR1); Spring Boot: prior to 1.5.9 and 2.0 M6

Code Fix Example

Spring Boot API Security Remediation
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.math.BigDecimal;

@RestController
public class WidgetController {
  @Autowired private WidgetRepository repo;

  // Vulnerable approach (illustrative only)
  @PatchMapping("/widgets/{id}/patch-vulnerable")
  public Widget patchWidgetVulnerable(@PathVariable Long id, @RequestBody JsonNode patch) throws IOException {
    Widget w = repo.findById(id).orElseThrow(() -> new ResourceNotFoundException("Widget not found"));
    ObjectMapper mapper = new ObjectMapper();
    // BAD: enabling default typing can deserialize malicious payloads into arbitrary types
    mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    Widget updated = mapper.readerForUpdating(w).readValue(patch.toString(), Widget.class);
    repo.save(updated);
    return updated;
  }

  // Safe approach (fix)
  @PatchMapping("/widgets/{id}/patch-safe")
  public Widget patchWidgetSafe(@PathVariable Long id, @RequestBody WidgetPatchDto patch) {
    Widget w = repo.findById(id).orElseThrow(() -> new ResourceNotFoundException("Widget not found"));
    if (patch.getName() != null) w.setName(patch.getName());
    if (patch.getPrice() != null) w.setPrice(patch.getPrice());
    repo.save(w);
    return w;
  }

  public static class WidgetPatchDto {
    private String name;
    private BigDecimal price;
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public BigDecimal getPrice() { return price; }
    public void setPrice(BigDecimal price) { this.price = price; }
  }
}

CVE References

Choose which optional cookies to allow. You can change this any time.