BootUI
Try it
Setup
Features
Properties
AI agents
Ecosystem
GitHub
Try it
Setup
Features
Properties
AI agents
Ecosystem
GitHub
  • Get started

    • Try the sample app
    • Setup
    • Spring WebFlux
    • Quarkus
    • Activation and safety
    • Non-standard runtimes
    • Troubleshooting
  • Features

    • All features
    • Overview
    • Advisors
    • Runtime
    • Configuration
    • Database
    • Security
    • Services
    • Diagnostics
    • Developer tools
  • Reference

    • Properties
    • Framework support
    • AI agents
    • Command line
    • BootUI family
  • Diagnostic checks

    • Architecture
    • REST API
    • Spring
    • Hibernate
    • Database
    • Security
    • Vulnerabilities
    • Memory
    • Pentesting
    • GraalVM readiness
    • CRaC readiness
    • Quarkus
    • Quarkus security
  • Contributing

    • Repository
    • Specification
    • Implementation plan
    • Quarkus design notes
    • WebFlux design notes
  • Privacy

Quarkus security checks

The Security panel, on Quarkus, runs a fixed, on-demand 45-rule ruleset against the host application's Quarkus security configuration — not Spring Security. It reads the effective quarkus.http.*, quarkus.oidc.*, quarkus.smallrye-jwt.*, quarkus.tls.*, quarkus.management.*, quarkus.http.proxy.*, quarkus.security.users.embedded.*, quarkus.rest-csrf.* (the CSRF extension), quarkus.grpc.server.*, quarkus.smallrye-graphql.*, quarkus-elytron-security-jdbc principal-query settings, and Kafka/SmallRye Reactive Messaging channel security settings, plus build-time counts of the standard authorization annotations (@RolesAllowed, @PermitAll, @DenyAll, @Authenticated, @PermissionsAllowed, and @AuthorizationPolicy) discovered in the application's own classes. It never intercepts live traffic, exposes credentials or secrets, or modifies the configuration. Findings are heuristic review prompts; the right remediation depends on the application's threat model and deployment topology.

OIDC checks aggregate the active default tenant and active named tenants; a tenant with quarkus.oidc[.<tenant>].tenant-enabled=false is excluded.

Reading more than the preview

Quarkus Security keeps its twenty-entry sampleViolations preview and full violationCount. View violations and GET <api>/security/rules/{id}/violations?scanId=...&offset=0&limit=100 read bounded, sanitized details retained by the same scan. Retention truncation is separate from security evidence coverage; see snapshot, retention, and MCP/CLI retrieval. QS-AUTHZ-004 preserves its aggregate preview while retaining endpoint identities when metadata provides them. Legacy count-only observations retain zero endpoint identities and explicitly report incomplete details.

This is the Quarkus replacement for the Spring ruleset in SECURITY-CHECKS.md: the panel and DTO are shared, but the framework-specific registries are mutually exclusive (Elytron/OIDC vs Spring Security). Equivalent authentication, authorization, transport, and CORS risks intentionally have framework-native rules on both stacks; Spring-only concepts (filter chains, FilterChainProxy, method-security proxies) are not evaluated here, and Quarkus-only concepts below are not evaluated on Spring.

Availability and bounds

Known-findings scores follow the same score eligibility policy as Spring. A required observation left unknown by native evaluation produces PARTIAL even when collection succeeded and no finding was emitted. Inapplicable extension checks alone do not make coverage incomplete.

The advisor is available on Quarkus without a security extension. Supported configuration facts are collected on explicit scans; endpoint declarations are captured at build time. Missing, inactive, unsupported and invalid observations are distinct: invalid or unreadable evidence is not silently treated as an absent control. Known findings survive unrelated incomplete collection. Unsupported analysis produces a partial scan; genuine failures use sanitized analysis errors.

This catalog was audited against Quarkus 3.33.3.1. Configuration metadata cannot establish arbitrary custom policies, dynamic tenants, delivered headers or network reachability. Collection never invokes tenant resolvers, credential providers, custom policies or HTTP-security initializers to resolve these gaps. Secret-hygiene classification is limited to recognized local application configuration sources; arbitrary external/dynamic sources are not read to label their values as committed secrets. Bounded metadata discovery also recognizes native SmallRye environment and system-property sources, without classifying their values as local-file secrets. For example, OIDC configured through a system property is not mistaken for an absent authentication mechanism. Native runtime-registry and test-URL bridges are not mistaken for arbitrary configuration inventories. Non-default @ApplicationPath, quarkus.rest.path, and quarkus.http.root-path prefixes make endpoint coverage incomplete rather than comparing unprefixed declarations with listener paths. After Arc initialization, the advisor compares raw security annotations with already-materialized interceptor bindings. A discrepancy, or a native additional-secured-method declaration, makes the affected endpoint's annotation evidence unknown. Unrelated transformations do not invalidate all endpoints. Binding agreement is not proof of an actual SecurityCheck or request authorization, and this is not a universal inventory of transformed routes and security checks. The native annotation stores are lazy, so even an annotation query can execute application transformation code; the advisor does not query those stores or replay transformers. Independent configuration findings are retained. A forwarding configuration (quarkus.http.proxy.proxy-address-forwarding=true) is not treated as proof that a proxy actually terminates TLS, so listener-level transport findings remain visible and explain that a verified terminating proxy can make them acceptable. A handful of rules — marked Quarkus-specific below — have no Spring Security equivalent at all: they cover Quarkus-only capabilities (gRPC, GraphQL, SmallRye Reactive Messaging). The rest address the same concerns the Spring Security advisor already checks, adapted to Quarkus's own config keys and extensions.

Severity scale

SeverityMeaning
CRITICALExposes credentials or secrets, or disables a critical control.
HIGHCommonly leaves the application exposed. Usually fix before production.
MEDIUMA hardening gap that warrants review.
LOWLower-impact hygiene.
INFOInformational. The right fix depends on context.

The panel lists only checks with findings, ordered by severity, count, then rule id.

