Sql Injection on Azure
How Sql Injection Manifests in Azure
In Azure environments, SQL injection typically occurs when user‑supplied data is concatenated directly into a Transact‑SQL string that is sent to Azure SQL Database, Azure SQL Managed Instance, Azure Database for MySQL, or Azure Database for PostgreSQL. Common entry points include:
- Azure Functions (HTTP trigger) that receive query parameters or JSON payloads and build a query string with string interpolation.
- ASP.NET Core APIs hosted in Azure App Service or Azure Container Apps that use
SqlCommandwithCommandTextbuilt from user input. - Logic Apps or Power Automate flows that call a stored procedure via the SQL connector and pass dynamic values without parameterization.
- Azure Static Web Apps with a backend API that forwards form data to a SQL endpoint.
An attacker can inject payloads such as ' OR 1=1-- to bypass authentication, ; DROP TABLE Users; to cause data loss, or UNION SELECT @@version, NULL, NULL-- to extract database metadata. These patterns map to OWASP API Security Top 10 A3: Injection and are frequently seen in real‑world breaches (e.g., CVE‑2021‑26084 affecting Confluence, where improper input handling allowed SQL injection).
Because Azure services often expose endpoints over the public internet, unauthenticated scanners like middleBrick can reach the same attack surface an external attacker would, testing for these injection vectors without any credentials or agents.
Azure-Specific Detection
Detecting SQL injection in Azure workloads involves both automated scanning and manual inspection of logs and code. middleBrick performs a black‑box, unauthenticated scan of the exposed API surface, sending a series of crafted payloads to each endpoint and analyzing responses for signs of successful injection (e.g., error messages containing SQL syntax, unexpected data in the response body, or changes in response time).
To run a scan with middleBrick:
# Install the CLI (npm)
npm i -g middlebrick
# Scan an Azure-hosted API
middlebrick scan https://myapi.azurewebsites.net/api/products
The tool returns a JSON report that includes:
- A risk score (A–F) and a breakdown per OWASP category.
- Findings labeled "SQL Injection" with severity, the exact payload used, and the affected endpoint.
- Remediation guidance referencing Azure‑specific fixes (parameterized queries, use of Entity Framework Core, etc.).
Beyond middleBrick, you can enable:
- Azure Monitor diagnostics for Azure SQL Database to capture
error_number208 (invalid object name) or 102 (incorrect syntax) that often surface when injection attempts fail. - Azure Application Insights custom telemetry to log exceptions from
SqlException. - Code review practices that look for string concatenation or interpolation in
SqlCommand.CommandText,ExecuteReader, or raw SQL strings passed toDbContext.Database.ExecuteSqlRaw.
Combining automated scanning with these telemetry sources gives visibility into both successful and blocked injection attempts.
Azure-Specific Remediation
The most reliable defense against SQL injection is to never build SQL strings from untrusted input. Azure provides native libraries that make parameterized queries straightforward.
C# (Azure Functions / ASP.NET Core)
Replace concatenated queries with SqlParameter objects:
using System.Data;
using System.Data.SqlClient;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
public static class GetProduct
{
[Function("GetProduct")]
public static async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "products/{id}")] HttpRequestData req,
FunctionContext executionContext)
{
string idStr = req.Route.Parameters["id"];
if (!int.TryParse(idStr, out int productId))
{
var badResp = req.CreateResponse(System.Net.HttpStatusCode.BadRequest);
await badResp.WriteStringAsync("Invalid product id");
return badResp;
}
using var conn = new SqlConnection(Environment.GetEnvironmentVariable("SQL_CONNECTION_STRING"));
await conn.OpenAsync();
using var cmd = new SqlCommand("SELECT Name, Price FROM Products WHERE Id = @Id", conn);
cmd.Parameters.Add("@Id", SqlDbType.Int).Value = productId;
using var reader = await cmd.ExecuteReaderAsync();
if (!reader.Read())
{
var notFound = req.CreateResponse(System.Net.HttpStatusCode.NotFound);
await notFound.WriteStringAsync("Product not found");
return notFound;
}
var product = new { Name = reader.GetString(0), Price = reader.GetDecimal(1) };
var jsonResp = req.CreateResponse(System.Net.HttpStatusCode.OK);
await jsonResp.WriteAsJsonAsync(product);
return jsonResp;
}
}
Notice that the user‑supplied id is validated, parsed to an integer, and then passed as a parameter. No string interpolation occurs.
Node.js (Azure Functions v4)
Using the mssql package with parameterized queries:
const sql = require('mssql');
async function getProduct(context, req) {
const id = parseInt(req.params.id, 10);
if (isNaN(id)) {
context.res = { status: 400, body: 'Invalid product id' };
return;
}
try {
await sql.connect(process.env.SQL_CONNECTION_STRING);
const result = await sql.query`
SELECT Name, Price FROM Products WHERE Id = ${id}
`; // note: the mssql template tag automatically parameterizes
if (result.recordset.length === 0) {
context.res = { status: 404, body: 'Product not found' };
return;
}
context.res = { status: 200, body: result.recordset[0] };
} catch (err) {
context.log.error(err);
context.res = { status: 500, body: 'Internal error' };
}
}
The mssql library treats the template literal as a parameterized query, preventing injection even if the input contains SQL syntax.
Azure SQL Managed Instance – Using Entity Framework Core
When using EF Core, always use LINQ or FromSqlRaw with parameters:
var product = await _context.Products .FromSqlRaw("SELECT * FROM Products WHERE Id = {0}", productId) .AsNoTracking() .FirstOrDefaultAsync();EF Core automatically substitutes the placeholder with a parameter, eliminating injection risk.
By adopting these patterns—input validation, type‑safe parsing, and parameterized APIs—you remove the root cause of SQL injection in Azure‑hosted applications.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |