Enterprise Java is heavy. It relies heavily on convention over configuration, auto-wiring, and deeply nested object serialization. In the Nigerian fintech ecosystem, legacy banks and scaling switch providers (like Interswitch or NIBSS infrastructure) overwhelmingly rely on Spring Boot. When we audit Spring Boot APIs, we do not look for simple cross-site scripting; we hunt for systemic logic failures, object injection vulnerabilities, and catastrophic credential leaks via default monitoring endpoints.

Exposed Spring Boot Actuator endpoints

Spring Boot Actuator provides built-in endpoints to monitor your application state, track metrics, and manage traffic. If these endpoints are left publicly accessible without strict authentication, they leak your entire infrastructure configuration. Attackers automate the discovery of `/actuator` paths using directory brute-forcing tools. The most critical actuator endpoints we exploit during engagements include:

The Fix: Restrict actuator access entirely to an internal management port distinct from the main application port. If it must be exposed, require strong HTTP Basic Authentication or JWT validation in your Spring Security configuration. Furthermore, explicitly mask sensitive keys in your `application.properties` (e.g., `management.endpoint.env.keys-to-sanitize=*password*,*secret*,*key*`).

// SECURE Spring Security configuration for Actuators
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(auth -> auth
        .requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("OPS_ADMIN") // Strict role check
        .anyRequest().authenticated()
    );
    return http.build();
}

Auditing Spring Security antMatchers and requestMatchers

Spring Security filters incoming requests using a top-down chain of matchers. The framework stops processing at the first match. A pervasive configuration flaw in enterprise Spring Boot applications is using overly permissive wildcard matching or mapping paths incorrectly. This allows attackers to bypass the entire authentication filter chain using path traversal techniques.

// VULNERABLE configuration matching
http.authorizeHttpRequests(auth -> auth
    .requestMatchers("/api/public/**").permitAll()
    // Bypass: An attacker requesting /api/public/../private/data 
    // may bypass the filter if the servlet container normalizes paths differently than Spring Security.
    .anyRequest().authenticated()
);

We exploit this using CVE-2022-22978 and similar regex bypasses. If developers use `.regexMatchers()` with poorly constructed expressions, we append carriage returns (`%0d` or `%0a`) to our HTTP requests. The regex matcher fails to read past the newline, assumes the request does not match the restricted path, and defaults to `permitAll()`, granting us unauthenticated access to secured APIs.

The Fix: Always use `mvcMatchers` (or `requestMatchers` in Spring Security 6+) instead of `antMatchers` where possible, as they align perfectly with Spring MVC routing logic. Enforce strict routing rules and rely on a deny-by-default architecture.

Spring Expression Language (SpEL) Injection

Spring Expression Language (SpEL) is a powerful tool used to evaluate expressions dynamically at runtime. It is heavily utilized in Spring Data, Spring Security (`@PreAuthorize`), and custom validation logic. If your application evaluates user-supplied input directly inside a SpEL parser, attackers can inject malicious payloads to execute arbitrary system code (Remote Code Execution).

We frequently hunt for SpEL injections inside custom `@Constraint` validation annotations. If a developer attempts to dynamically evaluate a localized error message string that contains unescaped user input, we execute a payload.

// VULNERABLE SpEL evaluation inside a custom validator
ExpressionParser parser = new SpelExpressionParser();
// Attacker sends: T(java.lang.Runtime).getRuntime().exec("cat /etc/passwd")
Expression exp = parser.parseExpression(userInput);
String value = exp.getValue(context, String.class);

The Fix: Never parse dynamic SpEL expressions from user-controlled parameters. If dynamic evaluation is an absolute business requirement, use a `SimpleEvaluationContext` instead of a `StandardEvaluationContext`. The simple context explicitly restricts expression features and completely blocks access to Java system classes and method invocations.

Database access validation (JPA & Hibernate)

Enterprise Java relies heavily on Object-Relational Mapping (ORM) frameworks like Hibernate (via Spring Data JPA). While ORMs inherently protect against basic SQL injection, developers frequently break this protection when writing custom `@Query` annotations or building dynamic criteria queries.

Using JPQL/HQL concatenations is just as dangerous as raw SQL string formatting. When a developer writes `@Query("SELECT u FROM User u WHERE u.username = '" + username + "'")`, they introduce an HQL injection vulnerability. We exploit this to extract data from other tables or bypass login mechanisms entirely. We audit all repository interfaces to ensure that custom queries utilize positional parameters (e.g., `?1`) or named parameters (e.g., `:username`) to bind inputs securely at the driver level.

Mass Assignment and Jackson Deserialization

Spring Boot uses Jackson for JSON serialization and deserialization. When a controller accepts a complex Entity object directly as a `@RequestBody` (e.g., `public ResponseEntity updateProfile(@RequestBody User user)`), it exposes the application to Mass Assignment attacks.

If the `User` entity contains an `isAdmin` boolean or a `walletBalance` integer, Jackson will faithfully map any JSON key provided by the attacker directly onto the entity, overwriting the database values. Attackers simply intercept the profile update request and append {"isAdmin": true, "walletBalance": 99999999}. We bypass this entirely by enforcing the strict use of Data Transfer Objects (DTOs). A controller must only accept a `UserUpdateDTO` containing strictly the fields the user is authorized to modify.

Insecure Deserialization via Polymorphic Jackson Types

Beyond mass assignment, Jackson introduces catastrophic Remote Code Execution risks if polymorphic type handling (`@JsonTypeInfo`) is enabled globally or configured loosely. When polymorphic typing is active, Jackson expects the incoming JSON to explicitly declare its Java class type (e.g., {"@class": "com.simpalabs.models.AdminUser", "id": 1}).

We exploit this by injecting "gadget chains" into the JSON payload. We change the `@class` value to a dangerous Java class that executes code upon initialization or finalization (like `org.springframework.context.support.FileSystemXmlApplicationContext`). When Jackson attempts to deserialize this object, it automatically instantiates the dangerous class, immediately handing us command execution on the host server. We audit your Jackson `ObjectMapper` configurations to ensure `enableDefaultTyping()` is never used, and that any `@JsonTypeInfo` annotations strictly enforce a highly restrictive whitelist of permitted subclasses.

Example finding

Actuator env leak leading to database access

During a core banking integration audit, we discovered an unauthenticated /actuator/env endpoint on a microservice. The endpoint exposed a configuration value named `SPRING_DATASOURCE_PASSWORD`. Because sanitization was weak and the endpoint lacked an operations role restriction, we extracted the plaintext password. We then used this credential to directly connect to the production PostgreSQL instance, bypassing the application layer entirely. Restrict Actuator to a separate management network, expose only required endpoints, and verify that secrets stay masked.

Running enterprise Java backends on Spring Boot? Secure your architecture.

Book a Spring Boot Pentest

Frequently asked questions

Why is Spring Boot Actuator a critical security risk?

Spring Boot Actuator exposes monitoring endpoints like `/actuator/env` and `/actuator/heapdump`. If left public, attackers can extract database credentials, API keys, and memory dumps containing active sessions.

How do you bypass Spring Security configurations during an audit?

We audit Spring Security configuration classes to identify bypasses, such as incorrect wildcard mapping (e.g., `antMatchers('/api/**').permitAll()`) or misconfigured request matchers.

What is SpEL injection in Spring Boot?

Spring Expression Language (SpEL) injection occurs when untrusted user input is evaluated dynamically inside a SpEL expression. This allows attackers to run arbitrary system commands (RCE).

Related reading

Blog: Flask API security · Django API security · API data leaks

Services: Penetration testing · Secure architecture review