← Back to blog
Blog Detail

CVE-2026-15587: Testing Trusted Internal Auth Headers for SOAR Privilege Escalation

An authenticated SOAR user could reach system-level admin by sending a crafted internal authentication header. The test is two accounts, one header, and a diff of the responses plus the audit log.

Trusteed Team
Trusteed Editorial
Written On
Oct 27, 2026
Category
API Security
Read Time
9 min read
  • CVE-2026-15587
  • SOAR
  • Privilege Escalation
  • Internal Auth Headers
  • Authorization Testing
  • CWE-269
CVE-2026-15587: Testing Trusted Internal Auth Headers for SOAR Privilege Escalation

CVE-2026-15587: Testing Trusted Internal Auth Headers for SOAR Privilege Escalation

TL;DR

Google's SOAR platform had an improper privilege management flaw: an authenticated user could escalate to system-level administrative access by sending a crafted internal authentication header. Google fixed it in version 6.3.85 and states that customers were upgraded automatically, with no action required. The durable lesson is the class, not the CVE ID — the authorization decision trusted where a header appeared to come from instead of who proved they sent it. Prove impact with two accounts, one manipulated header, and a diff between the two responses, backed by an audit-log entry that attributes an admin action to a non-admin actor.

What this is

An internal authentication header is a field that a front-end component adds to requests it forwards to a back-end service. The front end has already checked the session, so it stamps the request with an identity or trust marker — X-Forwarded-User, an X-Internal-* value, a mesh-injected identity header. The back end reads that field and grants access without re-checking anything. It is a performance and architecture shortcut that works exactly as long as the field can only be written by the component that is supposed to write it.

Improper privilege management of this shape maps to CWE-269, with a generous helping of CWE-290 (authentication bypass by spoofing) and CWE-807 (relying on untrusted inputs in a security decision). The defect is not cryptographic. Nothing is broken in the token or the session. The defect is a trust boundary that assumed network position instead of proof.

Do not conflate this with bugs in internal-only features. This CVE targets the authorization decision itself; the test is whether the back end accepts a trust marker from a client it should not trust.

Why it matters

SOAR is a control plane, not a dashboard. It holds integration credentials for ticketing, EDR, firewalls, mail gateways, and identity providers, and it is authorized to act with them. An escalation to system-level administrative access on that platform is not a data-read problem; it is a change the firewall rule, disable the detection, close the ticket problem. The attacker does not need to compromise the downstream tool — the SOAR will do it on request.

Three things make this harder to handle than a normal patch cycle:

  • The blast radius includes the credentials in the box. Whoever holds admin on the orchestrator can read the secrets it uses to command everything else.
  • Auto-upgrade removes the usual change-ticket evidence. There is no maintenance window, no version you personally bumped. Are we on 6.3.85? becomes an attestation question, and attestation is exactly what auditors and incident responders cannot fake later.
  • The pattern is everywhere. Every reverse proxy that injects an identity header, every service mesh that stamps X-Forwarded-*, every internal only route that shares an ingress with the public app has the same latent bug. Finding it in one product should trigger a search across your own estate.

How it works

The mechanism is simple enough to describe without the exploit. A request arrives at the SOAR application carrying a valid session for a low-privilege user, plus a header that the application associates with internal service traffic. The authorization layer evaluates the header, concludes the caller is an internal, privileged component, and permits an operation the session would never be allowed to perform. Google's bulletin describes the outcome as escalation to system-level administrative access using a crafted internal authentication header.

Per Google Cloud bulletin GCP-2026-063, the vulnerability was rated Critical as CVE-2026-15587 and is fixed in version 6.3.85 and later. Google's position is that no customer action is required because instances were upgraded automatically. Read that bulletin directly rather than a secondary summary — the affected-version statement belongs to the vendor.

The bulletin does not name the header. Enumerating candidate header names is part of the test, and that enumeration is ordinary work: read the front-end JavaScript and the API docs, capture a normal admin session and diff its request headers against a normal low-privilege session, and look for fields that appear only when the UI performs privileged actions. The following is an illustrative example of the shape, not a working payload:

POST /api/v1/admin/integrations HTTP/1.1
Host: soar.example.com
Authorization: Bearer <low-privilege-user-token>
X-Internal-Auth: <candidate value>
Content-Type: application/json

