Prototype Pollution on Azure
How Prototype Pollution Manifests in Azure
Prototype pollution in Azure environments typically occurs through deserialization of untrusted data, particularly when handling configuration files, API requests, or user-supplied parameters that interact with Azure services. This vulnerability allows attackers to modify JavaScript object prototypes, potentially leading to denial of service, information disclosure, or remote code execution.
In Azure Functions, prototype pollution often emerges when processing HTTP triggers that accept JSON payloads. Consider this vulnerable Azure Function code:
module.exports = async function (context, req) {
const config = JSON.parse(req.body);
const { options } = config;
// Vulnerable: options could be polluted
return {
status: 200,
body: processOptions(options)
};
};The issue arises because Node.js allows prototype chain manipulation through objects. An attacker could send:
{
"options": {
"__proto__.isAdmin": true
}
}This would add an isAdmin property to Object.prototype, affecting all objects in the application.
Azure App Service applications face similar risks when using Express middleware for request parsing. The built-in body-parser middleware can be vulnerable if not properly configured:
const express = require('express');
const app = express();
app.use(express.json()); // Vulnerable by default
app.post('/azure-config', (req, res) => {
const config = req.body;
// If config contains __proto__ or constructor properties,
// prototype pollution occurs
applyAzureConfig(config);
Azure Logic Apps that process JSON payloads from HTTP triggers can also be affected. When Logic Apps use custom connectors or HTTP actions to call APIs, malicious payloads can exploit prototype pollution in downstream services.
Azure API Management policies sometimes inadvertently introduce prototype pollution when transforming JSON payloads. Consider this policy:
<policies>
<on-error>
<set-variable name="error" value="@{(string)context.LastError.Message}" />
</on-error>
<return-response>
<set-status code="@((int)context.Response.StatusCode)" />
<set-body>
{
"message": "@context.Variables["error"]",
"__proto__.polluted": true
}
</set-body>
</return-response>
</policies>While this example shows the vulnerability in policy definition, the actual risk comes from how the response is processed by client applications.
Azure Service Bus message processing can also be vulnerable. When applications deserialize messages from Service Bus queues without proper validation, prototype pollution can occur:
const { ServiceBusClient } = require('@azure/service-bus');
const client = new ServiceBusClient(connectionString);
const receiver = client.createReceiver(queueName);
const processMessage = async (message) => {
const data = JSON.parse(message.body);
// No validation of data properties
applyConfiguration(data);
};The common thread across these Azure services is the lack of input validation and sanitization when processing untrusted JSON data that could contain prototype pollution payloads.
Azure-Specific Detection
Detecting prototype pollution in Azure environments requires both static code analysis and dynamic runtime scanning. For Azure Functions and App Services, the middleBrick API security scanner can identify prototype pollution vulnerabilities by analyzing the attack surface and testing for common pollution patterns.
middleBrick's black-box scanning approach tests Azure endpoints without requiring credentials or source code access. The scanner sends specially crafted payloads to detect prototype pollution:
POST /api/azure-function HTTP/1.1
Host: example.azurewebsites.net
Content-Type: application/json
{
"test": {
"__proto__.polluted": "prototype pollution test",
"constructor.prototype.polluted": "constructor pollution"
}
}The scanner then analyzes the response to determine if the payload successfully modified object prototypes. middleBrick tests for 12 security categories including Authentication, BOLA/IDOR, and Input Validation, with prototype pollution falling under the broader input validation category.
For Azure Logic Apps, detection involves examining HTTP trigger configurations and any custom connectors that process JSON data. The middleBrick CLI tool can scan Logic App endpoints:
npx middlebrick scan https://example.azurewebsites.net/api/logicapp-triggerAzure API Management policies can be analyzed using middleBrick's OpenAPI/Swagger spec analysis. The scanner resolves $ref definitions and identifies policy configurations that might introduce prototype pollution risks.
Static analysis tools specific to Node.js can also detect prototype pollution patterns in Azure Functions code. Tools like ESLint with the no-prototype-builtins rule can catch unsafe prototype usage:
// .eslintrc.js
module.exports = {
rules: {
'no-prototype-builtins': 'error'
}
};Runtime detection in Azure environments can be implemented using middleware that validates incoming JSON payloads:
const hasPrototypePollution = (obj) => {
const dangerousKeys = ['__proto__', 'constructor', 'prototype'];
const stack = [obj];
while (stack.length) {
const current = stack.pop();
for (const key of Object.keys(current)) {
if (dangerousKeys.includes(key)) {
return true;
}
if (typeof current[key] === 'object' && current[key] !== null) {
stack.push(current[key]);
}
}
}
return false;
};Azure Application Insights can be configured to log and alert on prototype pollution attempts by monitoring for unusual object property patterns in incoming requests.
For Azure Service Bus, message validation middleware should inspect payloads before processing:
const validateMessage = (message) => {
if (typeof message.body !== 'object' || message.body === null) {
return false;
}
return !hasPrototypePollution(message.body);
};middleBrick's continuous monitoring capability (available in Pro and Enterprise tiers) can regularly scan Azure endpoints to detect newly introduced prototype pollution vulnerabilities as code changes over time.
Azure-Specific Remediation
Remediating prototype pollution in Azure environments requires a multi-layered approach combining input validation, safe parsing, and secure coding practices. For Azure Functions and App Services, the primary defense is validating and sanitizing all incoming JSON data.
Using a secure JSON parser that prevents prototype pollution is the first line of defense:
const safeJSONParse = (str) => {
try {
const parsed = JSON.parse(str, (key, value) => {
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
throw new Error('Prototype pollution attempt detected');
}
return value;
});
return parsed;
} catch (error) {
throw new Error('Invalid JSON or prototype pollution attempt');
}
};Apply this safe parsing in Azure Functions:
module.exports = async function (context, req) {
let config;
try {
config = safeJSONParse(req.body);
} catch (error) {
return {
status: 400,
body: { error: 'Invalid input' }
};
}
// Safe to use config
};For Azure Logic Apps, use the built-in schema validation to define strict input formats:
<triggers>
<http-request>
<schema>
{
"type": "object",
"properties": {
"username": { "type": "string" },
"settings": {
"type": "object",
"properties": {
"theme": { "type": "string" }
},
"additionalProperties": false
}
},
"additionalProperties": false
}
</schema>
</http-request>
</triggers>Azure API Management can use validate-jwt policies to ensure only expected properties are present:
<validate-jwt header-name="Authorization" failed-validation-httpcode="401">
<openid-config url="https://example.com/.well-known/openid-configuration" />
<required-claims>
<claim name="aud" match="any">
<value>expected-audience</value>
</claim>
</required-claims>
</validate-jwt>For Azure Service Bus, implement message validation before processing:
const validateAzureServiceBusMessage = (message) => {
const schema = {
type: 'object',
properties: {
userId: { type: 'string' },
action: { type: 'string', enum: ['create', 'update', 'delete'] }
},
required: ['userId', 'action'],
additionalProperties: false
};
return validate(schema, message.body);
};Using TypeScript in Azure Functions provides compile-time protection against prototype pollution:
interface AzureConfig {
userId: string;
settings?: {
theme?: string;
notifications?: boolean;
};
}
const processConfig = (config: AzureConfig) => {
// TypeScript ensures only defined properties exist
};For Azure App Service, implement Express middleware that sanitizes request bodies:
const prototypePollutionSanitizer = (obj) => {
const dangerousKeys = ['__proto__', 'constructor', 'prototype'];
const sanitize = (currentObj) => {
if (Array.isArray(currentObj)) {
return currentObj.map(sanitize);
} else if (typeof currentObj === 'object' && currentObj !== null) {
const sanitized = {};
for (const [key, value] of Object.entries(currentObj)) {
if (dangerousKeys.includes(key)) {
continue; // Skip dangerous keys
}
sanitized[key] = sanitize(value);
}
return sanitized;
}
return currentObj;
};
return sanitize(obj);
};Azure Application Gateway WAF rules can be configured to block requests containing prototype pollution patterns:
# Azure Application Gateway WAF Policy
<Rule>
<Match>
<MatchVariable>RequestBodyJson</MatchVariable>
<Operator>Contains</Operator>
<Value>__proto__</Value>
</Match>
<Action>Block</Action>
</Rule>Regular security scanning with middleBrick (Pro tier includes continuous monitoring) ensures prototype pollution vulnerabilities are detected as they're introduced during development.