Zip Slip on Azure
How Zip Slip Manifests in Azure
Zip Slip in Azure environments typically occurs when applications process uploaded ZIP files without proper path validation. Azure Functions, Logic Apps, and Web Apps are common targets where this vulnerability can lead to arbitrary file write, code execution, or service disruption.
The attack pattern follows a predictable sequence: an attacker crafts a ZIP archive containing files with malicious path traversal sequences like ../../ or Windows-style .. arget.txt. When the Azure application extracts these files using Node.js's adm-zip, yauzl, or similar libraries without sanitization, the files are written outside the intended directory.
In Azure Functions, this often appears in file upload scenarios where users submit ZIP archives for processing. Consider this vulnerable Azure Function code:
const admZip = require('adm-zip');
module.exports = async function (context, req) {
const zipBuffer = req.body;
const zip = new admZip(zipBuffer);
// VULNERABLE: No path validation
zip.extractAllTo("/tmp/uploads", true);
context.res = { body: "Upload processed" };
return context.res;
};An attacker could upload a ZIP containing ../../../../../etc/passwd (Linux) or ../../../../windows/system32/calc.exe (Windows), which would be extracted to the host system's root directory. On Azure's Linux-based Functions, this could expose system files or overwrite critical binaries.
Azure Logic Apps face similar risks when processing attachments or file content from HTTP triggers. The vulnerability becomes more severe when combined with Azure's storage permissions—if the function has write access to Azure Blob Storage or Azure Files, attackers could overwrite application code, configuration files, or database backups.
Azure App Service on Windows presents unique Zip Slip scenarios due to path separator differences. The same traversal sequences work, but attackers might target ..in, ..
ode_modules, or .. emp directories where application code executes. Azure's default file permissions sometimes allow broader write access than developers expect, especially in development slots or during deployment.
Container-based Azure services add another layer: if a ZIP extraction vulnerability exists in a container, attackers could write to shared volumes or escape to the host filesystem if container isolation is misconfigured. Azure Container Instances and Azure Kubernetes Service deployments must validate ZIP contents before extraction to prevent lateral movement within the cluster.
The Azure-specific context matters because many Azure services use shared infrastructure. A successful Zip Slip in one function could affect other functions in the same consumption plan, especially if they share storage mounts or network access patterns.
Azure-Specific Detection
Detecting Zip Slip in Azure requires both static analysis and runtime monitoring. Azure Security Center and Defender for Cloud can flag suspicious file operations, but they often miss the initial ZIP extraction vulnerability.
middleBrick's Azure-specific scanning identifies Zip Slip by testing unauthenticated endpoints with crafted ZIP payloads containing path traversal sequences. The scanner verifies whether the Azure service extracts files to unintended locations by checking for specific indicators:
- Files appearing outside the expected extraction directory
- Access denied errors when attempting traversal (indicates attempted exploitation)
- Unexpected file creation in system directories
- Changes to file timestamps outside normal operation windows
For Azure Functions specifically, middleBrick tests against common extraction patterns using adm-zip, yauzl, and native Node.js zlib implementations. The scanner crafts ZIP files with varying traversal depths and path formats to bypass basic validation attempts.
Azure DevOps pipelines can integrate Zip Slip detection using middleBrick's GitHub Action. Add this to your azure-pipelines.yml:
- task: middleBrick@1
inputs:
targetUrl: '$(System.CollectionUri)/$(System.TeamProject)/_apis/build/builds?api-version=6.0'
failOnScore: 'D'
scanType: 'api'This scans your Azure DevOps API endpoints before deployment, catching Zip Slip vulnerabilities in build processes or extension APIs.
Azure Monitor Logs provide runtime detection by tracking file operations. Create an alert rule that triggers when files are written to unexpected locations:
let suspicious_paths = dynamic([
"c:\\windows\\system32*",
"/etc/passwd",
"/root/*",
"..\\..\\..\\..\\..\\"
]);
AzureDiagnostics
| where Category == "FunctionAppLogs"
| where Message has "write" or Message has "create"
| where Path startswith_any(suspicious_paths)Application Insights can also detect anomalous file operations by monitoring for ZIP extraction operations that take longer than expected or occur outside normal business hours, which might indicate automated exploitation attempts.
For Azure Kubernetes Service, use kubectl with custom admission controllers to scan incoming ZIP files before they reach your application pods. The controller can reject ZIP archives containing suspicious path patterns or excessive directory traversal attempts.
Azure-Specific Remediation
Azure provides several native approaches to prevent Zip Slip vulnerabilities. The most effective remediation combines path validation with Azure's built-in security features.
For Azure Functions, implement strict path sanitization before extraction:
const admZip = require('adm-zip');
const path = require('path');
const crypto = require('crypto');
function sanitizeZipEntry(entryName) {
// Remove any path traversal sequences
const sanitized = entryName.replace(/\.\./g, '')
.replace(/\\/g, '/') // Normalize Windows paths
.replace(/^\//, ''); // Remove leading slash
// Verify the sanitized path doesn't escape the target directory
const targetDir = "/tmp/uploads/";
const resolved = path.resolve(targetDir, sanitized);
if (!resolved.startsWith(targetDir)) {
throw new Error('Zip Slip attempt detected');
}
return resolved;
}
module.exports = async function (context, req) {
const zipBuffer = req.body;
const zip = new admZip(zipBuffer);
// Create a unique directory for this extraction
const extractionDir = `/tmp/uploads/${crypto.randomBytes(8).toString('hex')}`;
// Process entries individually with validation
zip.getEntries().forEach(entry => {
const safePath = sanitizeZipEntry(entry.entryName);
const relativePath = path.relative(extractionDir, safePath);
// Write file only if validation passes
const fileBuffer = entry.getData();
const fs = require('fs');
const dir = path.dirname(safePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(safePath, fileBuffer);
});
context.res = { body: "Upload processed securely" };
return context.res;
};This approach validates each file path before extraction, ensuring no file can be written outside the designated upload directory. The random subdirectory prevents conflicts between concurrent uploads.
Azure App Service on Linux benefits from using Azure Storage for file operations instead of local filesystem access. Store uploaded ZIP files in Azure Blob Storage, then use Azure Functions to process them in memory without writing to the host filesystem:
const { BlobServiceClient } = require('@azure/storage-blob');
module.exports = async function (context, req) {
const blobServiceClient = BlobServiceClient.fromConnectionString(process.env.AZURE_STORAGE_CONNECTION_STRING);
const containerClient = blobServiceClient.getContainerClient('uploads');
// Stream ZIP directly from Blob Storage without local extraction
const blockBlobClient = containerClient.getBlockBlobClient(req.query.blobName);
const downloadResponse = await blockBlobClient.download();
const zipBuffer = await streamToBuffer(downloadResponse.readableStreamBody);
// Process ZIP in memory or use a sandboxed extraction library
// ... (processing logic)
context.res = { body: "Processed from secure storage" };
return context.res;
};
async function streamToBuffer(readableStream) {
return new Promise((resolve, reject) => {
const chunks = [];
readableStream.on('data', (data) => chunks.push(data));
readableStream.on('end', () => resolve(Buffer.concat(chunks)));
readableStream.on('error', reject);
});
}Azure Security Center's Just-In-Time VM access can limit file system permissions for Azure Functions running on dedicated plans, reducing the impact of successful Zip Slip exploitation by restricting write access to specific directories only.
For Azure Logic Apps, use the built-in ZIP actions with validation enabled. Logic Apps automatically validates file paths when using the 'Create ZIP' and 'Extract ZIP' actions, but custom connectors require manual validation similar to the Azure Functions approach above.
Implement Azure Policy to enforce security standards across your Azure environment. Create a policy that audits functions and apps that handle file uploads without proper validation:
{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Web/sites"
},
{
"field": "kind",
"contains": "functionapp"
}
]
},
"then": {
"effect": "audit",
"details": {
"type": "Microsoft.Web/sites/config"
}
}
}This policy helps identify Azure Functions that may need security review for file handling operations.
Frequently Asked Questions
Can Zip Slip in Azure Functions lead to remote code execution?
node_modules, bin, or custom plugin directories. An attacker could overwrite JavaScript files or executable binaries. The risk increases if the function runs with elevated privileges or has access to shared storage volumes.