Integer Overflow in Adonisjs
How Integer Overflow Manifests in Adonisjs
Integer overflow in Adonisjs typically occurs when handling numeric inputs in controllers, database queries, or validation logic. The issue arises because JavaScript (and by extension Node.js, which Adonisjs runs on) uses IEEE 754 double-precision floating-point format for numbers, which can safely represent integers only up to 2^53 - 1.
In Adonisjs applications, this vulnerability often appears in:
- Database pagination: When users can control page size or offset parameters, they might input extremely large numbers that cause integer overflow in query calculations.
- Financial calculations: E-commerce applications handling prices, quantities, or totals may experience overflow when multiplying large numbers.
- Resource allocation: APIs that calculate memory, storage, or processing limits based on user input can overflow, leading to incorrect resource assignments.
Here's a common Adonisjs vulnerability pattern:
class ProductController {
async index ({ request }) {
const { page = 1, limit = 10 } = request.qs()
// Vulnerable: no validation of numeric bounds
const offset = (page - 1) * limit
const products = await Product.query()
.offset(offset)
.limit(limit)
.fetch()
return products
}
}If an attacker provides page=999999999999999999 and limit=999999999999999999, the multiplication can overflow, potentially causing the database query to return unexpected results or crash.
Another Adonisjs-specific scenario involves Lucid ORM's query builder:
class OrderController {
async calculateTotal ({ request }) {
const { price, quantity } = request.qs()
// Vulnerable: direct multiplication without bounds checking
const total = price * quantity
return { total }
}
}With price=1e20 and quantity=1e20, the result exceeds safe integer limits, potentially causing incorrect calculations or application crashes.
Adonisjs-Specific Detection
Detecting integer overflow in Adonisjs requires both static analysis and runtime scanning. 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 with middleBrick, the scanner tests for integer overflow by:
- Sending boundary value inputs (numbers near 2^53, negative numbers, zero, and extremely large values)
- Analyzing HTTP responses for anomalies like timeouts, crashes, or incorrect calculations
- Checking for error messages that might reveal internal implementation details
- Testing database query responses for unexpected results
Here's how to use middleBrick to scan your Adonisjs API:
# Using the CLI tool
npx middlebrick scan https://your-adonisjs-api.com/api/productsThe scanner will automatically test for integer overflow in relevant endpoints and provide a security score with specific findings. For Adonisjs applications, middleBrick pays special attention to:
- Query parameter handling in controllers
- Database query builder usage patterns
- Validation logic that might be bypassed with numeric inputs
- Financial calculation endpoints
Additionally, you can integrate middleBrick into your Adonisjs development workflow:
# In your AdonisJS project
npm install -D middlebrick
# Add to package.json scripts
"scripts": {
"scan:api": "middlebrick scan http://localhost:3333"
}For CI/CD integration, add a GitHub Action to your Adonisjs project:
name: API Security Scan
on: [push, pull_request]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run middleBrick Scan
run: |
npx middlebrick scan https://staging.your-adonisjs-app.com/api
continue-on-error: trueThis ensures integer overflow vulnerabilities are caught before deployment to production.
Adonisjs-Specific Remediation
Remediating integer overflow in Adonisjs requires a multi-layered approach using Adonisjs's built-in validation, type checking, and safe arithmetic libraries.
The first layer is input validation using Adonisjs's schema validation:
import { schema, rules } from '@adonisjs/core/validator'
class ProductController {
async index ({ request }) {
const validatedData = await request.validate({
schema: {
page: schema.number.optional(
[rules.unsigned(), rules.range(1, 10000)]
),
limit: schema.number.optional(
[rules.unsigned(), rules.range(1, 100)]
)
},
messages: {
'page.range': 'Page number must be between 1 and 10,000',
'limit.range': 'Limit must be between 1 and 100'
}
})
const { page = 1, limit = 10 } = validatedData
const offset = (page - 1) * limit
const products = await Product.query()
.offset(offset)
.limit(limit)
.fetch()
return products
}
}This approach validates that page and limit values are within safe bounds before any calculations occur.
For financial calculations, use the big-integer library to handle arbitrarily large numbers safely:
import bigInt from 'big-integer'
class OrderController {
async calculateTotal ({ request }) {
const validatedData = await request.validate({
schema: {
price: schema.number([rules.unsigned()]),
quantity: schema.number([rules.unsigned()])
}
})
const { price, quantity } = validatedData
// Convert to safe integer representation
const priceBigInt = bigInt(price.toString())
const quantityBigInt = bigInt(quantity.toString())
const total = priceBigInt.multiply(quantityBigInt)
return { total: total.toString() }
}
}For database operations, use Adonisjs's query builder with safe parameter handling:
class ReportController {
async generateReport ({ request }) {
const validatedData = await request.validate({
schema: {
userId: schema.number([rules.exists({ table: 'users', column: 'id' })]),
days: schema.number.optional([rules.range(1, 365)])
}
})
const { userId, days = 30 } = validatedData
// Safe query with validated parameters
const report = await Report.query()
.where('user_id', userId)
.where('created_at', '>', Database.raw('NOW() - INTERVAL ?? DAY', [days]))
.fetch()
return report
}
}For comprehensive protection, create a middleware that checks for numeric overflow across all endpoints:
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import bigInt from 'big-integer'
export default class OverflowProtectionMiddleware {
async handle ({ request, response }: HttpContextContract, next: () => Promise) {
const query = request.qs()
const body = request.body()
// Check all numeric inputs for safe bounds
const checkOverflow = (obj) => {
for (const [key, value] of Object.entries(obj)) {
if (typeof value === 'number') {
if (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) {
return response.badRequest({
error: 'Numeric value out of safe bounds',
field: key,
value
})
}
} else if (typeof value === 'object' && value !== null) {
checkOverflow(value)
}
}
}
checkOverflow(query)
checkOverflow(body)
await next()
}
} Register this middleware in your start/kernel.ts to protect all routes:
Server.middleware.register([{
name: 'overflowProtection',
boot: () => import('@app/Middleware/OverflowProtectionMiddleware')
}])