A security firm recently ran Sable against the public-facing surface of an AI security platform during a client engagement. The application exposed three service APIs through Swagger: a chat API, a trust-score API, and a scanner API. Sable focused on the scanner service after identifying POST /command_scan_private, an endpoint that accepted a user-controlled url, header_template, payload_template, tenant_id, username, and probe-related fields. Any scanner feature that accepts a URL and makes a backend request is immediately interesting, because the backend becomes the requester. Sable's goal was to determine whether this endpoint could be turned into a readable SSRF. Sable found several issues during the engagement, but the most interesting chain came from the scanner API, where a private endpoint testing feature became a path to Azure managed identity token exposure.

Finding the Request Primitive

Sable's first attempts failed with Probe type is required.

None
Sable's first SSRF attempts reached /command_scan_private, but the scanner rejected them with Probe type is required. The error showed the endpoint was reachable and that Sable needed to infer the real request shape before the backend would launch a scan.

That error was useful because it confirmed the endpoint was reachable and that the request shape was close. The Swagger surface suggested a parameter named probe, but the backend expected probe_type.

None

After testing the schema, Sable supplied probe_type=tap, and the endpoint returned {"pid":457}.

None
None

That meant the scanner had launched a backend job using attacker-controlled input.

Sable then looked for the job output and found GET /scan_progress/{pid}.

None
Polling /scan_progress/{pid} exposed _raw_output from the backend scanner process, including probe execution details and target response information. That gave Sable a readable response channel and confirmed the finding was no longer blind SSRF.

The response included _raw_output, which exposed backend scanner details from the running job, including filesystem paths and target response data. That gave the finding a clean proof-of-concept structure: /command_scan_private triggered the server-side request, and /scan_progress/{pid} returned the evidence.

Confirming Internal Reachability

Sable tested Azure's instance metadata endpoint at http://169.254.169.254/metadata/identity/oauth2/token. The first response did not return a token because the scanner was forcing a POST while Azure IMDS expects GET. The response still proved impact: Azure returned Request Method not supported for the API, which meant the backend had reached the link-local metadata service from inside the cloud environment.

None
Sable used the scanner's run inventory to identify the backend jobs created by its private endpoint tests. The failed scan reports showed that the scanner was processing the submitted URLs and writing artifacts that could be reviewed

Sable also tested internal service names and localhost paths. Internal hosts such as http://chat-[REDACTED].[REDACTED].com/users and localhost endpoints returned FastAPI-style 405 Method Not Allowed responses through _raw_output. The scanner was reaching internal services and reflecting their responses back to the user. At that point, SSRF was confirmed. The remaining question was whether Sable could work around the forced POST and retrieve metadata tokens.

None
Sable confirmed that the scanner could reach internal service names and localhost endpoints from the backend environment. The reflected 405 Method Not Allowed responses showed that the requests were hitting real internal application services.

Bypassing the POST Limitation

Sable treated the POST-only behavior as a constraint to work around. Azure's token endpoint requires GET, and HTTP redirect behavior can change the request method depending on the status code. Sable tested redirect handling and used a public redirector that returned a 303 See Other response pointing to Azure IMDS. With the scanner's HTTP client behavior, the original POST followed the 303 as a GET.

None
Sable reasons through the POST limitation and decides to test whether redirect behavior can turn the SSRF into an IMDS token request.

didThe chain became: scanner POST to public redirector, 303 redirect to Azure IMDS, scanner follows redirect as GET. The redirected target was http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/. This turned a constrained SSRF into a credential-exfiltration path.

None
Sable confirmed the redirect behavior: a 307 preserved the scanner's POST and failed, while a 302 reached Azure IMDS successfully and returned a managed identity token.

Exfiltrating and Validating Cloud Tokens

Once the redirect chain worked, Azure IMDS returned a managed identity bearer token. The scanner captured the response and reflected it through _raw_output in /scan_progress/{pid}. Sable decoded the token and confirmed it belonged to an Azure managed identity attached to the AKS/VMSS environment. It repeated the same flow for Azure Resource Manager, Microsoft Graph, Key Vault, and Storage audiences.

None

Sable then validated the Azure Resource Manager token against Azure APIs.

None

Azure returned 403 AuthorizationFailed, which proved the token was valid but underprivileged for the attempted action. A 401 would have meant the token failed authentication. The tested identity had limited RBAC, so immediate blast radius was constrained, but the boundary had already failed. Any future Key Vault, Storage, Graph, AKS, or Contributor permissions on that identity would become reachable through the same chain.

Scaling Professional Security Testing

This is where offensive AI becomes operationally useful for security firms. Sable moved through the workflow like a skilled consultant: recon, endpoint selection, schema testing, request shaping, response-channel discovery, impact validation, cloud-specific exploitation, and evidence collection. That work usually consumes senior tester time. In this case, Sable compressed it into an autonomous chain and produced proof-of-concept evidence the team could review, verify, and deliver.

The economics of an engagement change when an agent can run this kind of reasoning in parallel. Consultants can spend less time chasing every suspicious endpoint from a blank terminal and more time on judgment, remediation guidance, and client communication. Sable builds professional-grade PoCs with the request path, response path, exploitation logic, and impact clearly shown. Here, that meant going from a Swagger URL parameter to confirmed Azure managed identity token exposure.

The result is more coverage in fewer hours, faster validation of real issues, and stronger evidence for the final report. A tester can review the full thought trace, understand why Sable made each decision, and decide what belongs in the client-facing writeup. Strong security teams can scale their best work: more vulnerabilities found, fewer dead ends, and professional proof of impact generated faster.

Learn more about Sable

Book a demo