The advisor score applies the shared severity penalty to every concrete finding, not just once per violated rule. Dismissed rules remove all of their findings from the score.


Filter the list, then jump to a check — the detail below narrows to match.

  1. QS-AUTH-001HIGHNo authentication mechanism configured
  2. QS-AUTH-002HIGHBasic authentication without TLS
  3. QS-AUTH-003LOWReview form authentication CSRF defenses
  4. QS-AUTH-004MEDIUMJWT verification without an expected issuer
  5. QS-AUTH-007MEDIUMEmbedded identity store enabled for production
  6. QS-AUTH-008MEDIUMJWT verification without audience validation
  7. QS-AUTH-009INFOReview static JWT trust-anchor rotation
  8. QS-AUTH-010HIGHJDBC identity store using clear-text password mapper
  9. QS-AUTH-012HIGHForm authentication without TLS
  10. QS-AUTH-013HIGHEmbedded users stored with plain-text passwords
  11. QS-AUTHZ-001HIGHNo path or role authorization
  12. QS-AUTHZ-002INFOPermission policy permits all paths
  13. QS-AUTHZ-004MEDIUMNo deny-by-default for unannotated endpoints
  14. QS-TLS-001LOWInsecure requests enabled
  15. QS-TLS-002INFONo TLS configured for the main HTTP listener
  16. QS-TLS-003HIGHTLS certificate validation disabled
  17. QS-TLS-004HIGHIdentity-provider and JWK endpoints should use HTTPS
  18. QS-TLS-005HIGHTLS hostname verification disabled
  19. QS-TLS-006LOWLegacy TLS protocol versions configured
  20. QS-CORS-001LOWCORS allows any origin
  21. QS-CORS-002HIGHCORS wildcard origin with credentials
  22. QS-HDR-001LOWWeak Strict-Transport-Security policy
  23. QS-HDR-002MEDIUMWeak Content-Security-Policy
  24. QS-HDR-003LOWMissing Strict-Transport-Security header
  25. QS-HDR-004LOWMissing Content-Security-Policy header
  26. QS-HDR-005LOWMissing clickjacking protection
  27. QS-HDR-006LOWMissing X-Content-Type-Options header
  28. QS-DEV-001HIGHOIDC TLS verification disabled
  29. QS-DEV-002MEDIUMSwagger/GraphQL UI always included
  30. QS-DEV-003LOWSmallRye Health UI always included
  31. QS-OIDC-001HIGHOIDC without token audience validation
  32. QS-OIDC-002MEDIUMOIDC web-app session cookie not forced secure
  33. QS-OIDC-003MEDIUMPublic OIDC client without PKCE
  34. QS-OIDC-004HIGHOIDC token issuer validation is bypassed
  35. QS-OIDC-005MEDIUMOIDC session token encryption disabled
  36. QS-MGMT-001LOWManagement interface on a non-loopback host
  37. QS-MGMT-003INFOManagement interface has no explicit prod-scoped host binding
  38. QS-PROXY-001LOWForwarded headers trusted from any address
  39. QS-CFG-001MEDIUMPossible secret in configuration
  40. QS-SESSION-001MEDIUMForm-auth session cookie not HttpOnly
  41. QS-SESSION-002LOWForm-auth session cookie SameSite=None
  42. QS-SESSION-003LOWLong form-auth idle timeout
  43. QS-GRPC-001MEDIUMgRPC server reflection enabled in the prod profile
  44. QS-GRAPHQL-001LOWGraphQL schema introspection enabled
  45. QS-MSG-001HIGHMessaging credentials configured without an encrypted protocol

Authentication

QS-AUTH-001 - No authentication mechanism configured

  • Severity: HIGH
  • Detects: Supported observations find no active OIDC, JWT, basic, form, or mTLS mechanism, protective permission policy, restrictive endpoint annotation, default roles, or deny-unannotated default, while at least one REST-server endpoint is declared. @PermitAll and policy=permit are not restrictive controls. REST clients and unrelated secured beans are not endpoint evidence; unsupported custom authorization or incomplete endpoint metadata prevents an absence conclusion.
  • Recommendation: Add an auth mechanism (quarkus-oidc, quarkus-smallrye-jwt, quarkus.http.auth.basic) or restrict endpoints with @RolesAllowed/@PermissionsAllowed/ quarkus.http.auth.permission.*.
  • Learn more: https://quarkus.io/version/3.33/guides/security-overview

QS-AUTH-002 - Basic authentication without TLS

  • Severity: HIGH
  • Detects: Basic authentication is active while quarkus.http.insecure-requests=enabled accepts plain HTTP. Credentials submitted through that listener would lack transport encryption; the scan does not observe submitted credentials or external ingress policy.
  • Recommendation: Set insecure-requests=redirect (or disabled) and configure SSL.
  • Learn more: https://quarkus.io/version/3.33/guides/security-basic-authentication

QS-AUTH-003 - Review form authentication CSRF defenses

  • Severity: LOW
  • Detects: quarkus.http.auth.form.enabled=true (cookie-based login) without the io.quarkus:quarkus-rest-csrf extension, or with quarkus.rest-csrf.enabled=false or quarkus.rest-csrf.verify-token=false. This is a review of the standard defense, not proof that custom CSRF defenses are absent. Extension presence alone does not establish verification or coverage of every path, method, or media type.
  • Recommendation: Verify coverage of state-changing browser requests; use quarkus-rest-csrf and embed its token in forms where appropriate.
  • Learn more: https://quarkus.io/version/3.33/guides/security-csrf-prevention

QS-AUTH-004 - JWT verification without an expected issuer

  • Severity: MEDIUM
  • Detects: The JWT capability and a supported verification key source are active, but mp.jwt.verify.issuer is absent. Supported sources include the inline MicroProfile key, mp.jwt.verify.publickey.location, and the overriding smallrye.jwt.verify.key.location. Custom verifiers remain unknown; no verifier is executed to establish acceptance.
  • Recommendation: Set mp.jwt.verify.issuer to the expected token issuer.
  • Learn more: https://quarkus.io/version/3.33/guides/security-jwt

