When a scanner points to one service but the claimed harm happens in another, review the whole request and data path. Pin a revision, choose one actor and protected object, then follow the request through ingress, messages, service calls, authorization decisions, storage and delivery. At each boundary record where the actor, tenant, action and object came from and where they were checked. A trusted network hop or signed message does not automatically authorize the final resource.
The answer changes if an apparently missing check is enforced by a verified upstream decision that is bound to this exact operation, or if another route bypasses that decision. Source code can show how the path is meant to work; deployment routes, policy versions and runtime state may still need separate evidence. Leave those points open rather than calling a source-traced path an executed attack. The OWASP Microservices Security Cheat Sheet distinguishes edge checks from service-level checks and says internal calls also need protection.
Build a boundary map before choosing a verdict
The failure often lies in the handoff, not the line the scanner highlighted. A gateway may authenticate a user but not authorize the selected object. One service may verify permission on a project, then ask a second service to change an object whose owner it never checked. The second service may authenticate the caller service but treat a client-supplied object ID as though it were authorized. A successful internal request can therefore carry the wrong authority all the way to a harmful state change.
For each hop, write down five things:
- Principal: the end user or machine delegation on whose authority this work proceeds.
- Operation: the precise action, such as
delete webhook endpoint, not just “has access.” - Object and tenant: the actual resource owner read from an authoritative record, plus any selector supplied in the request.
- Decision: the check that permits or denies this principal's operation on that object, and where enforcement occurs.
- Continuity: what proof the next service receives, what it validates, and whether it can be replayed for another object or route.
This follows OWASP's authorization patterns guidance: enforcement belongs close enough to the protected resource to consider action, object and tenant. Signed context must be checked for issuer, audience, expiry and applicability; a signature alone does not grant a different resource. The method applies whether the teams use a central policy service, shared library or code in each service.
Illustrative case: one project's action may delete another tenant's webhook
This fictional product lets project administrators remove webhook endpoints belonging to their projects. A staff engineer receives an alert against a webhook service's delete operation. The customer-facing route is DELETE /projects/{project_id}/webhooks/{endpoint_id}. The path is gateway → projects API → webhook service → endpoint store → delivery scheduler. The scanner points at the webhook service, but the engineer needs to know which end user and project authorized the request that reached it.
At one immutable source revision, Mira administers Cedar's project P-Cedar; she has no authority over Harbor's webhook W-Harbor. The illustrative deployment manifest shows the delete route enabled for project administrators, so Mira can invoke it for P-Cedar. Her knowledge of W-Harbor's ID is still an unverified prerequisite. No real service was assessed and no delete request or exploit was performed for this example.
| Boundary | Selector and authority to trace | Illustrative observation | Question before a verdict |
|---|---|---|---|
| Gateway → projects API | Session subject, path project, delete action | Gateway authenticates Mira and routes this action to the projects API. | Does a downstream decision cover the webhook as well as the project? |
| Projects API → webhook service | P-Cedar, client-supplied endpoint ID, service credential |
Projects API confirms Mira may administer P-Cedar, then forwards the supplied endpoint ID in an authenticated internal delete request. |
Does it load the endpoint's owner before forwarding? |
| Webhook service → endpoint store | Caller service, endpoint ID, record owner | Webhook service checks the caller's service credential and retrieves W-Harbor by global ID. The reviewed branch does not compare its Harbor owner with P-Cedar or Mira's authority. |
Does another policy or storage condition enforce that relationship? |
| Endpoint store → delivery scheduler | Deleted marker or endpoint state, delivery target | The reviewed scheduler path excludes deleted endpoints from future delivery. | Was that path active for Harbor in the assessed deployment, and what outcome was actually observed? |
The code supports a narrow candidate: if Mira supplies W-Harbor's ID, the reviewed service path could mark Harbor's endpoint deleted without an ownership comparison in that code. The deployment manifest supports her access to the Cedar route, but no runtime deletion or missed callback has been observed. The engineer must still confirm the deployed service policy, any store-level condition and the scheduler's effective configuration. The ID's discoverability affects practical exploitation difficulty; it does not repair an authorization decision that lacks an owner comparison.
The gateway authentication, Mira's legitimate Cedar role and the internal service credential answer different questions. None of them establishes her right to delete Harbor's endpoint. OWASP API1:2023 makes the object-level distinction: permission to call an API is different from permission to act on the particular object ID supplied. Do not report Harbor's callbacks as actually disrupted when the reviewed evidence shows only the path that could disrupt them.
Trace alternative callers and the final effect
Do not stop after finding one apparently safe route. Search for each caller of the webhook service's delete operation: project settings, administrative tools, account closure and migration handlers when they exist. A project-specific list endpoint might correctly filter Cedar's endpoints while the direct delete operation still accepts a global ID. Note whether each caller supplies a signed actor context, a project selector, or only a service credential. A tenant_id copied from a request is a selector, not proof of ownership. OWASP's multi-tenant guidance calls for authorization on tenant-owned access paths.
Follow the side effect outward as carefully as the request inward. A 204 response might mean the endpoint was deleted, already absent, or the call was accepted for asynchronous work. Check the endpoint's authoritative state, the scheduler's consumption of that state, and whether another copy or retry path could keep deliveries running. Those facts affect the precise harm, but they do not excuse skipping the object-owner check. Keep a source-supported possible effect separate from a safely observed effect in an authorized environment.
The engineer's working artifact is a boundary ledger:
- Claim: A Cedar project administrator may be able to disable Harbor's webhook by supplying its endpoint ID to the Cedar delete route.
- Revision and scope: Exact application revision; route manifest, projects API, webhook service, endpoint store and delivery scheduler reviewed.
- Actor/action/object: Mira, Cedar project administrator; delete endpoint; Harbor-owned
W-Harbor.- Transitions: For every hop, source of subject/project/endpoint ID, enforced decision, state change and evidence reference.
- Counterevidence: Cedar project-role check and authenticated service call; neither binds the Harbor endpoint to Cedar.
- Unknowns: Endpoint-ID discoverability, deployed service/store policy, scheduler configuration and observed delivery effect. Next owner: Platform confirms effective policy and scheduler configuration; AppSec independently reviews the complete path.
Keep exact file and line references in the authorized technical record. A short plain-language explanation for an engineering manager can say, “A project administrator may be able to disable another tenant's webhook because the delete operation does not compare endpoint ownership with the authorized project. We need to confirm the deployed policy before treating that effect as verified.” This is more useful than either “missing auth” or an unqualified claim of lost notifications.
Find the handoff that loses the authority
Inspect the actual message as well as each service's prose description. The constructed projects API sends:
before handoff:
subject = Mira; authorized_project = P-Cedar
action = delete_webhook; endpoint_selector = W-Harbor
after handoff:
caller_service = projects-api
endpoint_selector = W-Harbor
The projects API's statement “we checked the project” is true. The webhook service's statement “we authenticate the caller” is also true. The missing relationship is whether W-Harbor belongs to the project for which Mira holds authority. An authenticated service name cannot reconstruct a project or user that was discarded.
Now supply the remaining artifacts: webhook build W17 accepts the service credential without an endpoint-owner decision; store policy S8 permits global endpoint updates; scheduler D9 stops future work when that same authoritative record has its deleted marker set. The deployment manifest binds those three versions to the assessed route. The narrow source-and-configuration candidate is now supported for independent verification: Mira, given Harbor's valid endpoint ID, can drive an unauthorized deleted-state update through the reviewed path. No missed callback or executed deletion is claimed.
A rolling upgrade complicates the repair. Suppose W18 adds an enforced owner check but the route can still send requests to W17. The new implementation breaks the path only when W18 handles it. The engineering output is therefore two tasks with different closure evidence: correct the owner binding in the webhook operation; then demonstrate that the selected environment no longer routes this operation to W17. Do not call the whole route fixed because W18 exists in the repository.
A completed boundary ledger should now move service/store/scheduler policy out of “unknown” and retain only genuine limits: how an actor could learn an endpoint ID, whether any request occurred, and which other deployments were excluded. That small revision matters. A report that continues listing resolved questions looks cautious but conceals what the review actually established.
Turn the boundary ledger into coordinated repair work
A cross-service finding often stalls because each team can truthfully say its own local check works. Give the projects and webhook owners a shared contract that names the relationship both must preserve: the selected endpoint must belong to an authorized project, and the end user's requested deletion must be permitted for that endpoint. Then let the owners choose the enforcement point with the platform constraints in view.
For the fictional W18 repair, the handoff should distinguish preparation from completion. The projects team can prepare the additional trusted context, the webhook team can enforce the endpoint relationship, and platform can control adoption. A message field alone is not the repair: the receiving service must use it in a mandatory decision, and its provenance must prevent the requesting customer from inventing authority.
During a mixed-version rollout, list the combinations that can actually occur. New sender with old receiver may transmit a project that the receiver ignores. Old sender with new receiver may lack the context the new check requires. Neither is solved by saying both repositories have merged. The release plan needs a defined safe behavior for unsupported combinations, with legitimate operations and recovery considered by the owners.
The acceptance record can therefore contain two distinct lines: “W18 enforces the endpoint relationship in source” and “the assessed route now uses compatible versions with no W17 destination.” If only the first is known, report a prepared source repair and unresolved rollout. If the second is established, retain evidence of the binding instead of replacing the record with a generic green deployment badge.
This coordination is part of finishing the original finding, not an invitation to review every service in the organization. Bound it to the actual senders, receivers and alternate callers that could preserve the unauthorized deletion path.
Next step: Fill the ledger for one cross-service alert, starting with the actual object owner rather than the scanner's highlighted file. Use the uncertainty template for deployment facts that remain unknown, then use the disagreement protocol if reviewers reach different conclusions from the same path.