HIGH integrity failuresadonisjs

Integrity Failures in Adonisjs

How Integrity Failures Manifests in Adonisjs

Integrity failures in Adonisjs applications typically occur when the server accepts modified client-side data without proper validation. In Adonisjs, this often manifests through model binding, query parameters, and form submissions where users can manipulate values to escalate privileges or access unauthorized resources.

The most common Adonisjs-specific integrity failure occurs with model binding. When using route model binding like async update({ params, request }) { const user = await User.findOrFail(params.id); }, if you directly use the bound model without verifying the authenticated user's permissions, an attacker can modify the URL parameter to access any user record.

Another frequent pattern involves query parameter manipulation. Adonisjs applications often use request.input() or request.qs() to capture filters or pagination parameters. Without validation, attackers can inject values that bypass authorization checks or cause logic errors.

async index({ request }) {
  const page = request.input('page', 1);
  const limit = request.input('limit', 10);
  
  // Integrity failure: unvalidated user input used directly
  return await User.query()
    .paginate(page, limit)
    .then(({ data }) => data);
}

This code allows an attacker to request any page or set an arbitrary limit, potentially causing performance issues or bypassing pagination-based access controls.

Adonisjs's Lucid ORM can also introduce integrity failures when using fetchOrCreate or updateOrCreate methods with user-supplied data. If the unique constraint or matching criteria comes from request parameters, attackers can manipulate these to create or update unintended records.

// Integrity failure: user can manipulate email to update any record
const user = await User.updateOrCreate(
  { email: request.input('email') },
  { name: request.input('name') }
);

The framework's middleware system can compound these issues. If authentication middleware sets user data on the request object, and subsequent middleware or controllers trust this data without re-validation, an attacker who bypasses authentication (or manipulates the request in transit) can inject arbitrary values.

Adonisjs-Specific Detection

Detecting integrity failures in Adonisjs requires examining both the application code and runtime behavior. Static analysis should focus on identifying where user input flows into database operations or authorization decisions without validation.

Code patterns to scan for include:

  • Route model binding without permission checks
  • Direct use of request.input(), request.qs(), or request.all() in database queries
  • Use of fetchOrCreate or updateOrCreate with request data
  • Middleware that trusts request data without validation
  • ACL or policy checks that use unvalidated parameters

middleBrick's black-box scanning approach is particularly effective for detecting integrity failures in Adonisjs applications. The scanner tests unauthenticated endpoints by modifying request parameters and observing how the application responds.

For example, middleBrick would test if an endpoint like /api/users/:id properly validates that the authenticated user owns the resource being accessed. It does this by:

  1. Scanning the endpoint without authentication to see if it returns data
  2. Modifying the ID parameter to test for IDOR (Insecure Direct Object Reference)
  3. Testing if query parameters can be manipulated to bypass filters
  4. Checking if pagination or limit parameters are properly constrained

The scanner's OpenAPI analysis also helps detect integrity failures by examining the API specification. If the spec shows endpoints that accept IDs or user-specific data without proper authentication requirements, this flags potential integrity issues.

middleBrick's 12 security checks include specific tests for authorization bypass attempts, making it effective at catching Adonisjs-specific integrity failures that might be missed by generic scanners.

Adonisjs-Specific Remediation

Remediating integrity failures in Adonisjs requires a defense-in-depth approach using the framework's built-in features. The primary strategy is to validate and sanitize all user input before it reaches business logic.

For route model binding, always add explicit permission checks:

async update({ params, request, auth }) {
  const user = await User.findOrFail(params.id);
  
  // Integrity fix: validate user owns this resource
  if (user.id !== auth.user.id && !auth.user.isAdmin) {
    return response.status(403).send('Unauthorized')
  }
  
  user.merge(request.post());
  await user.save();
  return user;
}

Adonisjs's Validator makes input validation straightforward. Always validate pagination and filter parameters:

async index({ request }) {
  const { page, limit } = await request.validate({
    schema: {
      page: schema.number.optional([
        rules.unsigned(),
        rules.range(1, 1000)
      ]),
      limit: schema.number.optional([
        rules.unsigned(),
        rules.range(1, 100)
      ])
    }
  });
  
  return await User.query()
    .paginate(page || 1, limit || 20)
    .then(({ data }) => data);
}

For methods like updateOrCreate, validate the matching criteria:

async upsertUser({ request }) {
  const { email, name } = await request.validate({
    schema: {
      email: schema.string({}, [
        rules.email(),
        rules.max(255)
      ]),
      name: schema.string.optional([rules.max(255)])
    }
  });
  
  // Only allow updating own record or if admin
  const user = await User.query()
    .where('email', email)
    .where((builder) => {
      if (!auth.user.isAdmin) {
        builder.where('id', auth.user.id)
      }
    })
    .first();
  
  if (user) {
    user.name = name;
    await user.save();
  } else {
    await User.create({ email, name });
  }
  
  return { success: true };
}

Adonisjs's policies provide a centralized way to handle authorization. Create a policy for your models:

class UserPolicy {
  constructor(user) {
    this.user = user
  }
  
  canView(otherUser) {
    return this.user.id === otherUser.id || this.user.isAdmin
  }
  
  canUpdate(otherUser) {
    return this.user.id === otherUser.id || this.user.isAdmin
  }
}

// In your controller
async show({ params }) {
  const user = await User.findOrFail(params.id);
  const policy = new UserPolicy(auth.user);
  
  if (!policy.canView(user)) {
    return response.status(403).send('Unauthorized');
  }
  
  return user;
}

For middleware that processes request data, add validation layers:

class ValidateRequestData {
  async handle({ request }, next) {
    const data = await request.validate({
      schema: schema.object({
        role: schema.string.optional([
          rules.in(['user', 'admin', 'moderator'])
        ])
      })
    });
    
    request.cleanedData = data;
    await next();
  }
}

Frequently Asked Questions

How does middleBrick detect integrity failures in Adonisjs applications?
middleBrick performs black-box scanning by testing API endpoints with modified parameters to detect IDOR and authorization bypass vulnerabilities. It checks if authenticated endpoints can be manipulated by changing IDs in URLs, modifying query parameters, or bypassing pagination controls. The scanner also analyzes OpenAPI specs to identify endpoints that accept user-specific data without proper authentication requirements.
What's the difference between integrity failures and broken authentication in Adonisjs?
Broken authentication is about verifying who the user is (login mechanisms, session management), while integrity failures occur after authentication when the application accepts manipulated data from an authenticated user. An integrity failure might let a user modify another user's ID in a URL parameter, whereas broken authentication would be about logging in as that user in the first place. Integrity failures often involve model binding, query parameters, and form submissions where users can tamper with values.