What you are testing is narrow and falsifiable: does the back end make its authorization decision from this field, and does it accept the field from a client it should not trust? A single 200 where a 403 belongs is the whole hypothesis.

Detection and response

Paired SOAR API requests: without the internal auth header the call returns 403, with X-Internal-Auth: trusted it returns 200 and grants a role, while the audit log records the admin action under a non-admin analyst account.

The telemetry that matters is the correlation between who the session says you are and what the request claimed to be. A defender should be checking:

  • Request headers that the edge never emits. If your ingress or WAF logs full header sets, alert on internal-trust header names arriving from client IP space. The header should exist only on traffic between the proxy and the back end, and it should never appear in an access log sourced from the internet.
  • Duplicate headers. Many stacks take the first value and many take the last. A request carrying the same internal header twice, or a client-supplied copy alongside the proxy-injected one, is a probe worth reading.
  • Audit-log actor versus action. The highest-fidelity signal is a privileged action — creating an integration, modifying a playbook, changing a role — attributed to a session whose role does not include that permission, or a role change mid-session that was not performed by an administrator.
  • Direct-to-backend reachability. Requests that hit an application node without traversing the proxy, visible as a missing proxy-specific header on an otherwise valid session.
  • Downstream egress from the SOAR. A newly created or modified integration producing outbound calls to an unfamiliar host is the post-exploitation signature you actually care about.

If you are on 6.3.85 or later, treat these as regression detections, not incident response. If you cannot prove your version, run them as hunting queries.

What to do

  1. Attest the version before anything else. Pull the running version from the admin console or the version API and attach the output to the ticket. If you rely on vendor-managed auto-upgrade, the artifact is a screenshot of the version string and the date, not an email saying it was handled.
  2. Map the trust boundary. Identify every header your ingress, proxy, or mesh injects for identity. For each one, determine whether the back end strips client-supplied copies and whether the back end is reachable without the proxy.
  3. Create two accounts. Account A is the lowest-privilege role that can authenticate. Account B is an administrator. Do not use a shared account; you need attributable sessions.
  4. Capture the baseline. As Account B, perform one privileged action — read an integration list, open an admin settings page — and save the full request and response. As Account A, replay the same request untouched and confirm the 403 or equivalent denial. That denial is your control.
  5. Replay with the candidate header. As Account A, send the identical request with the internal header added. Change nothing else: same path, same body, same token.
  6. Diff the two responses. Status code, body shape, and any rendered administrative content. A 200 with admin payload against a 403 control is the finding; a 302 to a login page is not.
  7. Prove state change, not just read access. Have Account A perform an action with a durable effect — a benign settings change you revert, a role assignment you roll back — and capture the before/after plus the audit-log line naming Account A as the actor.
  8. Fix the class, not the instance. Strip internal-trust headers at the edge and reject requests that carry them from client space. Bind identity to a signed, verified assertion rather than a bare header. Deny direct backend reachability so the proxy is not optional.

FAQ

Does an attacker need credentials? Yes. The bulletin describes an authenticated attacker. That lowers the bar from unauthenticated RCE but does not lower it much: a single valid low-privilege account — a contractor, a shared service account, a phished analyst — is enough to reach system-level admin.

Is this still worth testing if we were auto-upgraded? Yes, for two reasons. You need evidence that the running version is 6.3.85 or higher, and you need to know whether the same header-trust pattern exists in your own proxies and internal services. The second is a code and configuration review, and no vendor patch fixes it for you.

Can a WAF block it? Sometimes, by rejecting requests that carry internal header names from client IP space. That is a compensating control, not a fix, and it fails the moment the backend is reachable directly or the header is renamed. Treat WAF coverage as a detection opportunity and record it as such.

How do I test without touching production? Use a staging instance of the same version, or restrict production testing to read-only requests and a reverted settings change with a named approver and a timestamp. Never test privilege escalation by creating a persistent admin account you might forget to remove.

What is the strongest artifact for the report? Two HTTP transcripts from the same low-privilege token — one denied, one accepted — plus the audit-log entry showing that token's user performing an administrator-only action. A second researcher can reproduce all three in minutes.

Sources

Join Our Newsletter

Trusteed keeps you informed: emerging risks, platform updates, and practical guides for faster defense.