Retired: QS-AUTH-005. Proactive authentication controls when credentials are processed, not whether authorization is enforced. The supported deferred mode is not an independent security deficiency. Authorization coverage is reviewed by the applicable authorization rules; this ID remains reserved.

Retired: QS-AUTH-006 (JWT signature algorithm not pinned for a remote JWKS) was removed. MicroProfile JWT 2.1 defines mp.jwt.verify.publickey.algorithm with an RS256 default and explicitly describes the property as the algorithm whitelist. Leaving it unset therefore does not accept an unbounded algorithm set; the old rule reported a missing explicit preference even though the effective verifier remained pinned. The rule id is retired and will not be reused.

QS-AUTH-007 - Embedded identity store enabled for production

  • Severity: MEDIUM
  • Detects: The properties identity-store capability is present and supported local prod declarations enable quarkus.security.users.embedded.enabled (%prod. first, then the base key). BootUI runs in dev/test, so a %dev/%test-only declaration — the configuration this rule recommends — is not a finding, while an explicit %prod=false overrides base true. The embedded store is distinct from the file store. This reviews configuration, not a running production deployment; environment and external sources are not read for this review.
  • Recommendation: Review the identity-store choice for each deployment; keep demonstration users local and use an appropriate production identity provider or password-hashing store.
  • Learn more: https://quarkus.io/version/3.33/guides/security-properties#embedded-users

QS-AUTH-008 - JWT verification without audience validation

  • Severity: MEDIUM
  • Detects: The JWT capability and a supported verification key source are active, but no mp.jwt.verify.audiences declaration is observed. Scalar and supported indexed lists are recognized. This reviews the expected audience configuration rather than executing tokens or inferring custom validation from unrelated beans.
  • Recommendation: Set mp.jwt.verify.audiences to this service's expected audience(s).
  • Learn more: https://quarkus.io/version/3.33/guides/security-jwt

QS-AUTH-009 - Review static JWT trust-anchor rotation

  • Severity: INFO
  • Detects: Supported JWT configuration selects an inline mp.jwt.verify.publickey without an overriding key location.
  • Why it matters: Static trust anchors are supported and can rotate out of band. This is an operational reminder, not an inherent weakness or a requirement to use remote JWKS.
  • Recommendation: Document and test the trust-anchor replacement process.
  • Learn more: https://quarkus.io/version/3.33/guides/security-jwt

QS-AUTH-010 - JDBC identity store using clear-text password mapper

  • Severity: HIGH
  • Detects: The JDBC security capability and quarkus.security.jdbc.enabled=true are active, and a supported quarkus.security.jdbc.principal-query[.<name>].clear-password-mapper.enabled=true declaration selects clear-text password comparison. Unrelated keys containing principal-query, disabled stores, and unsupported named-query syntax do not establish this finding.
  • Recommendation: Switch to bcrypt-password-mapper (or another hashing mapper) and re-hash stored passwords.
  • Learn more: https://quarkus.io/version/3.33/guides/security-jdbc

QS-AUTH-012 - Form authentication without TLS

  • Severity: HIGH
  • Detects: quarkus.http.auth.form.enabled=true while quarkus.http.insecure-requests=enabled accepts passwords over plain HTTP, exposing them to passive network observers and active intermediaries. Forwarded-header trust does not suppress the finding because it does not prove that a proxy terminates TLS.
  • Recommendation: Set quarkus.http.insecure-requests=redirect (or disabled) and configure TLS.
  • Learn more: https://quarkus.io/version/3.33/guides/security-authentication-mechanisms#form-auth

QS-AUTH-013 - Embedded users stored with plain-text passwords

  • Severity: HIGH
  • Detects: Supported local prod declarations set both quarkus.security.users.embedded.enabled=true and quarkus.security.users.embedded.plain-text=true, making the embedded identity store accept literal passwords. Quarkus defaults plain-text to false and otherwise expects a digest derived from username:realm:password. Like QS-AUTH-007, %dev/%test-only demo users are not production evidence.
  • Recommendation: Use a production identity provider or a supported adaptive password-hashing store. The embedded store's legacy digest default is not a recommendation for modern production password storage.
  • Learn more: https://quarkus.io/version/3.33/guides/security-properties#embedded-users

Retired: QS-AUTH-011 (JDBC identity store bcrypt work-factor too low) was removed. The rule checked principal-query.*.bcrypt-password-mapper.work-factor, a property that does not exist: BcryptPasswordKeyMapperConfig (quarkus-elytron-security-jdbc) has no work-factor/cost-factor field at all (only enabled, password-index, hash-encoding, salt-index, salt-encoding, iteration-count-index — a column index, not a cost factor). Bcrypt's cost factor is embedded in the stored MCF-format hash string itself, not externally configurable via this extension, so the rule could never fire and its remediation ("raise the work factor") was nonsensical. The rule id is retired and will not be reused.

Authorization

QS-AUTHZ-001 - No path or role authorization

  • Severity: HIGH
  • Detects: An active auth mechanism and declared REST-server endpoints are observed, but no supported restrictive permission policy, endpoint annotation, default roles, or deny-unannotated default is found. Disabled policies and policy=permit do not count as protection. Unsupported custom/global policies or endpoint metadata remain unknown.
  • Recommendation: Add @RolesAllowed/@PermissionsAllowed/@Authenticated or path permissions with policy=authenticated/roles.
  • Learn more: https://quarkus.io/version/3.33/guides/security-authorize-web-endpoints-reference

