Skip to main content

Free 30-min security demo Book Now

Offensive360 Offensive360
ZeroDays CVE-2026-57510
High CVE-2026-57510 CVSS 8.8 SuperPlane Go

SuperPlane gRPC BOLA

CVE-2026-57510 exposes a broken object-level authorization flaw in SuperPlane's gRPC handlers, enabling cross-tenant data access and workflow disruption.

Offensive360 Research Team
Affects: < 0.27.0
Source Code View Patch

Overview

CVE-2026-57510 is a broken object-level authorization (BOLA) vulnerability — classified under CWE-639 — in SuperPlane, an open-source automation workflow platform. The flaw resides in the CanvasService gRPC handler layer, where resource lookups accept arbitrary canvas and queue UUIDs supplied by the caller without first verifying that those resources belong to the authenticated user’s organization. Any user holding valid credentials, even at the lowest privilege tier (viewer), can exploit this to cross tenant boundaries and interact with resources they have no legitimate access to.

The vulnerability affects all SuperPlane deployments running versions prior to 0.27.0. Because SuperPlane is designed as a multi-tenant platform where organizations store automation workflows, event payloads, and integration secrets, the blast radius of a successful exploit is significant. An attacker who has compromised or registered even a trial account gains a foothold from which they can enumerate, read, modify, and delete assets belonging to every other tenant on the same instance.

The issue was addressed in the v0.27.0 release, with the underlying authorization logic corrected in commit 3e45cf4f. Operators running self-hosted instances should treat this as a critical upgrade regardless of the nominal CVSS score — the practical exploitability requires nothing more than a valid session token and knowledge of (or the ability to guess) a UUID.

Technical Analysis

BOLA vulnerabilities in gRPC services follow a predictable pattern: the server authenticates the caller correctly but then performs a direct object lookup using a caller-supplied identifier without scoping that lookup to the authenticated principal’s tenant context. In SuperPlane’s case, every CanvasService RPC that accepted a canvas_id or queue_id field queried the database by UUID alone.

A representative vulnerable handler resembles the following:

// VULNERABLE — no organization scope enforced
func (s *CanvasService) GetCanvas(ctx context.Context, req *pb.GetCanvasRequest) (*pb.GetCanvasResponse, error) {
    caller, err := auth.CallerFromContext(ctx)
    if err != nil {
        return nil, status.Error(codes.Unauthenticated, "unauthenticated")
    }
    // caller.OrganizationID is available but never used in the query
    canvas, err := s.db.Canvases().FindByID(ctx, req.CanvasId)
    if err != nil {
        return nil, status.Error(codes.NotFound, "canvas not found")
    }
    return &pb.GetCanvasResponse{Canvas: canvas.ToProto()}, nil
}

The caller object is populated from the validated JWT, so authentication itself is not broken. The critical omission is that caller.OrganizationID is extracted from the token but never passed to the database query. FindByID resolves any UUID in the canvases table unconditionally, meaning the returned object may belong to an entirely different organization.

The same pattern was replicated across multiple handlers covering queue item creation, canvas event listing, execution history retrieval, and canvas deletion. Because gRPC method inputs are structured protobuf messages, an attacker needs only to craft a valid request with a substituted UUID — trivially accomplished with any gRPC client or via gRPC-Web if a frontend proxy is exposed. There is no secondary check, row-level security enforcement, or post-fetch ownership assertion anywhere in the affected code paths.

The severity is compounded by the richness of the exposed data. Event payloads in SuperPlane commonly carry webhook bodies, CI tokens, and third-party API credentials that were injected into automation pipelines. Execution history records preserve full input/output pairs for each workflow step. Write access to queue items in a victim organization means an attacker can inject malicious event payloads, potentially hijacking downstream automation runs within the victim’s environment.

Impact

An authenticated attacker — including a free-tier or trial user on a SaaS deployment — can:

  • Read canvas definitions, execution history, and event payloads from arbitrary organizations, including embedded secrets and integration credentials.
  • Write queue items and canvas events into victim organizations, enabling workflow injection and potentially triggering privileged automation jobs under the victim’s identity.
  • Delete arbitrary canvases across all tenants, causing irreversible data loss and operational disruption.
  • Disrupt running automation workflows by injecting malformed or adversarial event payloads into active queues.

The CVSS 8.8 score (High) reflects the combination of network-exploitable attack vector, low attack complexity, low privilege requirement, and high impact across confidentiality, integrity, and availability — a vector string consistent with AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H. For enterprises using SuperPlane to orchestrate deployments or integrate with cloud provider APIs, the secrets exposure alone constitutes a critical incident requiring credential rotation across all affected pipelines.

