HIGH zip slipexpressdynamodb

Zip Slip in Express with Dynamodb

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

Zip Slip is a path traversal vulnerability that occurs when user-supplied paths are concatenated to a base directory without proper validation. In an Express application that interacts with DynamoDB, the risk emerges not from DynamoDB itself, because DynamoDB does not use a traditional filesystem path model, but from how the application handles file operations before or after database interactions. For example, an endpoint might accept a fileName parameter, validate it minimally, and then use it to write a file to disk or extract an archive, while also storing metadata in DynamoDB. If the filename includes sequences like ../, an attacker can traverse outside the intended directory. The DynamoDB interaction can inadvertently amplify the issue: the application might log or index user-controlled values (such as a key name or object metadata) in DynamoDB, and later use those values in file system operations without re-validation. This cross-reference between user input, DynamoDB storage, and local file handling creates a chain where a malicious payload stored in the database can be reused in subsequent file operations, leading to unauthorized file access or overwrite. The unauthenticated scan capabilities of middleBrick can detect such unsafe consumption patterns by correlating API input points with file system interactions and identifying missing path sanitization.

Dynamodb-Specific Remediation in Express — concrete code fixes

To prevent Zip Slip in an Express service that uses DynamoDB, enforce strict input validation and canonicalize paths before any file system operation. Avoid directly using user input as a file path. Instead, use a allowlist of permitted file names or extensions and resolve paths with path.resolve() and path.normalize() to eliminate .. sequences. When storing and retrieving objects from DynamoDB, keep file metadata separate from user-controlled paths. Below is a concrete example using the AWS SDK for JavaScript (v3) with Express, demonstrating safe handling:

const express = require('express');
const { DynamoDBClient, PutItemCommand, GetItemCommand } = require('@aws-sdk/client-dynamodb');
const { marshall, unmarshall } = require('@aws-sdk/util-dynamodb');
const path = require('path');
const fs = require('fs');

const app = express();
app.use(express.json());

const client = new DynamoDBClient({ region: 'us-east-1' });
const TABLE_NAME = process.env.TABLE_NAME || 'MyTable';

// Safe upload: validate and sanitize before file system or DB operations
app.post('/upload', (req, res) => {
  const { fileName, content } = req.body;
  if (!fileName || typeof content === 'undefined') {
    return res.status(400).json({ error: 'Missing fileName or content' });
  }

  // Validate fileName: allow only alphanumeric, underscores, hyphens, and a safe extension
  const safeName = path.basename(fileName);
  const baseName = path.parse(safeName).name;
  const ext = path.parse(safeName).ext;
  const allowedExtensions = ['.txt', '.json', '.csv'];
  if (!allowedExtensions.includes(ext) || !/^[a-zA-Z0-9_-]+$/.test(baseName)) {
    return res.status(400).json({ error: 'Invalid file name' });
  }

  // Resolve to an absolute path within a controlled directory
  const targetDir = path.resolve(__dirname, 'uploads');
  const filePath = path.join(targetDir, safeName);

  // Ensure the resolved path is inside the target directory (prevent traversal)
  if (!filePath.startsWith(path.resolve(targetDir))) {
    return res.status(400).json({ error: 'Invalid path traversal attempt' });
  }

  // Write file safely
  fs.writeFileSync(filePath, content);

  // Store metadata in DynamoDB using safe marshalling
  const putCmd = new PutItemCommand({
    TableName: TABLE_NAME,
    Item: marshall({
      fileId: `${Date.now()}-${safeName}`,
      fileName: safeName,
      filePath: filePath,
      uploadedAt: new Date().toISOString(),
    }),
  });

  client.send(putCmd).then(() => {
    res.status(201).json({ message: 'File uploaded and recorded', fileName: safeName });
  }).catch(err => {
    console.error(err);
    res.status(500).json({ error: 'Failed to record file metadata' });
  });
});

// Safe retrieve: use DB record to locate file, not user-supplied path
app.get('/files/:fileId', async (req, res) => {
  const { fileId } = req.params;
  const getCmd = new GetItemCommand({
    TableName: TABLE_NAME,
    Key: marshall({ fileId }),
  });

  try {
    const data = await client.send(getCmd);
    if (!data.Item) {
      return res.status(404).json({ error: 'File not found' });
    }
    const item = unmarshall(data.Item);
    const filePath = item.filePath;

    // Double-check path safety before reading
    const resolvedPath = path.resolve(filePath);
    const baseDir = path.resolve(__dirname, 'uploads');
    if (!resolvedPath.startsWith(baseDir)) {
      return res.status(403).json({ error: 'Invalid file path' });
    }

    if (fs.existsSync(resolvedPath)) {
      res.sendFile(resolvedPath);
    } else {
      res.status(404).json({ error: 'File not found on disk' });
    }
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Failed to retrieve file' });
  }
});

app.listen(3000, () => console.log('Server running on port 3000'));

In this pattern, DynamoDB stores canonical metadata (fileId, fileName, filePath), while the file system operations rely on sanitized, resolved paths derived from controlled logic rather than raw user input. middleBrick can highlight areas where user input reaches file system calls without adequate validation, helping you identify and close Zip Slip vectors even when DynamoDB is used as a complementary data store.

Frequently Asked Questions

Can DynamoDB itself be exploited via Zip Slip?
DynamoDB does not use file system paths, so it cannot be exploited directly via Zip Slip. The risk occurs when application code uses user-controlled values stored in DynamoDB in unsafe file operations without proper validation.
How does middleBrick detect Zip Slip risks in Express APIs using DynamoDB?