boxlang-security
BoxLang Security
Overview
BoxLang inherits both the power and the historical attack surface of ColdFusion/CFML and the JVM. This skill documents security patterns and runtime controls to help build secure applications from the ground up.
Runtime Security Configuration (boxlang.json)
"security": {
// Regex patterns — prevent dangerous Java class access
"disallowedImports": [
"java\\.lang\\.(ProcessBuilder|Runtime)",
"java\\.io\\.(FileWriter|PrintWriter)",
"java\\.lang\\.reflect\\."
],
// BIFs that should be disabled in production web apps
"disallowedBifs": [
"createObject",
"systemExecute",
"getSystemInfo"
],
// Components that should be disabled in production
"disallowedComponents": [
"execute"
],
// Prevent system properties from leaking into server scope
"populateServerSystemScope": false,
// Explicit upload whitelist (overrides disallowed list)
"allowedFileOperationExtensions": [ "jpg", "png", "pdf", "docx" ],
// Dangerous executable extensions blocked on file upload and copy/move
"disallowedFileOperationExtensions": [
"exe", "bat", "sh", "bx", "bxm", "bxs", "php", "jsp", "jar", "dll"
]
}
Injection Prevention
SQL Injection
NEVER build SQL with string concatenation. Always use QueryParam:
// BAD — SQL injection vulnerability
var result = queryExecute(
"SELECT * FROM users WHERE email = '#email#'"
)
// GOOD — parameterized query (prevents SQL injection)
var result = queryExecute(
"SELECT * FROM users WHERE email = :email",
{ email: { value: arguments.email, cfsqltype: "cf_sql_varchar" } }
)
// GOOD — struct shorthand
var result = queryExecute(
"SELECT * FROM users WHERE id = :id AND status = :status",
{
id: { value: arguments.id, cfsqltype: "cf_sql_integer" },
status: { value: arguments.status, cfsqltype: "cf_sql_varchar" }
}
)
Cross-Site Scripting (XSS)
Encode all user-supplied output in HTML context:
// BAD — raw user input rendered in HTML
<bx:output>#userComment#</bx:output>
// GOOD — HTML encode before output
<bx:output>#encodeForHTML( userComment )#</bx:output>
// For HTML attribute context
<input value="#encodeForHTMLAttribute( userInput )#">
// For JavaScript context
<script>var name = "#encodeForJavaScript( userName )#";</script>
// For URL context
<a href="/search?q=#encodeForURL( searchTerm )#">Search</a>
Use the right encoding function per context:
| Context | Function |
|---|---|
| HTML content | encodeForHTML() |
| HTML attributes | encodeForHTMLAttribute() |
| JavaScript strings | encodeForJavaScript() |
| URL parameters | encodeForURL() |
| CSS values | encodeForCSS() |
Cross-Site Request Forgery (CSRF)
// Generate a token per session/form
var token = generateSecureToken()
session.csrfToken = token
// In the form template
<input type="hidden" name="csrfToken" value="#session.csrfToken#">
// Validate on POST
function onRequestStart( required string targetPage ) {
if ( cgi.request_method == "POST" ) {
if ( !structKeyExists( form, "csrfToken" ) ||
form.csrfToken != session.csrfToken ) {
throw( type="SecurityException", message="CSRF validation failed" )
}
}
return true
}
File Upload Security
Always validate file uploads before processing:
function handleUpload( required string fieldName ) {
// Restrict to explicit allowed types and extensions
var upload = fileUpload(
destination = getTempDirectory(),
filefield = arguments.fieldName,
accept = "image/jpeg,image/png,application/pdf",
nameconflict = "makeunique"
)
// Validate extension explicitly regardless of MIME type
var allowedExtensions = [ "jpg", "jpeg", "png", "pdf" ]
if ( !allowedExtensions.contains( lCase( upload.serverFileExt ) ) ) {
fileDelete( upload.serverDirectory & "/" & upload.serverFile )
throw( type="SecurityException", message="Disallowed file type" )
}
// Validate file size
var maxSizeBytes = 5 * 1024 * 1024 // 5 MB
if ( upload.fileSize > maxSizeBytes ) {
fileDelete( upload.serverDirectory & "/" & upload.serverFile )
throw( type="SecurityException", message="File too large" )
}
// Store outside the webroot, serve via handler — never serve raw uploads
var safePath = expandPath( "/private/uploads/" ) & createUUID() & "." & upload.serverFileExt
fileMove( upload.serverDirectory & "/" & upload.serverFile, safePath )
return safePath
}
Secrets Management
Never hardcode secrets. Use environment variables via the BoxLang config:
// boxlang.json — uses env var substitution
"datasources": {
"mainDB": {
"driver": "postgresql",
"host": "${env.DB_HOST:localhost}",
"username": "${env.DB_USERNAME:app}",
"password": "${env.DB_PASSWORD}" // No default — fail fast if missing
}
}
In code, access via environment (not hardcoded):
// GOOD — read from environment
var apiKey = server.system.environment.PAYMENT_API_KEY ?: ""
var jwtSecret = server.system.environment.JWT_SECRET ?: ""
if ( apiKey.isEmpty() ) {
throw( type="ConfigException", message="PAYMENT_API_KEY is not configured" )
}
Authentication Patterns
Password Hashing
// GOOD — bcrypt-style hash (use bx-bcrypt module or GeneratePBKDFKey)
var salt = generateSecureToken( 32 )
var hashed = hash( arguments.password & salt, "SHA-512" )
// Even better — use a dedicated BCrypt module
// install bx-bcrypt
var bcrypt = new BCrypt()
var hashed = bcrypt.hashpw( plainPassword, bcrypt.gensalt() )
// Verify
var isMatch = bcrypt.checkpw( loginPassword, storedHash )
JWT / Token Validation
// Always validate before trusting any token data
function validateToken( required string token ) {
try {
// Use the bx-jwt module
var claims = jwtService.decode( arguments.token )
// Validate expiry
if ( claims.exp < epochSecond() ) {
throw( type="AuthException", message="Token expired" )
}
return claims
} catch ( "JWT" e ) {
throw( type="AuthException", message="Invalid token" )
}
}
Session Security
Configure session settings in Application.bx:
class {
this.name = "MyApp"
this.sessionManagement = true
this.sessionTimeout = createTimeSpan( 0, 2, 0, 0 ) // 2 hours
// Rotate session ID after login (session fixation prevention)
function onLogin( required struct user ) {
var oldData = duplicate( session )
sessionRotate() // BoxLang BIF to regenerate session ID
structDelete( session, "ALL" )
structAppend( session, oldData )
session.userId = user.id
session.isLoggedIn = true
}
}
Path Traversal Prevention
Validate all user-supplied file paths:
function readFile( required string filename ) {
var safeBase = expandPath( "/app/uploads/" )
var fullPath = safeBase & arguments.filename
var cleanPath = createObject( "java", "java.io.File" ).init( fullPath ).getCanonicalPath()
// Ensure the resolved path is within the allowed directory
if ( !cleanPath.startsWith( safeBase ) ) {
throw( type="SecurityException", message="Path traversal detected" )
}
return fileRead( cleanPath )
}
Input Validation
// Validate and sanitize input at the boundary
function processContactForm( required struct form ) {
var errors = []
// Length limits
if ( form.name.len() > 100 ) errors.append( "Name too long" )
// Email format
if ( !isValid( "email", form.email ) ) errors.append( "Invalid email" )
// Numeric ranges
if ( !isNumeric( form.age ) || form.age < 0 || form.age > 150 ) {
errors.append( "Invalid age" )
}
// Allowlist for enum-style fields
var validTopics = [ "support", "sales", "billing" ]
if ( !validTopics.contains( lCase( form.topic ) ) ) {
errors.append( "Invalid topic" )
}
if ( !errors.isEmpty() ) {
throw( type="ValidationException", message=errors.toList( ", " ) )
}
}
Remote Function Exposure (Web Services)
When exposing class functions as web-accessible endpoints, explicitly control access:
class {
remote struct function getUser( required numeric id ) returnformat="json" {
// Always authenticate remote calls
if ( !isAuthenticated() ) {
httpSetResponseStatus( 401 )
return { error: "Unauthorized" }
}
// Validate and sanitize the id parameter
if ( !isValid( "integer", arguments.id ) || arguments.id < 1 ) {
httpSetResponseStatus( 400 )
return { error: "Invalid user ID" }
}
return userService.getById( arguments.id )
}
}
Production Hardening Checklist
- Set
populateServerSystemScope: falseunless needed - Configure
disallowedBifsto remove dangerous BIFs (systemExecute,createObjectif not needed) - Configure
disallowedImportsfor Java class access restrictions - Set
disallowedComponents: ["execute"]to prevent OS command execution - All secrets via environment variables — none in code or committed config
- All SQL via parameterized queries (
queryParam) - All user output HTML-encoded with context-appropriate encoding functions
- CSRF tokens on all state-changing forms
- File uploads stored outside webroot, validated by extension and size
- Session timeouts configured; session rotated on privilege elevation
- Enable
trustedCache: trueandclassResolverCache: truein production - HTTPS enforced at the reverse proxy or container level
- Dependency modules kept up to date (check
box outdated)
More from ortus-boxlang/skills
boxlang-functional-programming
Use this skill when working with BoxLang lambdas, closures, arrow functions, higher-order functions, functional array/struct pipelines (map, filter, reduce, flatMap, groupBy, etc.), destructuring, or spread syntax.
10boxlang-code-reviewer
Use this skill when reviewing BoxLang code for quality, correctness, security vulnerabilities, performance issues, style violations, or when providing structured code review feedback following BoxLang best practices and security guidelines.
9boxlang-best-practices
Use this skill when writing, reviewing, or improving BoxLang code to ensure it follows community best practices for naming, structure, scoping, error handling, performance, and maintainability.
9boxlang-classes-and-oop
Use this skill when writing BoxLang classes, components, interfaces, inheritance hierarchies, annotations, properties, constructors, or applying object-oriented design patterns in BoxLang.
9boxlang-web-development
Use this skill when building BoxLang web applications: Application.bx lifecycle, request/response handling, sessions, forms, REST APIs, HTTP clients, routing, CSRF protection, Server-Sent Events, or configuring CommandBox/MiniServer.
8boxlang-configuration
Use this skill when configuring BoxLang runtime settings via boxlang.json, setting environment variables for config overrides, configuring datasources, caches, executors, modules, logging, security, or schedulers — or when helping someone understand the BoxLang configuration system.
8