How to Fix It

The fix requires enforcing organization scope at every database query that resolves a resource by UUID. The corrected pattern scopes the lookup to the authenticated organization, ensuring that even a valid UUID belonging to another tenant returns a not-found error:

// FIXED — organization scope enforced on every lookup
func (s *CanvasService) GetCanvas(ctx context.Context, req *pb.GetCanvasRequest) (*pb.GetCanvasResponse, error) {
    caller, err := auth.CallerFromContext(ctx)
    if err != nil {
        return nil, status.Error(codes.Unauthenticated, "unauthenticated")
    }

    canvas, err := s.db.Canvases().FindByIDAndOrganization(ctx, req.CanvasId, caller.OrganizationID)
    if err != nil {
        // Return NotFound regardless of reason to avoid oracle behavior
        return nil, status.Error(codes.NotFound, "canvas not found")
    }

    return &pb.GetCanvasResponse{Canvas: canvas.ToProto()}, nil
}

The database layer implementation for the scoped query:

// FindByIDAndOrganization prevents cross-tenant resolution
func (r *canvasRepository) FindByIDAndOrganization(ctx context.Context, id, orgID string) (*Canvas, error) {
    var c Canvas
    err := r.db.WithContext(ctx).
        Where("id = ? AND organization_id = ?", id, orgID).
        First(&c).Error
    return &c, err
}

Key remediation steps:

  1. Upgrade immediately to SuperPlane v0.27.0 or later:
    # Helm
    helm upgrade superplane superplane/superplane --version 0.27.0
    
    # Docker Compose — update the image tag
    docker pull superplanehq/superplane:v0.27.0
  2. Rotate all secrets stored in event payloads or pipeline configurations on affected instances, as exposure cannot be ruled out without access logs proving otherwise.
  3. Audit gRPC access logs for anomalous UUID patterns — requests resolving resources outside the caller’s known organization indicate active exploitation.
  4. Apply defense in depth by enforcing row-level security (RLS) at the database layer as a secondary control, so that even a future handler regression cannot produce cross-tenant reads.

Our Take

BOLA remains the most consistently underestimated vulnerability class in modern backend services, and gRPC APIs are a particularly fertile environment for it. Protocol Buffers encourage developers to think in terms of strongly typed, self-documenting messages, which can create false confidence that the schema alone enforces access control. It does not. Authentication middleware intercepts the call; it does not scope the resources the call can touch.

Multi-tenant SaaS platforms amplify the consequence of every BOLA instance because the shared infrastructure means a single flaw grants lateral access across the entire customer base. The SuperPlane case is textbook: the authentication layer worked correctly, the UUID was a well-formed identifier, but no one asked “whose UUID is this?”

For developers building gRPC services in Go or any other language: organization or tenant ID must be a first-class parameter in every repository method that resolves a resource by external identifier. It should never live only in the caller context, available but ignored. Treat caller.OrganizationID the same way you treat a SQL WHERE clause on user ID in single-tenant applications — it is not optional.

Detection with SAST

This vulnerability class maps to CWE-639: Authorization Bypass Through User-Controlled Key and CWE-284: Improper Access Control. Offensive360’s SAST engine detects BOLA patterns in gRPC service implementations by performing taint analysis across the request handler boundary:

  1. Source identification: RPC request fields (req.CanvasId, req.QueueId, etc.) are tagged as attacker-controlled taint sources.
  2. Context extraction audit: The engine checks whether auth.CallerFromContext (or equivalent middleware extraction functions) produces a tenant/org identifier that flows into downstream database calls.
  3. Sink validation: Any ORM or raw SQL call resolving by UUID/ID is treated as a sensitive sink. If the taint source reaches the sink without the organization identifier appearing as a conjunctive query parameter, the path is flagged as a BOLA finding.
  4. Cross-method coverage: The analysis runs across all methods implementing the gRPC service interface, not just entry points, catching cases where internal helper functions strip the organization context.

Rules to implement in custom SAST policies: flag any function that (a) accepts a UUID from a protobuf request field and (b) performs a single-column database lookup by that UUID without an accompanying tenant scope column. This pattern is reliably detectable through dataflow analysis and produces low false-positive rates in well-structured codebases.

References

#BOLA #IDOR #gRPC #multi-tenancy #authorization

Detect this vulnerability class in your codebase

Offensive360 SAST scans your source code for CVE-2026-57510-class vulnerabilities and thousands of other patterns — across 60+ languages.