Summary
- Context:
IngestionController provides endpoints for triggering remote web crawling and local directory ingestion. It uses JSR-303 validation annotations (@Min, @Max) on request parameters to enforce safety limits on the scope of these operations.
- Bug: The
IngestionController class is missing the @Validated annotation, which is required by Spring to enable method-level validation for request parameters.
- Actual vs. expected: Validation constraints on
@RequestParam arguments are ignored; a user can provide values for maxPages or maxFiles that exceed the intended safety limits (e.g., millions of pages).
- Impact: An attacker can trigger extremely large, resource-intensive, and potentially costly ingestion runs (remote crawls or local scans), leading to Denial of Service via thread pool exhaustion and disk space depletion.
Code with bug
@RestController
@RequestMapping("/api/ingest")
@PermitAll
@PreAuthorize("permitAll()")
public class IngestionController extends BaseController { // <-- BUG 🔴 Missing @Validated annotation
// ...
@PostMapping
public ResponseEntity<? extends IngestionResponse> ingest(
@RequestParam(name = "maxPages", defaultValue = "100")
@Min(value = 1, message = "maxPages must be at least 1")
@Max(value = MAX_ALLOWED_PAGES, message = "maxPages cannot exceed " + MAX_ALLOWED_PAGES) // <-- BUG 🔴 Not enforced
int maxPages) {
Evidence
- Spring Framework Requirements: In Spring Boot, JSR-303 annotations on method parameters (like
@RequestParam, @PathVariable) are only processed if the class is annotated with @org.springframework.validation.annotation.Validated. Without this annotation, Spring does not create the necessary AOP proxy to intercept calls and validate the arguments.
- Missing Safety Net: While
LocalDocsDirectoryIngestionService manually checks if maxFiles <= 0, it does NOT check the upper bound. DocsIngestionService (for remote crawling) has no manual validation of maxPages at all. This means the @Max limit defined in the controller is the only thing preventing a massive ingestion run, and it is currently disabled.
- Synchronous Execution: The ingestion methods call
docsIngestionService.crawlAndIngest(maxPages) and docsIngestionService.ingestLocalDirectory(...) synchronously. These methods perform blocking IO (network requests, disk writes). A single request with an extremely high maxPages value will tie up a Tomcat worker thread for a long duration, making it trivial to exhaust the thread pool.
- Incorrect Error Handling Path: The controller contains a redundant
@ExceptionHandler(IllegalArgumentException.class). If validation were working correctly, it would throw ConstraintViolationException, not IllegalArgumentException. Furthermore, the methods contain catch (RuntimeException runtimeException) blocks that return 500 INTERNAL SERVER ERROR, which would catch any validation exceptions (if enabled) and hide the fact that they are client-side errors (which should be 400 BAD REQUEST).
Why has this bug gone undetected?
The application appears to be in an early or development stage where ingestion is triggered with default values or small increments. Since the code does not crash when receiving a large number (it just proceeds to crawl as many pages as it can find), the lack of enforcement is only apparent when monitoring server resources or LLM costs during a large-scale or malicious request. Additionally, the presence of the validation annotations gives a false sense of security to developers reviewing the code.
Recommended fix
Add the @Validated annotation to the IngestionController class to enable constraint enforcement for method parameters. Additionally, remove the broad catch (RuntimeException) blocks in the controller methods and rely on the @ExceptionHandler (updated to handle ConstraintViolationException) to return consistent 400 BAD REQUEST responses for all validation failures.
@RestController
@RequestMapping("/api/ingest")
@Validated // <-- FIX 🟢
@PermitAll
@PreAuthorize("permitAll()")
public class IngestionController extends BaseController {
Summary
IngestionControllerprovides endpoints for triggering remote web crawling and local directory ingestion. It uses JSR-303 validation annotations (@Min,@Max) on request parameters to enforce safety limits on the scope of these operations.IngestionControllerclass is missing the@Validatedannotation, which is required by Spring to enable method-level validation for request parameters.@RequestParamarguments are ignored; a user can provide values formaxPagesormaxFilesthat exceed the intended safety limits (e.g., millions of pages).Code with bug
Evidence
@RequestParam,@PathVariable) are only processed if the class is annotated with@org.springframework.validation.annotation.Validated. Without this annotation, Spring does not create the necessary AOP proxy to intercept calls and validate the arguments.LocalDocsDirectoryIngestionServicemanually checks ifmaxFiles <= 0, it does NOT check the upper bound.DocsIngestionService(for remote crawling) has no manual validation ofmaxPagesat all. This means the@Maxlimit defined in the controller is the only thing preventing a massive ingestion run, and it is currently disabled.docsIngestionService.crawlAndIngest(maxPages)anddocsIngestionService.ingestLocalDirectory(...)synchronously. These methods perform blocking IO (network requests, disk writes). A single request with an extremely highmaxPagesvalue will tie up a Tomcat worker thread for a long duration, making it trivial to exhaust the thread pool.@ExceptionHandler(IllegalArgumentException.class). If validation were working correctly, it would throwConstraintViolationException, notIllegalArgumentException. Furthermore, the methods containcatch (RuntimeException runtimeException)blocks that return500 INTERNAL SERVER ERROR, which would catch any validation exceptions (if enabled) and hide the fact that they are client-side errors (which should be400 BAD REQUEST).Why has this bug gone undetected?
The application appears to be in an early or development stage where ingestion is triggered with default values or small increments. Since the code does not crash when receiving a large number (it just proceeds to crawl as many pages as it can find), the lack of enforcement is only apparent when monitoring server resources or LLM costs during a large-scale or malicious request. Additionally, the presence of the validation annotations gives a false sense of security to developers reviewing the code.
Recommended fix
Add the
@Validatedannotation to theIngestionControllerclass to enable constraint enforcement for method parameters. Additionally, remove the broadcatch (RuntimeException)blocks in the controller methods and rely on the@ExceptionHandler(updated to handleConstraintViolationException) to return consistent400 BAD REQUESTresponses for all validation failures.