Phishing Api Keys in Express with Cockroachdb
Phishing Api Keys in Express with Cockroachdb — how this specific combination creates or exposes the vulnerability
When an Express application uses CockroachDB as its data store and handles API keys, the interaction between runtime behavior and database design can expose secrets through multiple vectors. A common pattern is to store API keys as strings in a CockroachDB table, such as api_keys, and retrieve them via an endpoint like /config/:env. If this endpoint does not enforce authentication and instead relies on unauthenticated access or weak referrer checks, an attacker can probe the route and receive key material directly in the response.
In a typical setup, the application might open a CockroachDB SQL connection using a URL stored in an environment variable, then execute a query such as SELECT key FROM api_keys WHERE env = $1. If the route is inadvertently exposed—perhaps due to a misconfigured middleware stack that allows unauthenticated requests to reach config endpoints—an attacker can use simple HTTP requests to harvest keys. This is a classic case where weak access control combines with insecure data exposure in the database layer to create a functional phishing surface: the API appears to serve configuration, but in reality it leaks credentials.
Another vector involves error handling and logging. If the Express app passes raw database errors to the client, a malformed request might cause CockroachDB to return stack traces or connection strings that include embedded keys. For example, a query constructed with string concatenation instead of parameterized statements can lead to syntax errors that reveal internal details. Even when the application uses prepared statements, verbose error messages can disclose whether a key exists for a given environment, enabling targeted phishing campaigns where attackers craft convincing-looking configuration payloads to trick downstream consumers.
The LLM/AI Security checks available in middleBrick are particularly relevant here because an exposed config endpoint could lead to system prompt leakage if the API keys are used to authorize language model calls. An attacker who obtains a key might use it to probe the application’s LLM integrations, testing for prompt injection or data exfiltration paths. middleBrick runs active prompt injection probes and system prompt leakage detection, which can surface risks where API keys double as model credentials.
Additionally, middleBrick’s inventory management and unsafe consumption checks help identify whether API keys are stored in plaintext, transmitted without encryption, or cached improperly by the client. Because the scanner tests the unauthenticated attack surface in 5–15 seconds, it can quickly highlight routes that return key-like strings without authentication, enabling teams to validate that sensitive values are never exposed through unauthenticated endpoints.
Cockroachdb-Specific Remediation in Express — concrete code fixes
To secure an Express application that uses CockroachDB, focus on strict access control, safe query patterns, and disciplined error handling. The following examples assume you have a table defined as CREATE TABLE api_keys (id UUID PRIMARY KEY, env STRING, key STRING, created_at TIMESTAMP);.
1. Use parameterized queries and enforce authentication
Never concatenate user input into SQL strings. Use prepared statements with environment-based routing that is gated by middleware. For example:
const express = require('express');
const { Pool } = require('pg');
const app = express();
const pool = new Pool({ connectionString: process.env.COCKROACH_URL });
// Auth middleware example
function requireAuth(req, res, next) {
if (!req.headers['x-api-key'] || req.headers['x-api-key'] !== process.env.SERVICE_KEY) {
return res.status(401).json({ error: 'unauthorized' });
}
next();
}
app.get('/config/:env', requireAuth, async (req, res) => {
const { env } = req.params;
try {
const result = await pool.query('SELECT key FROM api_keys WHERE env = $1', [env]);
if (result.rows.length === 0) {
return res.status(404).json({ error: 'not found' });
}
res.json({ key: result.rows[0].key });
} catch (err) {
res.status(500).json({ error: 'internal server error' });
}
});
app.listen(3000);
2. Avoid exposing keys in error paths and logs
Ensure that database errors do not reach the client. Wrap queries to normalize responses and log details server-side only:
async function safeQuery(client, text, params) {
try {
const result = await client.query(text, params);
return { data: result.rows };
} catch (err) {
console.error('DB error:', err.message);
return { error: 'request failed' };
}
}
// Usage inside a route
app.get('/keys/:id', async (req, res) => {
const client = await pool.connect();
const response = await safeQuery(client, 'SELECT key FROM api_keys WHERE id = $1', [req.params.id]);
client.release();
if (response.error) return res.status(500).json(response);
res.json(response.data);
});
3. Rotate keys and audit access patterns
Even with secure code, stored keys can be compromised. Use CockroachDB’s changefeed capabilities or scheduled jobs to rotate keys regularly and to audit which services accessed which keys. Combine this with middleware that validates key scopes and expiration dates before allowing use.
middleBrick’s Pro plan supports continuous monitoring, which can be configured to scan your staging APIs on a schedule and alert you if a route begins returning key-like strings without authentication. Its GitHub Action can fail builds when risk scores drop below your defined threshold, helping you catch regressions before deployment.