Type Confusion in Adonisjs with Cockroachdb
Type Confusion in Adonisjs with Cockroachdb
Type confusion in AdonisJS when interacting with CockroachDB typically arises from mismatched TypeScript or JavaScript type expectations and the runtime values returned by the database. AdonisJS relies on strong typing for models and Lucid ORM contracts, while CockroachDB returns native Postgres-compatible values. If a developer treats a database column as one TypeScript type but the query or cast produces another, runtime behavior can diverge from compile-time assumptions.
Consider a common scenario: a column defined as DECIMAL in CockroachDB is mapped in an AdonisJS model as a number. If the query builder or a custom cast returns a string (for example, when using row.toJSON() without proper serialization), assigning that value to a strictly typed number field can lead to unexpected coercion, such as Number('123.45') working while Number('not-a-number') becomes NaN. This is a type confusion between the expected numeric type and the actual string payload.
Another vector involves polymorphic relations or union types where the runtime entity does not match the static type guard. For instance, if an endpoint expects a User model but receives a serialized representation where the type discriminator is manipulated, AdonisJS may attempt to instantiate the wrong model or apply incorrect validation rules. Because CockroachDB stores JSONB columns as text, deserialization without strict schema validation can allow an attacker to inject objects that change the expected shape, leading to logic flaws such as privilege escalation or incorrect data handling.
LLM/AI security checks within middleBrick highlight prompt injection risks, but type confusion is a classic injection of unexpected data shapes rather than executable code. Still, the impact can be severe: logic bypasses, incorrect access control decisions, or runtime exceptions that degrade service reliability. In a black-box scan, middleBrick tests unauthenticated endpoints and may flag inconsistent type handling when responses do not conform to documented schemas, especially when OpenAPI specs declare numeric or enum types but runtime values violate those constraints.
Using the middleBrick CLI, developers can quickly verify that their API responses adhere to declared types. Running middlebrick scan <url> without authentication will surface mismatches between the spec and runtime behavior, including cases where numeric IDs are returned as strings or where enum values drift into unexpected states. The dashboard and GitHub Action integrations can enforce that type-related inconsistencies do not reach production, complementing the 12 parallel security checks that include Input Validation and Property Authorization.
Cockroachdb-Specific Remediation in Adonisjs — concrete code fixes
Remediation centers on strict casting, schema validation, and consistent serialization. Define explicit transformers for numeric and enum columns so that CockroachDB values are normalized before entering the AdonisJS model layer.
Example: a Transaction model with a amount column of type DECIMAL in CockroachDB. Without a custom cast, the ORM may return a string in certain query paths. Implement a static getter to enforce number conversion:
import { DateTime } from 'luxon'
import { BaseModel, beforeSave } from '@ioc:Adonis/Lucid/Orm'
import { column } from '@ioc:Adonis/Lucid/Columns'
export default class Transaction extends BaseModel {
@column({ isPrimary: true })
public id: number
@column()
public userId: number
@column({ serialize: false })
public amountDecimal: string
@column()
public get amount (): number {
const value = this.serializeAttribute('amountDecimal')
const num = Number(value)
if (Number.isNaN(num)) {
throw new Error('Invalid decimal value from CockroachDB')
}
return num
}
@beforeSave()
public static ensureAmountAsDecimal (transaction: Transaction) {
if (typeof transaction.amountDecimal !== 'string') {
transaction.amountDecimal = String(transaction.amountDecimal)
}
}
}
This ensures that regardless of how CockroachDB returns the value (string or number in JSONB), the getter normalizes it to a number and throws on invalid input, preventing type confusion downstream.
For polymorphic relations or union types, use runtime type guards and schema validation with the Lucid serializer:
import { schema } from '@ioc:Adonis/Core/Validator'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
const transactionSchema = schema.create({
type: schema.union([
schema.literal('credit'),
schema.literal('debit')
]),
amount: schema.number([
(value) => value > 0
])
})
export async function validateTransaction (ctx: HttpContextContract) {
const payload = await ctx.validate({
schema: transactionSchema
})
// payload.type is now strictly 'credit' | 'debit'
// payload.amount is strictly a validated number
return payload
}
When exposing data via JSON:API or standard REST endpoints, explicitly serialize using serialize() or the resource contract to avoid leaking raw CockroachDB JSONB strings that could confuse clients:
import { Resource } from '@ioc:AdonisJS/Addons/LucidResourceSerializer'
export default class TransactionResource extends Resource {
public serialize () {
return {
id: this.item.id,
amount: this.item.amount,
type: this.item.type
}
}
}
In the dashboard, monitor for fields where reported types deviate from the spec. The middleBrick GitHub Action can fail a build if a response contains a string in a field declared as integer, enforcing that CockroachDB schema changes do not introduce type confusion in the API contract.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |