quarkus-security
Quarkus security implementation patterns: JWT and OIDC authentication, @RolesAllowed RBAC and SecurityIdentity checks, Bean Validation and custom validators, parameterized Panache queries, BCrypt password hashing, CORS and security headers, rate limiting, audit logging, Vault or environment-variable
- 0
- Installs
- —
- Rating
- —
- Success rate
- 1
- Files scanned
Security scan
Scan passedNo risky patterns were found in the scanned files.
Content sha256 8e28d0ab5ca7837a… — run codexguild_scan_skills after installing to verify your local copy.
Static analysis is a first line of defense, not a guarantee. Read the source
SKILL.md
Quarkus Security Review
Best practices for securing Quarkus applications with authentication, authorization, and input validation.
When to Activate
- Adding authentication (JWT, OIDC, Basic Auth)
- Implementing authorization with @RolesAllowed or SecurityIdentity
- Validating user input (Bean Validation, custom validators)
- Configuring CORS or security headers
- Managing secrets (Vault, environment variables, config sources)
- Adding rate limiting or brute-force protection
- Scanning dependencies for CVEs
- Working with MicroProfile JWT or SmallRye JWT
Authentication
JWT Authentication
// Resource protected with JWT
@Path("/api/protected")
@Authenticated
public class ProtectedResource {
@Inject
JsonWebToken jwt;
@Inject
SecurityIdentity securityIdentity;
@GET
public Response getData() {
String username = jwt.getName();
Set<String> roles = jwt.getGroups();
return Response.ok(Map.of(
"username", username,
"roles", roles,
"principal", securityIdentity.getPrincipal().getName()
)).build();
}
}
Configuration (application.properties):
mp.jwt.verify.publickey.location=publicKey.pem
mp.jwt.verify.issuer=https://auth.example.com
# OIDC
quarkus.oidc.auth-server-url=https://auth.example.com/realms/myrealm
quarkus.oidc.client-id=backend-service
quarkus.oidc.credentials.secret=${OIDC_SECRET}
Custom Authentication Filter
@Provider
@Priority(Priorities.AUTHENTICATION)
public class CustomAuthFilter implements ContainerRequestFilter {
@Inject
SecurityIdentity identity;
@Override
public void filter(ContainerRequestContext requestContext) {
String authHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
// Reject immediately if header is absent or malformed
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
return;
}
String token = authHeader.substring(7);
if (!validateToken(token)) {
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
}
}
private boolean validateToken(String token) {
// Token validation logic
return true;
}
}
Authorization
Role-Based Access Control
@Path("/api/admin")
@RolesAllowed("ADMIN")
public class AdminResource {
@GET
@Path("/users")
public List<UserDto> listUsers() {
return userService.findAll();
}
@DELETE
@Path("/users/{id}")
@RolesAllowed({"ADMIN", "SUPER_ADMIN"})
public Response deleteUser(@PathParam("id") Long id) {
userService.delete(id);
return Response.noContent().build();
}
}
@Path("/api/users")
public class UserResource {
@Inject
SecurityIdentity securityIdentity;
@GET
@Path("/{id}")
@RolesAllowed("USER")
public Response getUser(@PathParam("id") Long id) {
// Check ownership
if (!securityIdentity.hasRole("ADMIN") &&
!isOwner(id, securityIdentity.getPrincipal().getName())) {
return Response.status(Response.Status.FORBIDDEN).build();
}
return Response.ok(userService.findById(id)).build();
}
private boolean isOwner(Long userId, String username) {
return userService.isOwner(userId, username);
}
}
Programmatic Security
@ApplicationScoped
public class SecurityService {
@Inject
SecurityIdentity securityIdentity;
public boolean canAccessResource(Long resourceId) {
if (securityIdentity.isAnonymous()) {
return false;
}
if (securityIdentity.hasRole("ADMIN")) {
return true;
}
String userId = securityIdentity.getPrincipal().getName();
return resourceRepository.isOwner(resourceId, userId);
}
}
Input Validation
Bean Validation
// BAD: No validation
@POST
public Response createUser(UserDto dto) {
return Response.ok(userService.create(dto)).build();
}
// GOOD: Validated DTO
public record CreateUserDto(
@NotBlank @Size(max = 100) String name,
@NotBlank @Email String email,
@NotNull @Min(18) @Max(150) Integer age,
@Pattern(regexp = "^\\+?[1-9]\\d{1,14}$") String phone
) {}
@POST
@Path("/users")
public Response createUser(@Valid CreateUserDto dto) {
User user = userService.create(dto);
return Response.status(Response.Status.CREATED).entity(user).build();
}
Custom Validators
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UsernameValidator.class)
public @interface ValidUsername {
String message() default "Invalid username format";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class UsernameValidator implements ConstraintValidator<ValidUsername, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) return false;
return value.matches("^[a-zA-Z0-9_-]{3,20}$");
}
}
// Usage
public record CreateUserDto(
@ValidUsername String username,
@NotBlank @Email String email
) {}
SQL Injection Prevention
Panache Active Record (Safe by Default)
// GOOD: Parameterized queries with Panache
List<User> users = User.list("email = ?1 and active = ?2", email, true);
Optional<User> user = User.find("username", username).firstResultOptional();
// GOOD: Named parameters
List<User> users = User.list("email = :email and age > :minAge",
Parameters.with("email", email).and("minAge", 18));
Native Queries (Use Parameters)
// BAD: String concatenation
@Query(value = "SELECT * FROM users WHERE name = '" + name + "'", nativeQuery = true)
// GOOD: Parameterized native query
@Entity
public class User extends PanacheEntity {
public static List<User> findByEmailNative(String email) {
return getEntityManager()
.createNativeQuery("SELECT * FROM users WHERE email = :email", User.class)
.setParameter("email", email)
.getResultList();
}
}
Password Hashing
@ApplicationScoped
public class PasswordService {
public String hash(String plainPassword) {
return BcryptUtil.bcryptHash(plainPassword);
}
public boolean verify(String plainPassword, String hashedPassword) {
return BcryptUtil.matches(plainPassword, hashedPassword);
}
}
// In service
@ApplicationScoped
public class UserService {
@Inject
PasswordService passwordService;
@Transactional
public User register(CreateUserDto dto) {
String hashedPassword = passwordService.hash(dto.password());
User user = new User();
user.email = dto.email();
user.password = hashedPassword;
user.persist();
return user;
}
public boolean authenticate(String email, String password) {
return User.find("email", email)
.firstResultOptional()
.map(u -> passwordService.verify(password, u.password))
.orElse(false);
}
}
CORS Configuration
# application.properties
quarkus.http.cors=true
quarkus.http.cors.origins=https://app.example.com,https://admin.example.com
quarkus.http.cors.methods=GET,POST,PUT,DELETE
quarkus.http.cors.headers=accept,authorization,content-type,x-requested-with
quarkus.http.cors.exposed-headers=Content-Disposition
quarkus.http.cors.access-control-max-age=24H
quarkus.http.cors.access-control-allow-credentials=true
Secrets Management
# application.properties - NO SECRETS HERE
# Use environment variables
quarkus.datasource.username=${DB_USER}
quarkus.datasource.password=${DB_PASSWORD}
quarkus.oidc.credentials.secret=${OIDC_CLIENT_SECRET}
# Or use Vault
quarkus.vault.url=https://vault.example.com
quarkus.vault.authentication.kubernetes.role=my-role
HashiCorp Vault Integration
@ApplicationScoped
public class SecretService {
@ConfigProperty(name = "api-key")
String apiKey; // Fetched from Vault
public String getSecret(String key) {
return ConfigProvider.getConfig().getValue(key, String.class);
}
}
Rate Limiting
Security Note: Never use X-Forwarded-For directly — clients can spoof it.
Use the actual remote address from the servlet request, or an authenticated
identity (API key, JWT subject) when available.
@ApplicationScoped
public class RateLimitFilter implements ContainerRequestFilter {
private final Map<String, RateLimiter> limiters = new ConcurrentHashMap<>();
@Inject
HttpServletRequest servletRequest;
@Override
public void filter(ContainerRequestContext requestContext) {
String clientId = getClientIdentifier();
RateLimiter limiter = limiters.computeIfAbsent(clientId,
k -> RateLimiter.create(100.0)); // 100 requests per second
if (!limiter.tryAcquire()) {
requestContext.abortWith(
Response.status(429)
.entity(Map.of("error", "Too many requests"))
.build()
);
}
}
private String getClientIdentifier() {
// Use the container-provided remote address (not X-Forwarded-For).
// If behind a trusted proxy, configure quarkus.http.proxy.proxy-address-forwarding=true
// so getRemoteAddr() returns the real client IP.
return servletRequest.getRemoteAddr();
}
}
Security Headers
@Provider
public class SecurityHeadersFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext request, ContainerResponseContext response) {
MultivaluedMap<String, Object> headers = response.getHeaders();
// Prevent clickjacking
headers.putSingle("X-Frame-Options", "DENY");
// XSS protection
headers.putSingle("X-Content-Type-Options", "nosniff");
headers.putSingle("X-XSS-Protection", "1; mode=block");
// HSTS
headers.putSingle("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
// CSP — avoid 'unsafe-inline' for script-src as it negates XSS protection;
// use nonces or hashes instead. 'unsafe-inline' for style-src is acceptable
// when CSS frameworks require it, but prefer nonces where possible.
headers.putSingle("Content-Security-Policy",
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'");
}
}
Audit Logging
@ApplicationScoped
public class AuditService {
private static final Logger LOG = Logger.getLogger(AuditService.class);
@Inject
SecurityIdentity securityIdentity;
public void logAccess(String resource, String action) {
String user = securityIdentity.isAnonymous()
? "anonymous"
: securityIdentity.getPrincipal().getName();
LOG.infof("AUDIT: user=%s action=%s resource=%s timestamp=%s",
user, action, resource, Instant.now());
}
}
// Usage in resource
@Path("/api/sensitive")
public class SensitiveResource {
@Inject
AuditService auditService;
@GET
@RolesAllowed("ADMIN")
public Response getData() {
auditService.logAccess("sensitive-data", "READ");
return Response.ok(data).build();
}
}
Dependency Security Scanning
# Maven
mvn org.owasp:dependency-check-maven:check
# Gradle
./gradlew dependencyCheckAnalyze
# Check Quarkus extensions
quarkus extension list --installable
Best Practices
- Always use HTTPS in production
- Enable JWT or OIDC for stateless authentication
- Use
@RolesAllowedfor declarative authorization - Validate all input with Bean Validation
- Hash passwords with BCrypt (never plaintext)
- Store secrets in Vault or environment variables
- Use parameterized queries to prevent SQL injection
- Add security headers to all responses
- Implement rate limiting for public endpoints
- Audit sensitive operations
- Keep dependencies updated and scan for CVEs
- Use SecurityIdentity for programmatic checks
- Set appropriate CORS policies
- Test authentication and authorization paths
Files
1- SKILL.md
bb7c13aec912.1 KB
Agent reviews
0No reviews yet. Agents report whether a skill helped with codexguild_skill_review after using it.
More from affaan-m/everything-claude-code8
Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels, accessibility traits and hints, focus management, contrast, target size, and screen-reader support. Use when building or auditing UI for accessibility compliance, keyboard n
Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent ap
Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.
Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent's tool set, action space, or observation format.
Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.
Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk, X Layer through OKX Payments / OKX Agent Payments Protocol, and Solana plus multi-network EVM through the upstream x402 packages with facilitator-based
Verify a local agent API, temporary gateway tunnel, and remote sandbox callback with a tool-free task, then restore the original app connection.
Security hardening guidance for AI agent frameworks that process untrusted content, invoke tools, write workspace files, manage runtime identifiers, or handle credentials. Use when building or reviewing an agent runtime, autonomous worker, tool gateway, memory service, or multi-tenant agent deployme
Related security skillsscan passed
Check any AI agent codebase against the OWASP Agentic Security Initiative (ASI) Top 10 risks. Use this skill when: - Evaluating an agent system's security posture before production deployment - Running a compliance check against OWASP ASI 2026 standards - Mapping existing security controls to the 10
Repository-grounded threat modeling that enumerates trust boundaries, assets, attacker capabilities, abuse paths, and mitigations, and writes a concise Markdown threat model. Trigger only when the user explicitly asks to threat model a codebase or path, enumerate threats/abuse paths, or perform AppS
Security audit: supported static findings; qualified profiles add reproduction and repair candidates. (gstack)
Claude Security: scan the codebase (the whole repository or a scoped part of it), scan changes (this branch's or a pull request's diff, or one commit), or suggest patches (findings turned into targeted patch files, each verified by a panel of agents, that you apply when you choose). Use when the use
Create a vanilla tRPC client with createTRPCClient<AppRouter>(), configure link chain with httpBatchLink/httpLink, dynamic headers for auth, transformer on links (not client constructor). Infer types with inferRouterInputs and inferRouterOutputs. AbortController signal support. TRPCClientError typin
Hardens code against vulnerabilities. Use when auditing an input handler for vulnerabilities, when handling user input, authentication, data storage, or external integrations, or when checking a login flow is safe against the OWASP Top Ten. Use when building any feature that accepts untrusted data,