QS-AUTHZ-002 - Permission policy permits all paths

  • Severity: INFO
  • Detects: A non-shared, applies-to=all permission declares policy=permit for /* without a method restriction. Supported scope names are case-normalized, including the native ALL default; unsupported values remain unknown. / is an exact path, not an application-wide wildcard. This is a public-default declaration, not proof that authentication is disabled: more-specific mappings, same-path restrictions, shared policies, endpoint annotations, and REST defaults can still restrict requests.
  • Recommendation: Confirm the public default is intentional; narrow it or select a restrictive policy where needed.
  • Learn more: https://quarkus.io/version/3.33/guides/security-authorize-web-endpoints-reference

Retired: QS-AUTHZ-003. An arbitrary annotation ratio is not effective authorization coverage. Path policies, defaults, public declarations and custom policies cannot be reduced to a percentage of annotated methods. The ID remains reserved.

QS-AUTHZ-004 - No deny-by-default for unannotated endpoints

  • Severity: MEDIUM
  • Detects: Authentication is active, deny-unannotated and default roles are absent in the current runtime, and a directly declared unannotated REST endpoint has no supported matching restriction. The bounded analysis distinguishes exact / from /*, longest-path and exact-path precedence, method-specific mappings, same-path restrictions, and shared policies. HTTP (all) and REST (jaxrs) scopes choose their matching policies independently, then intersect restrictions: a more-specific permit in one phase cannot override denial in the other. A matched path with no matching method mapping denies that method; a GET-only mapping does not establish that POST is public. Method annotations override class annotations, and explicit @PermitAll declarations are not counted as accidentally unannotated. Custom policies, unresolved route templates, inherited/transformed metadata, non-default listener prefixes, and unsupported scopes remain unknown rather than being executed or treated as public.
  • Recommendation: Set deny-unannotated-endpoints=true (or default roles) and mark public endpoints @PermitAll.
  • Learn more: https://quarkus.io/version/3.33/guides/security-authorize-web-endpoints-reference

Transport

QS-TLS-001 - Insecure requests enabled

  • Severity: LOW
  • Detects: quarkus.http.insecure-requests=enabled serves plain HTTP. The rule uses Quarkus's effective default: absent means disabled when quarkus.http.ssl.client-auth=required, and enabled otherwise. Forwarding configuration does not suppress it.
  • Why it matters: Acceptable in local dev or behind a TLS-terminating proxy; risky if exposed directly.
  • Recommendation: Prefer redirect once TLS is available, or document the terminating proxy.
  • Learn more: https://quarkus.io/version/3.33/guides/http-reference#ssl

QS-TLS-002 - No TLS configured for the main HTTP listener

  • Severity: INFO
  • Detects: No supported main-listener TLS material is declared. Recognized forms include a legacy keystore, paired certificate/key lists, TLS-registry JKS/P12 paths, and paired PEM certificate/key entries. A named registry bucket only counts when selected by quarkus.http.tls-configuration-name; an unrelated client bucket does not. Partial material and programmatic providers remain incomplete, and a declaration is not proof of usable HTTPS. Password, alias, ordering, and other option defaults are not certificate material and do not, by themselves, make TLS observation incomplete.
  • Recommendation: Acceptable behind a verified terminating proxy.
  • Learn more: https://quarkus.io/version/3.33/guides/http-reference#ssl

QS-TLS-003 - TLS certificate validation disabled

  • Severity: HIGH
  • Detects: trust-all=true is set on the default TLS registry bucket (quarkus.tls.trust-all) or any named bucket (quarkus.tls.<name>.trust-all), disabling peer certificate validation wherever that bucket is used and creating a transport-validation risk. The scan does not establish whether every named bucket is consumed.
  • Recommendation: Remove trust-all; import the peer's CA into a trust-store instead.
  • Learn more: https://quarkus.io/version/3.33/guides/tls-registry-reference#trusting-all-certificates-and-hostname-verification

QS-TLS-004 - Identity-provider and JWK endpoints should use HTTPS

  • Severity: HIGH
  • Detects: An active OIDC tenant's auth-server URL or an active JWT verifier's effective remote key location uses plain HTTP. smallrye.jwt.verify.key.location overrides mp.jwt.verify.publickey.location; stale configuration for absent capabilities or disabled tenants does not establish a finding. No discovery, key retrieval, or other network request is made, and endpoint values are not retained in report samples.
  • Recommendation: Use HTTPS endpoints with certificate validation enabled.
  • Learn more: https://quarkus.io/version/3.33/guides/security-oidc-bearer-token-authentication#bearer-token-jwt-claim-verification

QS-TLS-005 - TLS hostname verification disabled

  • Severity: HIGH
  • Detects: quarkus.tls.hostname-verification-algorithm=NONE, the equivalent setting on a named TLS registry bucket, or legacy OIDC tls.verification=certificate-validation validates certificate chains without checking that the certificate belongs to the requested host. A named OIDC TLS configuration supersedes the legacy OIDC setting and avoids a duplicate/obsolete finding.
  • Recommendation: Enable hostname verification for each applicable consumer. TLS-registry defaults depend on the consumer; the presence of a bucket alone does not establish a connection using it.
  • Learn more: https://quarkus.io/version/3.33/guides/tls-registry-reference#trusting-all-certificates-and-hostname-verification

QS-TLS-006 - Legacy TLS protocol versions configured

  • Severity: LOW
  • Detects: An effective quarkus.http.ssl.protocols, quarkus.tls.protocols, or quarkus.tls.<name>.protocols list (scalar or indexed) enables TLSv1, TLSv1.1, or SSLv3, compared case-insensitively. SSLv2Hello is a ClientHello compatibility format, not a protocol version, and is not flagged. Like Quarkus's HttpServerOptionsUtils, the legacy HTTP list is ignored when quarkus.http.tls-configuration-name or a default registry key store owns the listener. Report samples are value-free declaration labels; unresolved lists remain incomplete.
  • Why it matters: RFC 8996 deprecates TLS 1.0 and 1.1. The JDK disables them by default through jdk.tls.disabledAlgorithms, so an explicit opt-in is often inert, and the scan does not establish that a named bucket is consumed or that a listener or client negotiates a legacy version.
  • Recommendation: Remove the legacy versions. Quarkus defaults the HTTP list to TLSv1.3,TLSv1.2 and the TLS registry to TLSv1.3; isolate a legacy peer in a dedicated named TLS configuration.
  • Learn more: https://quarkus.io/version/3.33/guides/tls-registry-reference#tls-protocol-versions

CORS

QS-CORS-001 - CORS allows any origin

  • Severity: LOW
  • Detects: Enabled CORS permits universal noncredentialed response sharing. A literal * is universal only as the sole origin; recognized universal regexes (/.*/ or /^.*$/) also match universally inside a list. *,https://app.example is not a universal literal wildcard, while /.*/,https://app.example is universal. Empty origins remain restrictive. Explicit quarkus.http.cors.enabled=false wins over the legacy enable setting. Arbitrary regexes are not executed or classified as safe.
  • Recommendation: Confirm public response sharing is intentional, or configure trusted origins. CORS is not an authentication or authorization boundary.
  • Learn more: https://quarkus.io/version/3.33/guides/security-cors

