Quick Answer: An Azure Logic Apps vulnerability in API Connections let an attacker reference a connection they don't own and make the shared broker act with the victim's stored credentials. The researcher used this to reach Key Vaults and Azure SQL databases in other tenants. Microsoft fixed the reported issues, but each fix blocked a symptom rather than the trust flaw underneath.

Most people assume a managed cloud connector is a clean boundary between a workflow and the services it touches. It isn't always. A researcher who spent months on Azure's API Connection layer found that the boundary was enforced mostly by input validation, and that validation kept missing cases. The result was a series of cross-tenant compromises worth $200,000 in bounties, reported across multiple rounds. Here's how the pattern worked, why the fixes kept falling short, and what you can check in your own environment.

How API Connections Create a Shared Trust Boundary

Azure Logic Apps uses API Connections to store the credentials a workflow needs to talk to external services. A workflow doesn't hold a Key Vault secret or a SQL password itself. It points to a connection resource, and a shared Azure API Management (APIM) instance exchanges the connection's stored key or OAuth token for a backend credential and makes the call.

The flow is simple: the logic app queries the shared APIM instance, APIM checks the OpenAPI (Swagger) definition to confirm the action is valid, the input key is swapped for the configured backend token, and the call goes out. Microsoft's own architecture diagram shows this clearly, and it's the reason the design is easy to reason about.

The diagram omits one thing. Azure Resource Manager (ARM) can call the APIM layer directly through the DynamicInvoke and /extensions/proxy/ endpoints. ARM is the management plane with broad rights across a subscription, so anything that reaches APIM through ARM inherits that reach.

Here's the root problem in one sentence: the broker trusts the connection reference in the request, and the stored credential behind that reference is what does the damage. Once you control the reference, you control whose credential gets used.

This is the core of what the researcher calls a "single root cause." Each vulnerability was a different way to point the broker at a connection that wasn't yours.

The First Cross-Tenant Read Through Path Traversal

The first finding was a classic path traversal, catalogued as CWE-22. By putting encoded ../ sequences into the path of a DynamicInvoke request, the researcher steered an APIM call away from the intended backend resource and toward a Key Vault in another tenant. The secret came back in the response.

Path traversal is one of the oldest bugs in the book, and it's still common because it hides in APIs that build URLs from user input. Here the attacker's own connection was legitimate. What was illegitimate was the path it was allowed to reach, and the broker's credential had rights well beyond what the caller should ever touch.

Consider the mismatch. The caller owns connection A. The broker holds credentials for connection A and, because of the trust model, can use the backend rights that belong to connection B. A path parameter that should be scoped to A's resource ends up reaching B. Nothing in the chain verifies that the resolved path belongs to the connection that was authenticated.

The practical lesson for defenders: authorization that depends on "the request came from a valid connection" is not authorization for the resource being touched. You need the check at the resource, not at the front door.

Why the First Fix Didn't Hold

Microsoft fixed the reported path issue, and the researcher saw a new error when retrying. The fix restricted which paths were allowed. It did not change the underlying behavior of the broker, which still held credentials broader than any single caller should have.

This is the trap of a blocklist or path-allowlist fix. It addresses the payload you showed the vendor, not the trust assumption that made the payload useful. The researcher made this point directly: the fix blocked a route, and the trust problem was still there.

That's not a criticism unique to Microsoft. It's the default outcome of patching a validation bug. If you find a path traversal in a broker, ask two questions before you call it fixed:

  1. Does the fix change which credential the broker uses, or only which strings it accepts?
  2. Would a different encoding, a different endpoint, or a different parameter name reach the same resource?

Both questions matter because the second one is where the researcher went next.

Undocumented Endpoints and the Blocklist Gap

Digging through the ARM resource provider code, the researcher found that DynamicInvoke was not the only public function. There were four related functions, including DynamicList, that were undocumented and reachable along the same path. The researcher found no reference to them in any public documentation.

Reachable but undocumented is a dangerous combination. The security review that protected DynamicInvoke didn't automatically apply to its siblings. The DynamicList variant accepted path parameters in a different structure, which meant the same class of traversal could reach a SQL database, not just a Key Vault. The researcher demonstrated a conceptual cross-tenant write path against a victim's Azure SQL server through this route.

Microsoft's response to that report was to block the endpoints entirely. That stops this route, but it doesn't remove the broker's broad credential scope, so the researcher judged it a blunt fix. If those endpoints are ever re-exposed, the same behavior would likely return.

Here's the actionable insight for engineers building internal APIs: enumerate every route that reaches the same backend code, not just the one in your docs. Sibling functions with shared implementations are the most common place where a fix goes missing.

Consumption vs. Standard: The Identity Gap

The most important finding came from comparing how connections are created in the two Logic Apps hosting models. Consumption logic apps run in a multi-tenant shared pool. Standard logic apps run on a dedicated host that you control.

The researcher found that Consumption connections are created as Version 1 API Connections, while Standard logic apps create Version 2 connections. In the Standard model, you authorize a specific logic app's managed identity against the connection, so the platform knows which workload is allowed to use it.

