Api Key Exposure in Adonisjs with Redis
Api Key Exposure in Adonisjs with Redis — how this specific combination creates or exposes the vulnerability
AdonisJS applications commonly use Redis for caching session data, API tokens, or one-time tokens used for authentication or rate limiting. When developers store sensitive API keys or user secrets directly in Redis without additional controls, the combination of AdonisJS and Redis can inadvertently expose those keys. This exposure can occur through several realistic patterns:
- Keys stored in plain text under predictable Redis keys, such as
api_key:user_123, where an attacker who gains access to the Redis instance or can execute commands on the same host can read the values directly. - Misconfigured Redis allowing connections without authentication or with weak ACL rules, making it possible for an unauthenticated scanner or adjacent service to read key-value pairs.
- Accidental logging or serialization in AdonisJS code that writes Redis keys or values into logs, error messages, or debug output, which can be harvested by an attacker through log access or log injection bugs.
- Insecure default configurations in development or staging environments where AdonisJS connects to Redis without TLS, enabling network-based sniffing in shared or untrusted networks.
An unauthenticated attacker or a scanner performing black-box testing could probe the Redis endpoint (if exposed) to enumerate keys and read values. Even when Redis is not directly exposed, an insecure AdonisJS route or task that echoes Redis contents into HTTP responses can leak keys to remote attackers. The risk is compounded when API keys are used for third-party integrations, as leaked keys can lead to unauthorized access or financial impact. This pattern is commonly seen in applications that use Redis as a fast cache for session or token storage without encrypting or restricting access to sensitive fields.
During a scan, middleBrick tests the unauthenticated attack surface and checks for indicators such as world-readable key patterns, missing authentication on Redis connections, and references to sensitive data in logs or responses. These checks are part of the Data Exposure category and are run in parallel with other security checks to provide a comprehensive risk score and per-category breakdown.
Redis-Specific Remediation in Adonisjs — concrete code fixes
To reduce the risk of API key exposure when using Redis in AdonisJS, apply defense-in-depth measures that limit exposure, encrypt sensitive values, and harden connections.
Use Redis ACL and requirepass
Ensure your Redis instance enforces authentication. Configure a strong password via the requirepass directive and define user roles with least privilege using Redis ACLs. In your AdonisJS application, provide the password through environment variables and avoid hardcoding it.
import { Redis } from '@adonisjs/redis'
// config/redis.ts
export default {
connection: {
host: process.env.REDIS_HOST,
port: Number(process.env.REDIS_PORT || 6379),
password: process.env.REDIS_PASSWORD || '',
tls: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: true } : false
}
}
Namespacing and key design
Avoid predictable key names for sensitive values. Use namespaced keys and avoid storing raw API keys in plain keys. Instead, store metadata or references and keep secrets in a secure vault, using Redis only for non-sensitive cache data.
// Avoid:
await redis.put('api_key:user_123', 'sk_live_abc')
// Prefer non-sensitive reference:
await redis.hset('user:123:api', 'provider', 'stripe')
// Keep the actual key in a secrets manager; store only a reference in Redis
Encrypt values at rest
When you must store sensitive data in Redis, encrypt values before writing them. Use a strong symmetric key managed outside Redis (for example via a secrets manager). In AdonisJS, integrate an encryption helper to handle this securely.
import { crypto } from '@adonisjs/core'
const algorithm = 'aes-256-gcm'
const key = Buffer.from(process.env.ENCRYPTION_KEY!, 'hex')
async function storeEncryptedKey(redis: Redis, userId: string, apiKey: string) {
const iv = crypto.randomBytes(12)
const encrypted = crypto.encrypt(key, iv, apiKey, algorithm)
const payload = JSON.stringify({ iv: iv.toString('hex'), encrypted })
await redis.set(`user:${userId}:api_key`, payload)
}
async function getEncryptedKey(redis: Redis, userId: string): Promise {
const payload = await redis.get(`user:${userId}:api_key`)
if (!payload) return null
const { iv, encrypted } = JSON.parse(payload)
return crypto.decrypt(key, Buffer.from(iv, 'hex'), encrypted, algorithm)
}
Restrict network exposure and TLS
Bind Redis to localhost or a private network, and enforce TLS in production to prevent network sniffing. Configure AdonisJS to use TLS options when connecting in production environments.
// Example TLS configuration for production
export default {
connection: {
host: '127.0.0.1',
port: 6379,
tls: process.env.NODE_ENV === 'production' ? {
rejectUnauthorized: true,
// optionally provide cert/key if using mutual TLS
} : false
}
}
Audit and monitoring
Instrument your AdonisJS application to avoid logging Redis values directly. Sanitize logs and ensure that debug or error paths do not include raw key material. Use middleware or event listeners to redact sensitive fields before writing to logs.
These steps reduce the likelihood of API key exposure via Redis and align with secure handling practices for secrets in distributed cache systems.