HIGH zip slipexpresscockroachdb

Zip Slip in Express with Cockroachdb

Zip Slip in Express with Cockroachdb — how this specific combination creates or exposes the vulnerability

Zip Slip is a path traversal vulnerability that occurs when an application constructs file paths using user-supplied input without proper validation. In an Express application that interacts with CockroachDB, the risk is not that the database itself suffers path traversal, but that malicious payloads can escape intended directories when the application writes or references files on the server. For example, an endpoint that accepts a database backup filename or a migration script path might concatenate user input directly to a base directory, allowing sequences like ../../../ to traverse outside the target folder.

Consider an Express route that stores a backup file name provided by an admin user into a CockroachDB table for later retrieval:

const express = require('express');
const fs = require('fs');
const path = require('path');
const { Pool } = require('pg');

const pool = new Pool({ connectionString: process.env.COCKROACHDB_URL });
const app = express();
app.use(express.json());

app.post('/save-backup', async (req, res) => {
  const { backupName } = req.body; // user-controlled
  const targetDir = '/var/backups/cockroach';
  const filePath = path.join(targetDir, backupName); // vulnerable if backupName contains ../

  // If attacker sends {"backupName": "../../../etc/passwd"}, filePath escapes targetDir
  fs.writeFileSync(filePath, 'fake backup content');

  const query = 'INSERT INTO backup_log (name, path) VALUES ($1, $2)';
  await pool.query(query, [backupName, filePath]);
  res.json({ ok: true });
});

Here, if the backupName is not validated, an attacker can write files outside the intended backup directory. Because the path is later stored in CockroachDB, any subsequent retrieval or listing operations may expose or serve unintended files. The same pattern applies when accepting filenames for restores or migrations: unchecked user input used in file system operations enables Zip Slip, and the database merely records the malicious path for future misuse.

Another scenario involves serving user-generated content from a directory tied to CockroachDB metadata. If Express constructs URLs or filesystem paths from record identifiers without canonicalization, an attacker can leverage directory traversal to read arbitrary files. For example:

app.get('/export/:recordId', async (req, res) => {
  const { recordId } = req.params;
  const query = 'SELECT filename FROM records WHERE id = $1';
  const { rows } = await pool.query(query, [recordId]);
  if (!rows.length) return res.status(404).send('Not found');

  const base = '/data/exports';
  const filePath = path.join(base, rows[0].filename); // filename from DB could be manipulated via prior input
  res.download(filePath);
});

If an earlier administrative endpoint allowed an attacker to insert a filename like ../../../secrets/.env into the database, this route could facilitate path traversal on retrieval. The vulnerability therefore emerges from the combination of unchecked user input in file operations and the persistence of paths in CockroachDB, not from the database protocol itself.

Cockroachdb-Specific Remediation in Express — concrete code fixes

Remediation centers on strict input validation, path canonicalization, and avoiding direct concatenation of user input into filesystem paths. Below are concrete Express patterns that safely handle filenames when storing metadata in CockroachDB.

1. Validate and sanitize filenames before database and filesystem use: Use a whitelist approach and remove dangerous sequences. Do not rely solely on client-side checks.

function safeFilename(input) {
  // Allow alphanumerics, underscores, hyphens, and a single dot for extension
  const normalized = input.replace(/[^a-zA-Z0-9_.-]/g, '');
  if (!/^[a-zA-Z0-9_.-]+$/.test(normalized)) {
    throw new Error('Invalid filename');
  }
  return normalized;
}

2. Use a database-stored mapping rather than trusting stored filenames for path construction: Keep original filenames in CockroachDB but map them to safe filesystem names.

app.post('/save-backup-safe', async (req, res) => {
  const { backupName } = req.body;
  const safeName = safeFilename(backupName);
  const storageKey = `backup_${Date.now()}_${safeName}`;
  const targetDir = '/var/backups/cockroach';
  const filePath = path.join(targetDir, storageKey);

  fs.writeFileSync(filePath, 'backup content');

  const query = 'INSERT INTO backup_log (original_name, storage_key, path) VALUES ($1, $2, $3)';
  await pool.query(query, [backupName, storageKey, filePath]);
  res.json({ ok: true, storageKey });
});

3. When serving files, reconstruct paths from trusted identifiers and avoid user-supplied names: Query CockroachDB for the storage key and build the path server-side.

app.get('/export-safe/:recordId', async (req, res) => {
  const { recordId } = req.params;
  const query = 'SELECT storage_key FROM backup_log WHERE id = $1';
  const { rows } = await pool.query(query, [recordId]);
  if (!rows.length) return res.status(404).send('Not found');

  const base = '/var/backups/cockroach';
  const filePath = path.join(base, rows[0].storage_key);
  res.download(filePath);
});

4. Always resolve paths to ensure they remain within the intended directory: Use path.resolve and verify the resolved path starts with the expected absolute base directory.

function withinBase(filePath, base) {
  const resolved = path.resolve(filePath);
  const baseResolved = path.resolve(base);
  return resolved.startsWith(baseResolved + path.sep) || resolved === baseResolved;
}

// Usage example inside a route
const candidate = path.join(targetDir, userSupplied);
if (!withinBase(candidate, targetDir)) {
  return res.status(400).send('Invalid path');
}

By combining strict filename normalization, server-side mapping, and path canonicalization checks, Express applications can safely persist metadata in CockroachDB while mitigating Zip Slip risks.

Frequently Asked Questions

Can Zip Slip affect CockroachDB data integrity directly?
No. Zip Slip is a file system path traversal issue; CockroachDB remains unaffected. The risk is that attackers may read or write unintended files on the host server if user input is used unsafely in file operations.
Does enabling CockroachDB TLS or authentication prevent Zip Slip in Express?
No. Transport encryption and database authentication do not mitigate path traversal in the application layer. You must validate and sanitize file paths and avoid concatenating unchecked user input into filesystem paths.