In the Consumption model there is no per-app identity to authorize, because you don't control the host. The platform's answer was, in effect, that a Consumption logic app doesn't get an authorization step. The researcher's reasoning was that this implies implicit access to every Version 1 connection, with input validation as the only barrier.

AspectConsumption (Version 1 connections)Standard (Version 2 connections)
Hosting modelShared multi-tenant poolDedicated host you control
Caller identityNo per-app managed identity to authorizeManaged identity authorized per logic app
Who can reference the connectionAny Consumption workflow that can name it, subject to runtime checksOnly identities explicitly granted access
Main safeguardRuntime validation of connection ownershipIdentity-based authorization

Here's where most people's mental model breaks. They assume that "owning" a connection is the access control. In Version 1, ownership was checked by runtime validation rather than by a durable identity grant. Validation logic is only as good as its coverage, and the researcher found gaps.

This next part matters more than it looks: the difference isn't a bug in itself. It's a design choice that moved the security decision from an identity grant to a validation function. When you make that move, every new input field becomes a potential bypass.

The Runtime URL Override

The last route involved a workflow parameter, host.api.RuntimeUrl. After validating the connection named in host.connection, the runtime accepted an override for the host the request would go to, as long as the host ended with azure-apihub.net. The override also carried the Authorization header.

The researcher's reasoning was simple: if the runtime validates the connection but then lets the definition choose a different endpoint, the validation covers the wrong thing. The check confirmed the caller had a connection, not that the destination belonged to that connection.

Microsoft's fix added a check that the runtime URL path must match the expected endpoint for the referenced connection. The error message the researcher received explained this requirement explicitly. That's the right fix shape: tie the destination to the authenticated resource rather than to a suffix match on the domain.

Most guides skip this point, but it's the most useful one for anyone reviewing a similar system. A domain-suffix check is not an authorization check. Tying the destination to the resource identity is.

Where Input Validation Keeps Losing

Put the five findings together and the pattern is clear. Each vulnerability used the same primitive: a request that named a connection or resource the caller shouldn't reach, and a broker that acted on that name with stored credentials. Each fix narrowed the input rather than tightening the trust decision.

Here's the counter-intuitive takeaway. Many teams treat validation bugs as isolated defects and patch them one at a time. That feels efficient, but it means your security depends on finding every edge case, and the researcher's experience suggests that's extremely hard. The more inputs a system accepts, the more places the check can drift from the intent.

There's a fair counterargument. Input validation is still necessary, and the vendor can't realistically remove all shared-broker designs overnight. Blocking endpoints and tightening paths reduces risk quickly. The tradeoff is that you're buying time, not closing the design gap.

For defenders building or operating these systems, the broader rule is this: prefer identity-bound authorization at the resource over validation of request fields, and treat any broker that holds credentials for many tenants as a high-value target.

What to Check in Your Own Environment

You don't need to be a vendor to act on this. If you use Azure Logic Apps with API Connections, you can reduce your exposure today.

  1. Inventory your connections and note which hosting model created each one. Version 1 connections on Consumption workflows deserve the closest review.
  2. Scope backend credentials minimally. The researcher noted that API keys and OAuth tokens are often granted far more rights than the workflow needs. Use a dedicated service identity with least-privilege access to the specific Key Vault secret or SQL schema.
  3. Restrict who can create or modify connections through RBAC on the resource group, and review any logic app that accepts externally supplied definitions.
  4. Monitor Key Vault and SQL audit logs for access from unexpected callers or unusual access patterns.

Scoping is the most effective single step. If the stored credential can only read one secret, a successful traversal gets the attacker one secret, not a tenant's worth of data.

Frequently Asked Questions

What is an Azure Logic Apps vulnerability in API Connections?

An Azure Logic Apps vulnerability in API Connections is a flaw that lets a caller use a connection they don't own, causing the shared broker to act with that connection's stored credentials. In the researched cases, this reached Key Vaults and SQL databases in other tenants. The root cause was trust in the connection reference rather than verification at the target resource.

How do I check if my Logic Apps connections are exposed?

Start by listing your API Connections and noting whether each was created by a Consumption or Standard logic app. Confirm that each backend credential has only the rights the workflow needs. Then review Key Vault and SQL audit logs for access from unexpected identities or callers.

Why does path traversal work against Azure APIs?

Path traversal works when a service builds a resource path from user input without confirming the resolved path belongs to the authenticated caller. Encoded sequences like ../ can move the request to a different resource. The defense is to bind authorization to the target resource, not just to the input string.

Is the Azure Logic Apps vulnerability fixed?

According to the researcher's write-up, Microsoft fixed the reported issues. The fixes mostly blocked specific paths, endpoints, and runtime URL formats. The researcher noted that these changes addressed symptoms, and the broader design of shared broker credentials was not changed, so ongoing review is still sensible.

Read the original research at binarysecurity.no, and check your own Logic Apps connections this week. Pick one Version 1 connection, confirm what its backend credential can actually reach, and narrow it to the minimum. Share this with anyone running Azure Logic Apps who's wrestling with the same question: who really controls the credentials behind their workflows?