Ortus Solutions today announces CBSecurity 3.9, a major step forward for securing ColdBox applications. This release adds 12 ready-made security middleware that you attach directly to routes and route groups, with no firewall rules required.
Security in most applications lives far away from the thing it protects. A rule list in one file, a handful of if checks in another, and a hope that nobody forgot a route. CBSecurity 3.9 flips that model. You declare protection where the route is declared, and the framework enforces it before your handler ever runs.
box install cbsecurity
🛡️ A new paradigm: security that lives on the route
CBSecurity has always given ColdBox teams a firewall with rules, handler annotations and JWT support. Version 3.9 adds a third, route-scoped approach built on ColdBox route middleware (route().middleware()).
Read a route and you know exactly how it is protected:
route( "/account" ).middleware( "Authenticated@cbsecurity" ).to( "account.index" )
route( "/admin" )
.middleware( "Authorized@cbsecurity" )
.meta( { permissions : "ADMIN" } )
.to( "admin.index" )
Parameters travel in the route meta(), so permissions, roles and the matching mode (any, all or none) sit right next to the route they guard. Protect a whole section of your application once by applying middleware and shared meta to a group:
group( { pattern : "/admin", middleware : [ "Authorized@cbsecurity" ], meta : { roles : "admin", mode : "all" } }, () => {
route( "/users" ).to( "admin.users.index" )
route( "/audit" ).to( "admin.audit.index" )
} )
Denied requests are not a second-class path. Authentication and authorization middleware send them through the same invalid access flow your firewall already uses: redirects, event overrides, blocks, module overrides, interception points and logging. Your existing security behavior stays consistent no matter which approach protects the route.
🔐 The 12 middleware
Identity and access
| Middleware | What it does |
|---|---|
Authenticated@cbsecurity | The user must be logged in |
Authorized@cbsecurity | Logged in and satisfying the permissions, roles and mode declared in the route meta() |
JwtAuth@cbsecurity | Authorization through the JWT validator |
BasicAuth@cbsecurity | Authorization through the Basic Auth validator |
Abuse protection
| Middleware | What it does | Route meta() |
|---|---|---|
Throttle@cbsecurity | Rate limiting with named or inline limiters on any CacheBox cache. Answers with 429 and a Retry-After header | throttle |
ApiKey@cbsecurity | Reads the x-api-key header, then the apiKey request key. Both are configurable. Validate against keys or a validator service | apiKeys, apiKeyHeader, apiKeyParam |
Honeypot@cbsecurity | A hidden trap field that catches bots. Responds with a silent 200 or a 422 | honeypotField, honeypotSilent |
Network and transport
| Middleware | What it does | Route meta() |
|---|---|---|
AllowedIPs@cbsecurity | Only let listed IPv4, IPv6 or CIDR ranges through | allowedIps |
DenyIPs@cbsecurity | Block listed IPv4, IPv6 or CIDR ranges | denyIps |
EnsureHttps@cbsecurity | 301 redirect for GET and HEAD, 403 for every other method | redirectToHttps |
Request integrity
| Middleware | What it does | Route meta() |
|---|---|---|
VerifyCsrf@cbsecurity | Validates the cbcsrf token on unsafe HTTP methods | csrfKey |
Signed@cbsecurity | Only accepts valid, unexpired signed URLs | none |
The abuse protection middleware answer denied requests directly with a JSON error and the right status code, which makes them a natural fit for APIs. Defaults live in the new middleware and signedUrls module settings, and every value can be overridden per route.
🚦 Stop abuse before it reaches your code
Brute force logins, credential stuffing, scraping and bot sign-ups all share one trait: they hammer an endpoint. Throttle@cbsecurity puts a rate limiter in front of any route, backed by any CacheBox cache (the default cache unless you say otherwise). When a client goes over the limit, they get a 429 with a Retry-After header, and your handler never runs.
route( "/api/login" ).middleware( "Throttle@cbsecurity" ).to( "api.auth.login" )
Need the same limiter outside the router? The RateLimiter@cbsecurity model is a cache-backed fixed window limiter you can use anywhere in your application.
Pair it with Honeypot@cbsecurity for forms. A hidden field that real users never see and bots love to fill in is a cheap, effective tripwire:
route( "/contact" )
.middleware( "Honeypot@cbsecurity" )
.meta( { honeypotField : "website", honeypotSilent : true } )
.to( "contact.send" )
And for machine-to-machine traffic, ApiKey@cbsecurity checks the x-api-key header (or the apiKey request key) against a list of keys or a validator service of your own.
🌐 Control who can reach what
AllowedIPs@cbsecurity and DenyIPs@cbsecurity filter by IPv4, IPv6 and CIDR range. Lock an admin area to your office network, or block a hostile range in one line:
route( "/internal/metrics" )
.middleware( "AllowedIPs@cbsecurity" )
.meta( { allowedIps : "10.0.0.0/8" } )
.to( "internal.metrics" )
Behind a load balancer? Client IP detection is a classic spoofing target. CBSecurity honors X-Forwarded-For only from the proxies you list in trustedProxies, so an attacker cannot forge their way past your allow list with a header.
EnsureHttps@cbsecurity keeps plaintext traffic off sensitive routes. GET and HEAD requests are redirected with a 301, and every other method is rejected with a 403, so a form post never travels over an insecure connection.
✍️ Signed URLs: tamper-proof, expiring links
Password resets, email verifications, unsubscribe links, private downloads. Any URL that grants access without a login needs to be impossible to forge or guess.
Signed URLs solve that. UrlSigner@cbsecurity signs the path and query string with HMAC-SHA256 and can add an expiration time. Change one character of the URL and the signature no longer matches. Wait too long and the link is dead.
Protect the route with one middleware:
route( "/unsubscribe/:id" ).middleware( "Signed@cbsecurity" ).to( "newsletter.unsubscribe" )
Then generate links with the new signedRoute() and signedUrl() helpers, and check a signature yourself anywhere with hasValidSignature(). If you forget to configure the signing secret, CBSecurity throws a cbsecurity.SigningSecretMissing exception instead of quietly signing with nothing.
🧯 Built to fail loudly, not open
Security configuration mistakes are dangerous when they fail silently. When an IP list or a set of API keys is missing, the middleware throws cbsecurity.MiddlewareMisconfigured so you find the problem in development, not after an incident.
🧩 Extend it your way
Need a rule that is unique to your business? Create custom middleware by extending cbsecurity.models.middleware.Guard. To support your own integrations, the Security interceptor now exposes two public methods, validateAccess() and processInvalidAccess(). They are the same methods the built-in middleware use, so your custom checks get the same denial handling as everything else.
✅ Testable from day one
Protected routes should be tested like any other code. With ColdBox 8.3+, route middleware runs inside integration tests (execute(), get(), post() and friends), and group-level meta is supported, so a middleware-protected route never looks unprotected in your specs. This release itself ships with over 100 new specs covering the middleware.
🐞 Also fixed: cbcsrf settings no longer get overwritten
Settings you configured on the cbcsrf module were being overwritten by the cbsecurity csrf defaults, even if you never set cbsecurity.csrf. That is a nasty surprise for a security setting. Now only the keys you explicitly set in cbsecurity.csrf are applied, and they win over the cbcsrf settings. The Which Settings Win section of the docs explains the details.
Handler and action annotation security now share processInvalidAccess() with route middleware. Behavior is unchanged.
📦 Requirements and upgrading
- Route middleware requires ColdBox 8.2+
- Group-level
metaand route middleware in integration tests require ColdBox 8.3+
Existing firewall rules and handler annotations keep working exactly as before. Adopt middleware route by route, whenever it makes sense for your application.
box update cbsecurity
🚀 Get started
Dive into the documentation for each middleware:
Resources
- Documentation: coldbox-security.ortusbooks.com
- Source: github.com/coldbox-modules/cbsecurity
- ForgeBox: forgebox.io/view/cbsecurity
- Community: community.ortussolutions.com
- Professional support and consulting: ortussolutions.com/services
Stop scattering security checks across your codebase. Declare it on the route and let CBSecurity enforce it. 🔒
Add Your Comment