Out Of Bounds Write in Adonisjs
How Out Of Bounds Write Manifests in Adonisjs
Out Of Bounds Write vulnerabilities in Adonisjs applications typically occur when user-controlled input is used to index into arrays or objects without proper bounds checking. In Adonisjs, this often manifests through dynamic property assignment, request body parsing, and model mass assignment.
A common Adonisjs-specific pattern involves the request.all() method, which merges request.body(), request.query(), and request.params() into a single object. When this merged object is directly passed to model methods like Model.create() or Model.fill(), an attacker can exploit property whitelisting to write to unintended properties.
class UserController {
async store({ request, response }) {
const data = request.all(); // Merges body, query, params
const user = await User.create(data); // Vulnerable to OOB write
return response.json(user);
}
}
Another Adonisjs-specific scenario involves the @each decorator for model relationships. When combined with user-controlled indices, attackers can manipulate relationship data structures:
class Post extends Model {
@each('comments', 'App/Models/Comment')
comments;
async addComment({ request }) {
const { index, content } = request.only(['index', 'content']);
const comment = await Comment.create({ content });
this.comments[index] = comment; // OOB write if index is invalid
await this.save();
}
}
Adonisjs's Lucid ORM also introduces OOB write risks through dynamic model attribute assignment. The fill() method accepts any object and assigns properties based on the model's schema, but without strict type checking:
class ProductController {
async update({ request, params }) {
const product = await Product.find(params.id);
const updates = request.only(['name', 'price', 'description']);
product.fill(updates); // Vulnerable if updates contains unexpected properties
await product.save();
}
}
The vulnerability becomes more severe when combined with Adonisjs's implicit type casting. A string like __proto__ or constructor passed through request.all() can trigger prototype pollution, allowing attackers to modify object prototypes and inject arbitrary properties across all instances.
Adonisjs-Specific Detection
Detecting Out Of Bounds Write vulnerabilities in Adonisjs requires examining both code patterns and runtime behavior. middleBrick's black-box scanning approach is particularly effective for Adonisjs applications because it tests the actual API endpoints without requiring source code access.
When scanning an Adonisjs API endpoint, middleBrick performs several specific checks:
- Property Authorization Testing: Attempts to write to properties that shouldn't be user-modifiable, such as
id,created_at, or internal model properties - Array Index Manipulation: Tests boundary conditions on array-like properties and relationship indices
Mass Assignment Testing: Probes for vulnerabilities inModel.create()andModel.fill()usage patterns
For Adonisjs applications, middleBrick's scanning process includes these specific steps:
# Scan an Adonisjs API endpoint
middlebrick scan https://api.example.com/users
The scanner tests for OOB write by attempting to:
- Modify read-only properties through mass assignment
- Write to array indices beyond the current bounds
- Exploit prototype pollution via
__proto__andconstructorproperties - Manipulate relationship data structures
middleBrick's Property Authorization check specifically identifies Adonisjs patterns where models accept unvalidated input. The scanner examines the API's response structure and attempts to write to properties that should be protected by the model's schema.
For development teams using Adonisjs, the CLI tool provides JSON output that highlights specific OOB write risks:
{
"endpoint": "/api/users",
"risk_score": 65,
"findings": [
{
"category": "Property Authorization",
"severity": "high",
"description": "Potential Out Of Bounds Write via mass assignment",
"remediation": "Implement strict whitelist validation in User model",
"adonisjs_specific": true,
"affected_methods": ["Model.create", "Model.fill"]
}
]
}
The GitHub Action integration allows continuous monitoring of Adonisjs APIs in CI/CD pipelines:
- name: Run middleBrick Security Scan
uses: middlebrick/middlebrick-action@v1
with:
url: http://localhost:3333/api
fail_below: 80
Adonisjs-Specific Remediation
Remediating Out Of Bounds Write vulnerabilities in Adonisjs requires a multi-layered approach that leverages the framework's built-in security features. The most effective strategy combines strict model whitelisting, input validation, and safe assignment patterns.
For model-level protection, Adonisjs provides the $fillable and $guard properties on Lucid models. These should be explicitly defined to prevent mass assignment vulnerabilities:
class User extends Model {
static get $fillable() {
return ['name', 'email', 'password'];
}
static get $guard() {
return ['id', 'created_at', 'updated_at', 'is_admin'];
}
}
The $fillable array explicitly whitelists properties that can be mass-assigned, while $guard protects sensitive properties from being modified. This prevents OOB writes through Model.create() and Model.fill() methods.
For request handling, Adonisjs's request.only() and request.pick() methods provide safe property selection:
class UserController {
async update({ request, params }) {
const user = await User.find(params.id);
// Only allow specific properties
const allowed = request.only(['name', 'email', 'password']);
// Validate and sanitize
const schema = schema.create({
name: schema.string.optional(),
email: schema.string.optional({}, [
rules.email(),
rules.maxLength(255)
]),
password: schema.string.optional({}, [
rules.minLength(8)
])
});
const validated = await request.validate({ schema });
user.merge(validated);
await user.save();
}
}
For array and relationship operations, implement bounds checking before assignment:
class PostController {
async addComment({ request, params }) {
const post = await Post.find(params.id);
const { index, content } = request.only(['index', 'content']);
// Bounds checking
if (index < 0 || index > post.comments_count) {
return response.status(400).json({
error: 'Comment index out of bounds'
});
}
const comment = await Comment.create({ content });
post.comments[index] = comment;
await post.save();
}
}
Adonisjs's validation schema can also protect against prototype pollution attacks:
const schema = schema.create({
name: schema.string({}, [
rules.blacklist(['__proto__', 'constructor', 'prototype'])
]),
data: schema.object.optional()
});
For relationship handling, use Adonisjs's built-in relationship methods instead of direct array manipulation:
class PostController {
async addComment({ request, params }) {
const post = await Post.find(params.id);
const commentData = request.only(['content']);
// Use relationship method instead of direct array write
const comment = await post.comments().create(commentData);
return response.json(comment);
}
}
The middleBrick CLI can verify these remediations by scanning the protected endpoints:
middlebrick scan https://api.example.com --test-property-authorization
This comprehensive approach ensures that Out Of Bounds Write vulnerabilities are eliminated at both the model and controller levels, leveraging Adonisjs's native security features while maintaining application functionality.