Zip Slip in Dynamodb
How Zip Slip Manifests in Dynamodb
Zip Slip in DynamoDB environments typically occurs when applications process untrusted ZIP archives and extract files to paths derived from archive contents without proper validation. The vulnerability allows attackers to overwrite arbitrary files on the filesystem by using path traversal sequences like ../../ in filenames within the archive.
In DynamoDB contexts, Zip Slip often appears in Lambda functions that handle file uploads, ETL pipelines that process archive data, or backup/restore utilities. A common pattern involves extracting ZIP contents to temporary directories before processing and storing metadata in DynamoDB tables.
Consider this vulnerable Lambda function that processes uploaded ZIP files containing CSV data for DynamoDB import:
const AWS = require('aws-sdk');
const { createReadStream } = require('fs');
const { extract } = require('extract-zip');
const { DynamoDB } = require('aws-sdk');
exports.handler = async (event) => {
const s3 = new AWS.S3();
const dynamodb = new AWS.DynamoDB();
// Download ZIP from S3
const zipStream = s3.getObject({
Bucket: event.bucket,
Key: event.key
}).createReadStream();
// Extract to temporary directory
const tempDir = '/tmp/extracted';
await extract(zipStream, { dir: tempDir });
// Process files - vulnerable to Zip Slip
const files = await fs.readdir(tempDir);
for (const file of files) {
if (file.endsWith('.csv')) {
const csvData = fs.readFileSync(`${tempDir}/${file}`, 'utf8');
// Import CSV data into DynamoDB
const items = parseCSV(csvData);
for (const item of items) {
await dynamodb.putItem({
TableName: 'UserData',
Item: AWS.DynamoDB.Converter.marshall(item)
}).promise();
}
}
}
return { success: true };
};The vulnerability lies in the extract call without path validation. An attacker could craft a ZIP file with entries like ../../etc/passwd or ../../../../proc/self/environ, causing the extraction to overwrite critical system files on the Lambda container's filesystem.
Another DynamoDB-specific Zip Slip scenario occurs in backup utilities that store file paths as DynamoDB attributes. Consider this backup restoration code:
import boto3
import zipfile
import os
def restore_backup(zip_path, dynamodb_table):
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(dynamodb_table)
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
for entry in zip_ref.infolist():
# Vulnerable: uses entry.filename directly
dest_path = os.path.join('/restore', entry.filename)
zip_ref.extract(entry, '/restore')
# Store file metadata in DynamoDB
table.put_item(
Item={
'file_path': dest_path,
'size': entry.file_size,
'timestamp': entry.date_time.isoformat()
}
)
return 'Backup restored'An attacker could include ../../../../../root/.ssh/authorized_keys in the ZIP archive, gaining persistent SSH access to the container if it has SSH enabled.
Dynamodb-Specific Detection
Detecting Zip Slip in DynamoDB-integrated applications requires both static analysis of extraction logic and runtime scanning of exposed endpoints. The middleBrick API security scanner includes specific Zip Slip detection for DynamoDB workflows.
middleBrick's Zip Slip detection examines Lambda functions and containerized applications that:
- Use ZIP extraction libraries without path validation
- Process file uploads that could contain archives
- Store file paths or metadata in DynamoDB tables
- Perform file operations based on untrusted input
- Handle backup/restore functionality
The scanner tests for Zip Slip by attempting to extract archives with malicious path traversal sequences and monitoring for successful file writes outside intended directories. For DynamoDB-specific workflows, middleBrick also checks:
- Backup restoration endpoints that accept ZIP files
- File processing pipelines that store results in DynamoDB
- ETL jobs that extract archives before database operations
- Content management systems integrated with DynamoDB
Here's how middleBrick reports Zip Slip findings for a DynamoDB-integrated API:
{
"severity": "high",
"category": "Input Validation",
"title": "Zip Slip Path Traversal Vulnerability",
"description": "The API endpoint /upload-csv accepts ZIP files and extracts them without validating file paths, allowing attackers to overwrite arbitrary files on the filesystem.",
"impact": "Attackers can overwrite critical system files, inject malicious code, or gain persistent access to the Lambda container environment.",
"remediation": "Validate and sanitize all file paths before extraction. Use safe extraction libraries or implement path traversal detection.",
"affected_components": ["Lambda function: process-csv", "DynamoDB table: UserData"],
"remediation_guidance": "Implement path validation using a whitelist approach. Only allow extraction to specific directories and validate that extracted paths do not contain '..' sequences or absolute paths."
}Manual detection should include reviewing code for these patterns:
// Vulnerable patterns to search for:
const { extract } = require('extract-zip');
const { createGunzip } = require('zlib');
const { extractAll } = require('tar');
// Look for these without path validation:
extract(zipStream, { dir: '/tmp' });
archive.extractAll('/tmp');
zip.extractAllTo('/tmp', true);
// Check for path construction like:
const dest = path.join('/tmp', entry.filename);
const dest = '/tmp/' + filename;
const dest = `/tmp/${filename}`;middleBrick also provides compliance mapping, showing how Zip Slip vulnerabilities relate to OWASP API Top 10 (A4: Insecure Design) and other frameworks relevant to DynamoDB applications.
Dynamodb-Specific Remediation
Remediating Zip Slip in DynamoDB-integrated applications requires a defense-in-depth approach combining safe extraction libraries, path validation, and secure file handling practices.
The most effective remediation is using libraries that automatically prevent path traversal. For Node.js applications, the decompress library with validation or the adm-zip library with path checking provides built-in protection:
const AWS = require('aws-sdk');
const { createReadStream } = require('fs');
const decompress = require('decompress');
const { DynamoDB } = require('aws-sdk');
exports.handler = async (event) => {
const s3 = new AWS.S3();
const dynamodb = new AWS.DynamoDB();
// Download ZIP from S3
const zipStream = s3.getObject({
Bucket: event.bucket,
Key: event.key
}).createReadStream();
// Safe extraction with path validation
const tempDir = '/tmp/extracted';
await decompress(zipStream, tempDir, {
strip: 1, // Remove top-level directory
filter: (file) => {
// Validate file paths
if (file.path.includes('..') || file.path.startsWith('/') || file.path.startsWith('\')) {
throw new Error('Invalid file path in archive');
}
return true;
}
});
// Process files safely
const files = await fs.readdir(tempDir);
for (const file of files) {
if (file.endsWith('.csv')) {
const csvData = fs.readFileSync(`${tempDir}/${file}`, 'utf8');
const items = parseCSV(csvData);
// Batch write to DynamoDB for efficiency
const batchRequests = items.map(item => ({
PutRequest: {
Item: AWS.DynamoDB.Converter.marshall(item)
}
}));
// Write in batches of 25 (DynamoDB limit)
for (let i = 0; i < batchRequests.length; i += 25) {
await dynamodb.batchWriteItem({
RequestItems: {
'UserData': batchRequests.slice(i, i + 25)
}
}).promise();
}
}
}
return { success: true };
};For Python applications using boto3 and DynamoDB, implement explicit path validation:
import boto3
import zipfile
import os
import re
from pathlib import Path
def is_safe_path(base_dir, target_path):
"""Validate that target_path is within base_dir"""
base_path = Path(base_dir).resolve()
target_path = Path(target_path).resolve()
try:
target_path.relative_to(base_path)
return True
except ValueError:
return False
def restore_backup(zip_path, dynamodb_table):
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(dynamodb_table)
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
for entry in zip_ref.infolist():
# Validate path - reject if traversal detected
if '..' in entry.filename or entry.filename.startswith('/') or entry.filename.startswith('\\'):
raise ValueError(f'Invalid file path: {entry.filename}')
# Construct safe destination path
dest_path = os.path.join('/restore', entry.filename)
if not is_safe_path('/restore', dest_path):
raise ValueError(f'Path traversal detected: {entry.filename}')
# Extract safely
zip_ref.extract(entry, '/restore')
# Store metadata in DynamoDB
table.put_item(
Item={
'file_path': dest_path,
'size': entry.file_size,
'timestamp': entry.date_time.isoformat(),
'valid': True
}
)
return 'Backup restored'Additional remediation strategies include:
- Content-Type validation: Verify that uploaded files are actually ZIP archives using magic bytes or file signatures before processing
- Size limits: Implement maximum archive sizes to prevent resource exhaustion attacks
- Directory isolation: Use unique temporary directories for each extraction to prevent conflicts
- Monitoring: Log and alert on file operations that attempt to write outside allowed directories
- Runtime scanning: Use middleBrick's continuous monitoring to detect if Zip Slip vulnerabilities are reintroduced during development
For backup/restore functionality specifically, consider implementing checksum verification and digital signatures to ensure archive integrity before extraction. This prevents both Zip Slip and malicious archive injection.
middleBrick's remediation guidance for Zip Slip in DynamoDB contexts includes specific recommendations for Lambda functions, containerized applications, and microservices that interact with DynamoDB tables. The scanner provides severity-based prioritization, helping teams focus on the most critical vulnerabilities first.