Out Of Bounds Read in Adonisjs
How Out Of Bounds Read Manifests in Adonisjs
Out Of Bounds Read (OOB Read) vulnerabilities in Adonisjs applications typically occur when code attempts to access array or string indices beyond their actual length. In Adonisjs, this often manifests through improper handling of request parameters, database query results, or user-provided data.
A common pattern in Adonisjs controllers involves accessing array elements without validating their existence. For example:
class UserController {
async show({ params }) {
const user = await User.find(params.id)
// OOB Read risk: accessing properties without checking if user exists
return {
name: user.name,
email: user.email,
role: user.role // If user is null, this throws TypeError
}
}
}Another frequent scenario involves parsing request bodies where Adonisjs's automatic JSON parsing can lead to OOB Read if the input structure is unexpected:
class ProductController {
async create({ request }) {
const data = request.post()
// OOB Read risk: assuming specific array structure
const tags = data.tags || []
return {
name: data.name,
tag1: tags[0], // If tags is undefined or empty, this is undefined
tag2: tags[1], // Same issue
tag3: tags[2] // Same issue
}
}
}Database query results can also trigger OOB Read vulnerabilities when Adonisjs's Lucid ORM returns unexpected results:
class ReportController {
async generate({ params }) {
const sales = await Sale.query()
.where('product_id', params.productId)
.orderBy('created_at', 'desc')
.limit(10)
// OOB Read risk: assuming at least one result exists
const latestSale = sales[0] // If sales is empty, this is undefined
return {
latestPrice: latestSale.price, // TypeError if latestSale is undefined
totalSales: sales.length
}
}
}Adonisjs's middleware system can propagate OOB Read issues when data flows through multiple layers without proper validation:
class AuthMiddleware {
async handle({ request, auth }, next) {
const token = request.header('authorization')?.replace('Bearer ', '')
const payload = jwt.verify(token, process.env.JWT_SECRET)
// OOB Read risk: assuming payload has specific structure
request.user = {
id: payload.sub,
email: payload.email, // If payload doesn't have email, this is undefined
permissions: payload.permissions || []
}
await next()
}
}Adonisjs-Specific Detection
Detecting Out Of Bounds Read vulnerabilities in Adonisjs requires both static analysis and runtime scanning. The framework's structure creates specific patterns that make detection more straightforward than in other Node.js frameworks.
Static analysis should focus on controller methods and middleware that access array indices or object properties without null checks. Look for patterns like:
const result = await Model.find(id)
return result.property // Missing null checkmiddleBrick's API security scanner includes specific checks for Adonisjs applications. When scanning an Adonisjs endpoint, middleBrick tests for OOB Read vulnerabilities by:
- Sending malformed request bodies with unexpected array structures
- Testing database query responses with empty result sets
- Verifying authentication middleware handles missing claims properly
- Checking for proper error handling when accessing undefined properties
The scanner's black-box approach is particularly effective for Adonisjs because it tests the actual runtime behavior without needing access to source code. For example, when scanning a user profile endpoint, middleBrick will:
POST /api/users/profile
Content-Type: application/json
{
"userIds": []
}
// Tests if the endpoint handles empty arrays properly
// Checks if it crashes when accessing [0] on empty arraysmiddleBrick's OpenAPI analysis also helps detect OOB Read vulnerabilities by cross-referencing your API specification with actual runtime behavior. If your spec defines a response object with required fields, but the implementation doesn't validate their presence, middleBrick will flag this discrepancy.
Integration with Adonisjs's validation system is another detection vector. The framework's validate method can prevent many OOB Read issues, but only if properly configured:
const { validate } = use('Validator')
async show({ request }) {
const data = await validate(request.post(), {
tags: 'array|min:1', // Ensures tags exists and has at least one element
name: 'required|string'
})
if (data.fails()) {
return response.badRequest(data.messages())
}
// Now it's safe to access tags[0]
return {
name: data.name,
firstTag: data.tags[0]
}
}Adonisjs-Specific Remediation
Remediating Out Of Bounds Read vulnerabilities in Adonisjs requires a combination of defensive programming practices and leveraging the framework's built-in features. The key is to always validate data before accessing it.
The most effective approach is using Adonisjs's schema-based validation system:
const { schema } = use('Validator')
async create({ request }) {
const newUserSchema = schema.create({
name: schema.string({}, [rules.required()]),
email: schema.string({}, [
rules.required(),
rules.email()
]),
tags: schema.array.optional([
rules.minLength(1)
])
})
const payload = await request.validate({
schema: newUserSchema,
messages: {
'tags.minLength': 'At least one tag is required'
}
})
// Safe to access payload.tags[0] because validation passed
return {
success: true,
firstTag: payload.tags ? payload.tags[0] : null
}
}For database operations, Adonisjs's Lucid ORM provides safe access patterns. Instead of directly accessing array indices, use optional chaining and nullish coalescing:
async show({ params }) {
const user = await User.find(params.id)
// Safe access pattern
return {
name: user?.name ?? 'Unknown',
email: user?.email ?? '[email protected]',
role: user?.role ?? 'guest'
}
}Middleware is an excellent place to centralize OOB Read protection in Adonisjs applications. Create a validation middleware that ensures required data exists:
class DataValidationMiddleware {
async handle({ request }, next) {
const body = request.post()
// Ensure required fields exist
if (!body?.userIds || !Array.isArray(body.userIds)) {
return response.badRequest({
error: 'userIds must be an array'
})
}
// Ensure array has elements before accessing
if (body.userIds.length === 0) {
return response.badRequest({
error: 'userIds array cannot be empty'
})
}
await next()
}
}
// Register in start/kernel.js
const globalMiddleware = [
'App/Middleware/DataValidationMiddleware'
]Adonisjs's error handling system can also help prevent OOB Read vulnerabilities from causing application crashes. Configure a global error handler:
// app/Exceptions/Handler.js
class ExceptionHandler {
async handle(error, { response }) {
if (error instanceof TypeError && error.message.includes('Cannot read property')) {
// Log the incident and return safe response
console.warn('OOB Read attempt:', error.message)
return response.status(500).json({
error: 'Internal server error'
})
}
return response.status(500).json({
error: 'Internal server error'
})
}
}For API endpoints that return data, always provide default values or proper error responses:
async fetchProducts({ request }) {
const category = request.input('category', 'all')
const products = await Product.query()
.where('category', category)
.limit(10)
// Safe access with default values
return products.map(product => ({
id: product.id,
name: product.name || 'Unnamed Product',
price: product.price ?? 0,
description: product.description || ''
}))
}