How to Secure AI Agents in Spring Boot Applications
SafeClaw by Authensor integrates into Spring Boot applications as a managed bean, providing deny-by-default action gating for AI agent operations. Every ProcessBuilder.start(), file operation, and RestTemplate call your agent makes is gated against your YAML policy. Install with npx @authensor/safeclaw and inject the gate bean into your Spring services.
Why Spring Boot AI Agents Need Gating
Spring Boot is widely used for enterprise AI agent APIs, especially with Spring AI and Semantic Kernel for Java. These agents run with full JVM permissions — access to the filesystem, ability to spawn processes, and outbound network connectivity. In enterprise environments, an uncontrolled agent can access production databases, read configuration secrets, or modify deployment artifacts.
SafeClaw gates each action with 446 validated tests and provides a hash-chained audit trail for compliance.
Installation
npx @authensor/safeclaw
Policy
version: 1
defaultAction: deny
rules:
- action: file.read
path:
glob: "/app/data/**"
decision: allow
- action: file.write
path:
glob: "/app/output/**"
decision: allow
- action: process.exec
command:
startsWith: "mvn"
decision: allow
- action: process.exec
command:
startsWith: "gradle"
decision: allow
- action: network.request
host:
in: ["api.openai.com", "api.anthropic.com"]
decision: allow
- action: file.read
path:
glob: "*/application.properties"
decision: deny
- action: file.read
path:
glob: "*/application.yml"
decision: deny
Spring Boot Configuration
// config/SafeClawConfig.java
package com.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class SafeClawConfig {
@Bean
public RestTemplate safeClawRestTemplate() {
return new RestTemplate();
}
@Bean
public SafeClawGate safeClawGate(RestTemplate safeClawRestTemplate) {
return new SafeClawGate(safeClawRestTemplate, "http://localhost:9800");
}
}
Gate Bean
// service/SafeClawGate.java
package com.example.service;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
public class SafeClawGate {
private final RestTemplate restTemplate;
private final String endpoint;
public SafeClawGate(RestTemplate restTemplate, String endpoint) {
this.restTemplate = restTemplate;
this.endpoint = endpoint;
}
public record GateDecision(boolean allowed, String reason) {}
public GateDecision check(Map<String, Object> actionRequest) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(actionRequest, headers);
try {
var response = restTemplate.postForObject(
endpoint + "/check", entity, GateDecision.class
);
return response != null ? response : new GateDecision(false, "Null response");
} catch (Exception e) {
// Fail closed
return new GateDecision(false, "SafeClaw unreachable: " + e.getMessage());
}
}
public void require(Map<String, Object> actionRequest) {
GateDecision decision = check(actionRequest);
if (!decision.allowed()) {
throw new SecurityException("SafeClaw denied: " + decision.reason());
}
}
}
Agent Service
// service/AgentService.java
package com.example.service;
import org.springframework.stereotype.Service;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
@Service
public class AgentService {
private final SafeClawGate gate;
public AgentService(SafeClawGate gate) {
this.gate = gate;
}
public String readFile(String path) throws Exception {
gate.require(Map.of("action", "file.read", "path", path));
return Files.readString(Path.of(path));
}
public String execCommand(String command) throws Exception {
gate.require(Map.of("action", "process.exec", "command", command));
Process process = new ProcessBuilder(command.split(" "))
.redirectErrorStream(true)
.start();
return new String(process.getInputStream().readAllBytes());
}
public String fetchUrl(String url) throws Exception {
var host = java.net.URI.create(url).getHost();
gate.require(Map.of(
"action", "network.request",
"host", host,
"url", url,
"method", "GET"
));
return restTemplate.getForObject(url, String.class);
}
}
REST Controller
// controller/AgentController.java
@RestController
@RequestMapping("/api/agent")
public class AgentController {
private final AgentService agentService;
public AgentController(AgentService agentService) {
this.agentService = agentService;
}
@PostMapping("/read")
public ResponseEntity<?> readFile(@RequestBody Map<String, String> body) {
try {
String content = agentService.readFile(body.get("path"));
return ResponseEntity.ok(Map.of("content", content));
} catch (SecurityException e) {
return ResponseEntity.status(403).body(Map.of("error", e.getMessage()));
}
}
}
MIT licensed, works with Claude and OpenAI, hash-chained audit trail.
Cross-References
- Java Integration
- Kubernetes Deployment
- Semantic Kernel Safety
- Enterprise Compliance
- Deny-by-Default Explained
Try SafeClaw
Action-level gating for AI agents. Set it up in your browser in 60 seconds.
$ npx @authensor/safeclaw