QS-CORS-002 - CORS wildcard origin with credentials

  • Severity: HIGH
  • Detects: A supported universal origin configuration allows credentials. Explicit quarkus.http.cors.access-control-allow-credentials wins; otherwise both exact and regex origin matches default credentials to true. A sole * or sole /.*/ is Quarkus's wildcard origin (CORSFilter.isOriginConfiguredWithWildcard), which defaults credentials to false and is reviewed by QS-CORS-001 instead. A universal regex inside a list, or a sole /^.*$/, is matched as a regex and defaults credentials to true. Quarkus reflects the request Origin, so this is not the browser-rejected literal Access-Control-Allow-Origin: * plus credentials combination. QS-CORS-001 is not also emitted for the same credentialed policy.
  • Recommendation: Pin explicit origins; never combine wildcard with credentials.
  • Learn more: https://quarkus.io/version/3.33/guides/security-cors

Retired: QS-CORS-003. Reflecting requested methods/headers for an allowed origin is supported Quarkus/Fetch behavior, not an independent bypass of the origin trust boundary. Least-privilege API design can still use narrower lists. The ID remains reserved.

Retired: QS-CORS-005. Unset origins are restrictive, not a security gap. The filter is not inert: it rejects disallowed cross-origin requests. The ID remains reserved.

Retired: QS-CORS-004 (CORS regex origin pattern not anchored) was removed. The rule claimed Quarkus's CORSFilter matched an unanchored /regex/ origin pattern anywhere in the string (.find() semantics) rather than against the whole string, citing quarkusio/quarkus#34718. Direct inspection of the current CORSFilter.isOriginAllowedByRegex shows pattern.matcher(origin).matches() — Java's .matches() requires a full match of the entire input string, not .find() — and issue #34718 was fixed in Quarkus 3.3.0, long before this project's current Quarkus line. The bypass the rule warned about no longer applies to any Quarkus version this project supports, so the rule was removed rather than re-worded; preferring literal origins over regex (and anchoring any regex you do use) remains sound general advice, just not something this advisor asserts a specific exploitable mechanism for. The rule id is retired and will not be reused.

Headers

QS-HDR-001 - Weak Strict-Transport-Security policy

  • Severity: LOW
  • Detects: A supported global HSTS declaration has an invalid lifetime, disables HSTS with max-age=0, or uses a lifetime shorter than one year. Zero disables the policy; a short nonzero lifetime may be an intentional rollout. Multiple or scoped declarations are not combined into an effective delivered policy.
  • Recommendation: Review the lifetime and rollout plan. One year is a review baseline, not a protocol minimum. includeSubDomains is optional and should be enabled only when every subdomain is HTTPS-ready.
  • Learn more: https://quarkus.io/version/3.33/guides/http-reference#additional-http-headers

QS-HDR-002 - Weak Content-Security-Policy

  • Severity: MEDIUM
  • Detects: One supported global enforcing CSP permits unsafe inline scripts, unsafe evaluation, or an unrestricted script source. The bounded parser observes script-src/default-src fallback, script-src-elem and script-src-attr, first-duplicate-directive semantics, nonce/hash/strict-dynamic exceptions, and restrictive script overrides. Style-only inline permissions and scoped host wildcards are not arbitrary-script-source proof. Report-only policy does not establish enforcement; enforcing plus report-only is valid. Multiple policies, unsupported syntax, unknown custom-writer ordering, and uncertain path/method scope remain incomplete.
  • Recommendation: Remove unsafe-inline/unsafe-eval and wildcard sources; use nonces/hashes for scripts.
  • Learn more: https://quarkus.io/version/3.33/guides/http-reference#additional-http-headers

QS-HDR-003 - Missing Strict-Transport-Security header

  • Severity: LOW
  • Detects: Declared document endpoints and supported listener TLS configuration are present, but no global HSTS declaration is observed. This is configuration review, not proof of missing delivered headers. Custom filters, proxies, and uncertain header scope prevent an absence conclusion.
  • Recommendation: Add quarkus.http.header."Strict-Transport-Security".value=max-age=31536000; add includeSubDomains only after every subdomain is HTTPS-ready.
  • Learn more: https://quarkus.io/version/3.33/guides/http-reference#additional-http-headers

QS-HDR-004 - Missing Content-Security-Policy header

  • Severity: LOW
  • Detects: Declared document endpoints have no observed global enforcing CSP declaration. A report-only policy alone is not enforcing, but an additional report-only policy does not invalidate an enforcing one. API-only or uncertain document applicability, custom filters, and scoped/multiple header declarations remain incomplete.
  • Recommendation: Add a CSP tailored to the app's script/style/asset origins.
  • Learn more: https://quarkus.io/version/3.33/guides/http-reference#additional-http-headers

QS-HDR-005 - Missing clickjacking protection

  • Severity: LOW
  • Detects: Declared document endpoints have no supported restrictive framing declaration after applying precedence. An enforcing CSP frame-ancestors directive overrides X-Frame-Options even when permissive (*); an empty ancestor list blocks all framing. Valid global X-Frame-Options: DENY/SAMEORIGIN is an alternative only when the enforcing ancestor directive is known absent. Invalid XFO values do not establish protection. Report-only directives do not override XFO; unknown CSP composition or writer/path/method scope cannot be assumed safe because XFO exists.
  • Recommendation: Use a restrictive enforcing CSP frame-ancestors, such as 'none'. XFO DENY is an alternative only without an overriding enforcing ancestor directive.
  • Learn more: https://quarkus.io/version/3.33/guides/http-reference#additional-http-headers

QS-HDR-006 - Missing X-Content-Type-Options header

  • Severity: LOW
  • Detects: No valid global X-Content-Type-Options=nosniff declaration is observed. Header names and the recognized value are compared case-insensitively; an arbitrary nonblank value does not count. Scoped headers and custom response filters remain unknown, and the scan does not observe proxy-delivered or runtime-written headers.
  • Recommendation: Add quarkus.http.header."X-Content-Type-Options".value=nosniff.
  • Learn more: https://quarkus.io/version/3.33/guides/http-reference#additional-http-headers

Retired: QS-HDR-007. Modern browsers default to strict-origin-when-cross-origin; the absence of an explicit Referrer-Policy does not establish the full-URL disclosure asserted by the former rule. Applications can still select an explicit policy for their needs. The ID remains reserved.

Retired: QS-HDR-008. Missing Permissions-Policy alone does not establish a meaningful defect without application feature and embedding context. Feature-specific browser policy remains a design choice. The ID remains reserved.

Dev exposure

QS-DEV-001 - OIDC TLS verification disabled

  • Severity: HIGH
  • Detects: quarkus.oidc.tls.verification=none disables provider certificate validation. This legacy setting is deprecated in Quarkus 3.33 in favor of a TLS registry configuration. Only active tenants are considered; a selected named TLS configuration overrides the legacy setting.
  • Recommendation: Sometimes used against a local dev provider, but must never reach production.
  • Learn more: https://quarkus.io/version/3.33/guides/tls-registry-reference#trusting-all-certificates-and-hostname-verification

QS-DEV-002 - Swagger/GraphQL UI always included

  • Severity: MEDIUM
  • Detects: The corresponding capability is present and supported local prod declarations enable quarkus.swagger-ui.always-include or quarkus.smallrye-graphql.ui.always-include. An explicit %prod=false overrides base true; a dev-only declaration is not production evidence. Inclusion does not prove an enabled route, anonymous access, or a running production deployment. quarkus.smallrye-openapi.always-include does not exist and is not evaluated.
  • Recommendation: Restrict it to dev, or remove always-include.
  • Learn more: https://quarkus.io/version/3.33/guides/openapi-swaggerui#swagger-ui

QS-DEV-003 - SmallRye Health UI always included

  • Severity: LOW
  • Detects: The Health capability is present and supported local prod declarations enable quarkus.smallrye-health.ui.always-include, honoring explicit prod overrides. Inclusion is distinct from route availability, access policy, and production exposure; none is inferred from inclusion alone.
  • Recommendation: Remove the override so the Health UI is only available outside production, or protect it via the management interface / a permission policy.
  • Learn more: https://quarkus.io/version/3.33/guides/smallrye-health#ui

OIDC

QS-OIDC-001 - OIDC without token audience validation

  • Severity: HIGH
  • Detects: OIDC is configured for a default or named service/hybrid token-consuming tenant without that tenant's expected quarkus.oidc[.<tenant>].token.audience, or with the exact singleton any, which disables audience validation. Scalar and supported indexed lists are recognized; any,service is not the singleton sentinel. Absent capabilities, disabled tenants, and unknown custom validation are not missing-audience proof. Pure web-app authorization-code clients are excluded because their primary authentication artifact is an OIDC ID token whose audience is validated against the client id by the protocol implementation; applying this resource-server rule to them would be a false positive.
  • Why it matters: The severity is HIGH for service/M2M flows because RFC 8725 requires each JWT application to validate that the token was issued for it.
  • Recommendation: Set the tenant's token audience to this resource server's expected audience.
  • Learn more: https://quarkus.io/version/3.33/guides/security-oidc-bearer-token-authentication#bearer-token-jwt-claim-verification

QS-OIDC-002 - OIDC web-app session cookie not forced secure

  • Severity: MEDIUM
  • Detects: An active OIDC web-app/hybrid tenant does not force cookie Secure while the listener accepts HTTP. Without the override, Secure is request-dependent; HTTPS key material alongside an accepted HTTP listener does not make HTTP session cookies secure. Disabled or redirected HTTP does not trigger this finding.
  • Recommendation: Disable or redirect HTTP and review quarkus.oidc.authentication.cookie-force-secure, including trusted proxy handling. The scan does not establish external TLS termination.
  • Learn more: https://quarkus.io/version/3.33/guides/security-oidc-code-flow-authentication#oidc-cookies

QS-OIDC-003 - Public OIDC client without PKCE

  • Severity: MEDIUM
  • Detects: Supported client-authentication metadata establishes a public web-app/hybrid client without PKCE. Missing literal credentials.secret alone is insufficient: client-secret providers, JWT client authentication, supported key/secret-provider settings, and provider presets are considered. Spotify and Twitter/X presets enable PKCE by default; an explicit authentication.pkce-required=false overrides that default. Dynamic tenants, custom providers, unsupported source/profile combinations, and incomplete credential metadata remain unknown.
  • Recommendation: Set quarkus.oidc.authentication.pkce-required=true for public clients.
  • Learn more: https://quarkus.io/version/3.33/guides/security-oidc-code-flow-authentication#proof-key-for-code-exchange-pkce

QS-OIDC-004 - OIDC token issuer validation is bypassed

  • Severity: HIGH
  • Detects: The exact lowercase quarkus.oidc[.<tenant>].token.issuer=any disables issuer matching for an active default or named tenant. ANY is not that sentinel. Supported provider defaults also count: the Microsoft preset supplies any unless explicitly overridden. Disabled tenants are excluded, and no token or tenant resolver is invoked.
  • Recommendation: Remove token.issuer=any and pin the exact trusted issuer; use explicit tenant resolution when multiple issuers are intentional.
  • Learn more: https://quarkus.io/version/3.33/guides/security-oidc-bearer-token-authentication#bearer-token-jwt-claim-verification

