Validate Request DTOs and Stop Exposing Entities in Spring Boot

Flags @RequestBody parameters missing @Valid, JPA entities returned from controllers, and requests bound onto entities so clients can set any field.

What it flags

Flaggedusers/UserController.java
@RestController
@RequestMapping("/api/users")
public class UserController {

    private final UserRepository users;

    public UserController(UserRepository users) {
        this.users = users;
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public User register(@RequestBody User user) { // client can set id, role, and passwordHash
        return users.save(user);
    }
}
Passesusers/UserController.java
@RestController
@RequestMapping("/api/users")
public class UserController {

    public record RegisterUserRequest(
        @NotBlank @Email String email,
        @NotBlank @Size(min = 12, max = 128) String password,
        @NotBlank @Size(max = 100) String displayName) {}

    public record UserResponse(Long id, String email, String displayName) {}

    private final UserService users;

    public UserController(UserService users) {
        this.users = users;
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public UserResponse register(@Valid @RequestBody RegisterUserRequest request) {
        User user = users.register(request.email(), request.password(), request.displayName());
        return new UserResponse(user.getId(), user.getEmail(), user.getDisplayName());
    }
}

Why it matters

When a controller binds JSON straight onto an entity, every field the client names becomes writable, including roles, owner IDs, and prices, and a client-supplied id can make Spring Data save() merge over an existing row. Returning the entity leaks every mapped field, such as password hashes and internal flags, and a column added later leaks too without anyone touching the controller. A missing @Valid fails silently: the DTO carries constraint annotations, so the code looks validated, and Spring never runs them.

Agent instructions

cubic checks every pull request against these instructions. Paste them into AGENTS.md or Cursor rules and your AI coding tool follows them while it writes code.

AGENTS.md

Add this section to AGENTS.md at the repository root. Codex, Cursor, and other AI coding tools read it.

## Validate Request DTOs and Stop Exposing Entities in Spring Boot

Applies to `**/*.java`.

Review Spring MVC and WebFlux controllers for request bodies that skip validation and for JPA entities used as request or response types.

Flag changes that:
- Take a `@RequestBody` or `@ModelAttribute` parameter whose type declares `jakarta.validation` constraints without `@Valid` or `@Validated` on the parameter, so the constraints never run.
- Add nested objects or collections to a request DTO without `@Valid` on the field, so constraints on the nested type are skipped.
- Bind a `@RequestBody` or `@ModelAttribute` directly onto a JPA entity, letting clients set fields such as `id`, `role`, or `ownerId`. A client-supplied `id` can make repository `save()` merge over an existing row.
- Copy request data onto an entity with `BeanUtils.copyProperties` or a mapper that copies every matching field, instead of naming the fields the client may change.
- Return JPA entities, or `List`, `Page`, or `ResponseEntity` of entities, from controller methods, exposing internal fields such as password hashes and triggering lazy loads during serialization.

Do not flag:
- Controllers that validate explicitly with an injected `Validator` before using the input.
- Response types that are records, DTOs, or Spring Data projections, even when they mirror entity fields.
- Entities added to the model of a server-rendered view (Thymeleaf, JSP), where only the fields the template reads are rendered.

Checks files matching **/*.java.

More Spring Boot agents

See all Spring Boot code review standards

Run this agent on every pull request

cubic reviews every pull request against the agents you turn on and comments on the lines that break them.

Catch this in your code