boxlang-code-reviewer — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited boxlang-code-reviewer (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
This skill provides a structured checklist and framework for reviewing BoxLang code. Apply these checks systematically when reviewing PRs, auditing existing code, or self-reviewing before committing.
When reviewing BoxLang code, evaluate these categories in order of priority:
// RED FLAG — string interpolation in SQL
queryExecute( "SELECT * FROM users WHERE id = #url.id#" )
// REQUIRED FIX — always parameterize
queryExecute(
"SELECT * FROM users WHERE id = :id",
{ id: { value: url.id, cfsqltype: "cf_sql_integer" } }
)Review question: Is every SQL value passed via queryParam / :name binding?
// RED FLAG — raw user input rendered in HTML
<bx:output>#form.comment#</bx:output>
// REQUIRED FIX — encode for context
<bx:output>#encodeForHTML( form.comment )#</bx:output>Review question: Is every user-supplied value encoded with the appropriate encodeFor*() function before output?
Review question: Does any file read/write accept a user-supplied path? If yes, is it validated with canonical path comparison?
RED FLAG: API keys, passwords, tokens hardcoded in .bx, .bxs, .bxm, or boxlang.json.
REQUIRED FIX: Use ${env.SECRET_NAME} in config, and access via server.system.environment.SECRET_NAME in code.
Review question: Are remote functions authenticated before executing? Are all arguments validated before use?
// RED FLAG — missing var keyword (bleeds into variables scope)
function process() {
result = loadData() // BAD
return result
}
// CORRECT
function process() {
var result = loadData()
return result
}// RED FLAG — potential null pointer
var name = user.profile.displayName // throws if profile is null
// CORRECT — null-safe navigation
var name = user?.profile?.displayName ?: "Anonymous"// RED FLAG — catch-all silently swallows bugs
try {
doWork()
} catch ( any e ) {
logError( e ) // continues execution after unexpected error
}
// CORRECT — re-throw unknown errors
try {
doWork()
} catch ( "ExpectedError" e ) {
handleExpected( e )
} catch ( any e ) {
logError( e )
rethrow // let unexpected errors propagate
}structKeyExists()?// SLOWER — scope chain walked every iteration
for ( var i = 1; i <= items.len(); i++ ) {
process( items[ i ] )
}
// FASTER — len() called once
var count = items.len()
for ( var i = 1; i <= count; i++ ) {
process( items[ i ] )
}// RED FLAG — query inside a loop (N+1 problem)
for ( var order in orders ) {
order.customer = queryExecute( "SELECT * FROM customers WHERE id = #order.customerId#" )
}
// CORRECT — fetch all in one query with JOIN or batch lookup
var enriched = queryExecute(
"SELECT o.*, c.name as customerName
FROM orders o
JOIN customers c ON c.id = o.customerId
WHERE o.status = :status",
{ status: { value: "active", cfsqltype: "cf_sql_varchar" } }
)// RED FLAG — unguarded write to application scope (race condition)
application.settings = loadSettings()
// CORRECT — use locking
bx:lock name="app-settings-lock" type="exclusive" timeout="5" {
application.settings = loadSettings()
}| Check | Bad Example | Good Example |
|---|---|---|
| Variables clear | var x = getData() | var userProfile = getProfile( id ) |
| Functions descriptive | function do() | function processPayment() |
| Boolean names readable | var flag = check() | var isEligible = checkEligibility() |
| Magic numbers named | if ( status == 3 ) | if ( status == STATUS_SUSPENDED ) |
Flag functions exceeding ~50 lines — they likely need splitting. Each function should do one thing clearly.
// RED FLAG — no argument metadata
function getUser( id, options ) { ... }
// REQUIRED — typed, required annotations
function getUser( required numeric id, struct options = {} ) { ... }Flag:
BoxLang docs state: do not use semicolons except where required.
// BAD — unnecessary semicolons
var name = "BoxLang";
return result;
// CORRECT — no semicolons needed
var name = "BoxLang"
return result
// OK — semicolons required here
property name="userId" type="numeric";// Correct — lambda for pure transforms (no outer scope)
var doubled = numbers.map( ( n ) -> n * 2 )
// Correct — closure for outer scope access or BIF calls
var filtered = numbers.filter( ( n ) => n > minValue )
var upper = words.map( ( w ) => uCase( w ) )// Acceptable but verbose
var user = structNew()
user.name = "Alice"
// Preferred — literal syntax
var user = { name: "Alice", email: "[email protected]" }When writing review feedback, use this structure:
## Critical (must fix before merge)
- [ ] **[Security/SQL Injection]** Line 42: `url.id` is interpolated directly into SQL.
Fix: use `:id` binding with `cfsqltype: "cf_sql_integer"`.
- [ ] **[Security/XSS]** Line 87: `form.description` rendered without encoding.
Fix: `encodeForHTML( form.description )`.
## Major (should fix)
- [ ] **[Correctness/Null Safety]** Line 23: `user.address.city` — `address` may be null.
Fix: use `user?.address?.city ?: "Unknown"`.
- [ ] **[Performance/N+1]** Lines 55–60: query inside loop will execute N queries.
Fix: use JOIN or batch lookup.
## Minor (consider fixing)
- [ ] **[Style/Naming]** `var x` on line 31 — rename to clarify purpose.
- [ ] **[Docs]** `processOrder()` lacks `@param` and `@return` documentation.
## Positive Feedback
- Good use of parameterized queries in `getUserById()`.
- Error handling in `chargePayment()` correctly re-throws unknown exceptions.Run these before manual review:
# Format check (BoxLang code style)
box run-script format:check
# Run test suite
./run --reporter=text
# Check for outdated modules (dependency audit)
box outdated
# Security scan (if using CommandBox security module)
box security:scan~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.