Ssrf Server Side in Adonisjs with Cockroachdb
Ssrf Server Side in Adonisjs with Cockroachdb — how this specific combination creates or exposes the vulnerability
Server-side request forgery (SSRF) in an AdonisJS application that uses CockroachDB can arise when the app accepts a user-supplied URL or host and makes an HTTP request on behalf of the server, while also interacting with CockroachDB as the backend store. In this stack, an attacker may supply a CockroachDB connection string or an internal service address (such as the metadata service 169.254.169.254 or the database listener) as the target URL. Because AdonisJS often uses generic HTTP clients (e.g., the built-in HTTP client based on got) to call external APIs or perform webhooks, these requests can be redirected internally if input validation is weak.
The risk is compounded by the typical AdonisJS pattern of centralizing HTTP interactions in services or providers, where a developer may pass a user-controlled parameter into the request configuration. If the application stores or logs the target host in CockroachDB without strict allowlisting, an SSRF payload can be persisted and later used in background jobs or scheduled tasks, expanding the attack surface. CockroachDB itself does not introduce SSRF, but it can act as a pivot point: an SSRF probe that reaches the database may return schema or credential information if the application uses the database to store or retrieve sensitive configuration, such as API keys or internal endpoints.
Common attack patterns in this combination include probing the metadata service to obtain instance credentials, targeting internal admin panels bound to localhost, or abusing DNS rebinding to resolve to CockroachDB’s RPC ports. Because AdonisJS may rely on environment variables stored in the database or loaded via configuration files, SSRF can lead to indirect data exposure, including table names, index structures, or execution of crafted queries when the application deserializes maliciously crafted input. The 12 security checks in middleBrick highlight these risks by testing input validation and data exposure in tandem with the API surface that interacts with CockroachDB.
Cockroachdb-Specific Remediation in Adonisjs — concrete code fixes
Remediation focuses on strict input validation, network segregation, and secure handling of database credentials within AdonisJS. Do not allow user-controlled values to define request targets. Instead, use allowlists for protocols, hosts, and ports, and resolve internal addresses via configuration rather than runtime input.
1. Validate and restrict outbound targets
Create a validation layer for any user input that could influence an outbound request. Use schema-driven validation in AdonisJS to reject non-whitelisted hosts and block private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) and loopback addresses.
// resources/validators/url.validator.ts
import { schema } from '@ioc:Adonis/Core/Validator'
export const outboundRequestSchema = schema.create({
targetUrl: schema.string({}, [rules.url(), rules.hostname(), (_, _, value) => {
const allowed = ['api.example.com', 'webhook.partner.com']
return allowed.includes(new URL(value).hostname)
}]),
method: schema.optional.string({}, [rules.optional(), rules.in(['GET', 'POST'])]),
})
2. Use a typed HTTP client with fixed base URLs
Configure a dedicated HTTP client in AdonisJS with a fixed base URL and disable redirects to internal addresses. This ensures that even if a malicious parameter is supplied, the request cannot be diverted to internal services or metadata endpoints.
// start/hooks.ts
import { Http } from '@adonisjs/core/http'
import { cacache } from 'cacache'
Http.hooks.register('beforeRoute', (ctx) => {
ctx.request.httpClient = Http.client.get({ timeout: 5000, redirect: 'manual' })
})
// app/Services/ExternalService.ts
import { Http } from '@ioc:Adonis/Core/Http'
export class ExternalService {
private client = Http.client
.get({ baseURL: 'https://api.example.com', timeout: 8000 })
.disableRedirects()
async fetchPublicData(id: string) {
return this.client.get('/v1/data', { params: { id } })
}
}
3. Secure CockroachDB connection handling
Store CockroachDB credentials and connection strings exclusively in environment variables or a secure vault, and never write them to logs or responses that could be exposed via SSRF. Use connection pooling with minimal privileges and avoid embedding host information in user-controlled data structures.
// config/database.ts
import { Env } from '@ioc:Adonis/Core/Env'
export default {
connection: 'cockroachdb',
connections: {
cockroachdb: {
client: 'pg',
host: Env.get('COCKROACH_HOST', 'localhost'),
port: Env.get('COCKROACH_PORT', 26257),
user: Env.get('COCKROACH_USER', 'root'),
password: Env.get('COCKROACH_PASSWORD', ''),
database: Env.get('COCKROACH_DB', 'defaultdb'),
ssl: {
rejectUnauthorized: true,
},
extra: {
application_name: 'adonisjs-app',
max: {
idleCount: 1,
lifetime: 30000,
},
},
},
},
}
4. Avoid storing sensitive data in database-mapped models
Do not use AdonisJS models to store or retrieve values that influence outbound request targets. If you must persist configuration, enforce strict validation and encrypt sensitive fields. This reduces the risk that an SSRF vector can read or modify routing information stored in CockroachDB.
// app/Models/SecureConfig.ts
import { DateTime } from 'luxon'
import {
BaseModel,
column,
beforeSave,
} from '@ioc:Adonis/Lucid/Orm'
import { encrypt, decrypt } from 'App/Helpers/crypto'
export default class SecureConfig extends BaseModel {
@column({ isPrimary: true })
public id: number
@column()
public encryptedValue: string
@column.dateTime({ autoCreate: true })
public createdAt: DateTime
@beforeSave()
public static async encryptValue(config: SecureConfig) {
if (config.$dirty.plainValue) {
config.encryptedValue = encrypt(config.plainValue)
}
}
}