QS-OIDC-005 - OIDC session token encryption disabled

  • Severity: MEDIUM
  • Detects: An active default or named web-app/hybrid tenant sets quarkus.oidc[.<tenant>].token-state-manager.encryption-required=false (Quarkus default true). Service tenants and disabled tenants are excluded; dynamic tenants are not evaluated.
  • Why it matters: The default token state manager then stores the retained ID, access, and refresh tokens in the session cookie without encryption. When encryption is required, Quarkus also encrypts tokens before handing them to a custom (database or Redis) token state manager; disabling it hands them over in plain text. Independent encryption by a custom manager is not observed. The cookie stays HttpOnly by default, so this is defense in depth for bearer artifacts, not a replacement for cookie protection.
  • Recommendation: Remove the override so token-state-manager.encryption-required keeps its true default.
  • Learn more: https://quarkus.io/version/3.33/guides/security-oidc-code-flow-authentication#token-state-manager

Management

QS-MGMT-001 - Management interface on a non-loopback host

  • Severity: LOW
  • Detects: The separate management interface is enabled in the observed runtime and its resolved quarkus.management.host is non-loopback. Binding is not proof of remote reachability or anonymous access. Current runtime evidence is separate from the bounded prod declarations reviewed by QS-MGMT-003. Launch mode must not be inferred from a profile name: RUN and NORMAL can both default to prod, while BootUI remains excluded from NORMAL.
  • Recommendation: Bind the host to 127.0.0.1, or protect the management endpoints.
  • Learn more: https://quarkus.io/version/3.33/guides/management-interface-reference#configure-the-host-port-and-scheme

Retired: QS-MGMT-002. Sharing an application namespace does not itself create endpoints, remove authorization or prove wider exposure. Paths and protection need endpoint-specific evidence. The ID remains reserved.

QS-MGMT-003 - Management interface has no explicit prod-scoped host binding

  • Severity: INFO
  • Detects: Supported local prod declarations enable management without either a base quarkus.management.host or %prod.quarkus.management.host declaration. Explicit prod enabled=false wins over base true; an inactive production declaration does not trigger the rule. Unresolved or unsupported source/profile evidence remains incomplete.
  • Why it matters: The prod-profile default is all interfaces, unlike the dev/test loopback default. This reviews a possible deployment configuration, not an observed production listener. It can differ from the runtime state reviewed by QS-MGMT-001 and does not establish launch mode, firewall policy, or endpoint authorization.
  • Recommendation: Explicitly pin %prod.quarkus.management.host to 127.0.0.1, or to the intended bind address.
  • Learn more: https://quarkus.io/version/3.33/guides/management-interface-reference#configure-the-host-port-and-scheme

Proxy

QS-PROXY-001 - Forwarded headers trusted from any address

  • Severity: LOW
  • Detects: Supported local prod declarations (%prod. first, then the base key) enable quarkus.http.proxy.proxy-address-forwarding with forwarded-header processing — allow-forwarded=true, or allow-x-forwarded, which defaults to !allow-forwarded exactly as in Quarkus's ForwardingProxyOptions — and quarkus.http.proxy.trusted-proxies is absent, empty, or contains a universal range (0.0.0.0/0, ::/0). An effective runtime trusted-proxies value (for example from the environment) also counts as a restriction. Unresolved declarations remain incomplete.
  • Why it matters: Without trusted proxies Quarkus accepts Forwarded/X-Forwarded-* from every peer, so a client that reaches the listener directly, or through a proxy that does not strip those headers, can spoof the client address and scheme (and the host when enable-forwarded-host is set). The Quarkus HTTP reference warns that activating forwarding "leaves the server exposed to several security issues (i.e. information spoofing)". Network isolation and proxy header stripping are not observable, hence LOW.
  • Recommendation: Set quarkus.http.proxy.trusted-proxies to the proxy addresses or CIDR ranges, and make the proxy strip client-supplied forwarded headers.
  • Learn more: https://quarkus.io/version/3.33/guides/http-reference#reverse-proxy

Config hygiene

QS-CFG-001 - Possible secret in configuration

  • Severity: MEDIUM
  • Detects: A config key's terminal segment identifies a password, secret, API key, private key, token, access/refresh token, or symmetric key (encryption-key, signature-key, signing-key, secretkey) set to a literal value (not an externalized ${...} reference). Inline private keys whose terminal segment is the generic key are matched by exact name only: smallrye.jwt.sign.key, smallrye.jwt.decrypt.key, and quarkus.oidc[.<tenant>].credentials.jwt.key. Public keys (mp.jwt.verify.publickey) and *.location/*-file references are excluded. Scans application and %prod configuration, including the quarkus.* namespace — e.g. quarkus.datasource.password, quarkus.oidc.credentials.secret, quarkus.mail.password are all in scope, alongside application-owned keys. A committed quarkus.http.auth.session.encryption-key (form-auth cookie encryption), quarkus.rest-csrf.token-signature-key (CSRF token HMAC) or smallrye.jwt.verify.secretkey (HMAC JWT verification) lets anyone with the source forge sessions, CSRF tokens or JWTs.
  • Scope: Only recognized local application properties/YAML source provenance is inspected for literal credentials. Environment-variable, system-property, config-tree, remote, and custom sources are not enumerated or read to infer committed secrets. ${...} expressions, %dev/%test values, BootUI internals, and metadata keys such as quarkus.oidc.token.issuer are excluded. Bounded safe labels enter report samples; values and application exception text never do. This is local source hygiene, not proof of credential exposure, current use, or production deployment.
  • Recommendation: Move committed literals to a vault/env var.
  • Learn more: https://quarkus.io/version/3.33/guides/credentials-provider

Session

QS-SESSION-001 - Form-auth session cookie not HttpOnly

  • Severity: MEDIUM
  • Detects: quarkus.http.auth.form.http-only-cookie defaults to false in Quarkus 3.33 (FormAuthConfig) — unlike most frameworks — so the form-auth session cookie is readable from JavaScript; any XSS flaw can then steal the session. Exploitation needs a separate XSS flaw, so the rule is MEDIUM, matching the Spring SEC-SESSION-003 control.
  • Recommendation: Set quarkus.http.auth.form.http-only-cookie=true.
  • Learn more: https://quarkus.io/version/3.33/guides/security-authentication-mechanisms#form-auth

QS-SESSION-002 - Form-auth session cookie SameSite=None

  • Severity: LOW
  • Detects: Active form authentication selects quarkus.http.auth.form.cookie-same-site=none, allowing cross-site cookie use. This can be an intentional compatibility choice, not an independent proof of missing CSRF defenses.
  • Recommendation: Use Secure with SameSite=None and verify independent CSRF defenses. Prefer Strict/Lax when compatible with the required browser flows.
  • Learn more: https://quarkus.io/version/3.33/guides/security-authentication-mechanisms#form-auth

QS-SESSION-003 - Long form-auth idle timeout

  • Severity: LOW
  • Detects: Active form authentication has a supported parsed quarkus.http.auth.form.timeout of at least eight hours. This is an idle timeout, not an absolute session lifespan: active sessions can renew. Eight hours is a heuristic review threshold; invalid or unsupported durations never become a passing default.
  • Recommendation: Lower the timeout (the Quarkus default is 30 minutes) and pair it with new-cookie-interval.
  • Learn more: https://quarkus.io/version/3.33/guides/security-authentication-mechanisms#form-auth

gRPC

QS-GRPC-001 - gRPC server reflection enabled in the prod profile

  • Severity: MEDIUM
  • Detects: Quarkus-specific. The gRPC capability and a declared server service are present, and supported local prod declarations enable quarkus.grpc.server.enable-reflection-service. Explicit %prod=false overrides base true; dev-only settings and client-only capability do not establish this finding.
  • Why it matters: Reflection makes service/schema metadata discoverable to permitted callers. This is a production configuration review, not proof of public access or a running production server.
  • Recommendation: Remove the %prod override; keep reflection enabled only in %dev/%test.
  • Learn more: https://quarkus.io/version/3.33/guides/grpc-service-implementation#reflection-service

GraphQL

QS-GRAPHQL-001 - GraphQL schema introspection enabled

  • Severity: LOW
  • Detects: Quarkus-specific. The GraphQL capability is present and supported local prod declarations leave quarkus.smallrye-graphql.field-visibility without no-introspection, honoring the prod override before the base declaration. This reviews schema-disclosure configuration, not the access policy of a running deployment. quarkus.smallrye-graphql.introspection-enabled does not exist and is not evaluated.
  • Why it matters: Often intentional for public APIs, but worth a deliberate decision.
  • Recommendation: Add no-introspection to quarkus.smallrye-graphql.field-visibility in %prod unless the schema is meant to be publicly discoverable.
  • Learn more: https://quarkus.io/version/3.33/guides/smallrye-graphql

Messaging

QS-MSG-001 - Messaging credentials configured without an encrypted protocol

  • Severity: HIGH
  • Detects: Quarkus-specific. An enabled channel explicitly using the Kafka connector has declared SASL password or JAAS credentials with effective PLAINTEXT or SASL_PLAINTEXT. Protocol resolution follows channel, connector (mp.messaging.connector.smallrye-kafka), then global (kafka) settings. Global credentials can apply to a channel with an insecure override; a global bucket is not independently treated as a running channel. Disabled/non-Kafka channels are excluded, and implicit connectors or custom CDI configuration maps remain unknown without invoking producers. Report samples use bounded, value-free channel labels.
  • Why it matters: SASL_PLAINTEXT lacks transport encryption for the selected authentication exchange. PLAINTEXT does not send SASL credentials; alongside declared credentials it indicates an inconsistent, unencrypted setup. The rule does not claim that every SASL mechanism transmits a raw password.
  • Recommendation: Set security.protocol=SASL_SSL (or SSL) for each affected channel (or globally via kafka.security.protocol).
  • Learn more: https://quarkus.io/version/3.33/guides/kafka#tls-configuration

Audit sources and limits

The implementation review is pinned to 3.33.3.1:

  • Permission mapping configuration and path matching policy establish exact paths, longest match, method mismatch denial and shared policy behavior.

  • CORSFilter establishes reflected origins, regex matching and the conditional credentials default.

  • OidcProvider, tenant configuration and known provider presets define validation sentinels and provider-specific defaults.

  • Client credential configuration supports providers and JWT client authentication; missing a literal secret does not establish a public client.

  • Header configuration and Kafka configuration reference define scope and inheritance that raw property-presence checks cannot replace.

  • LaunchMode distinguishes RUN from NORMAL, although both default to the prod profile. Profile names are not proof of launch mode or network exposure; BootUI's existing NORMAL exclusion remains unchanged.

  • Fetch, CSP3, Referrer Policy, OWASP headers, JWT BCP and OAuth BCP provide the browser/token context.

  • FormAuthConfig confirms the http-only-cookie=false and cookie-same-site=strict defaults; ProxyConfig and ForwardingProxyOptions establish that an absent trusted-proxies list trusts every peer (3.33 has no trusted-proxy[n].subject-dn); ServerSslConfig and HttpServerOptionsUtils define the protocol defaults and registry precedence.

  • Learn-more links point to the version-pinned Quarkus 3.33 guides, whose anchors were verified; the unversioned guides already document later releases.

Considered and not added: a SmallRye JWT smallrye.jwt.verify.relax-key-validation rule. Its documented default is false, but SmallRye JWT 4.6.3 (the version Quarkus 3.33 ships) declares defaultValue = "true" in JWTAuthContextInfoProvider, so the relaxation is the library default for every JWT application and is inert unless an issuer actually signs with a short RSA key, which configuration cannot observe.

Custom policies, dynamic tenants, credentials providers, external sources and delivered headers are not evaluated by executing application code. Unsupported evidence remains incomplete; no active testing or endpoint mutation is performed. Retired IDs are permanently reserved.

Prev
Quarkus