Skip to content

[REVIEW] api-security: add SignalR hub authorization and origin evidence #1187

@99INFLUENCERS

Description

@99INFLUENCERS

Skill Being Reviewed

Skill name: api-security
Skill path: skills/appsec/api-security/

False Positive Analysis

Benign SignalR hub that should not be reported as a critical API auth gap:

builder.Services.AddCors(options =>
{
    options.AddPolicy("SignalRPolicy", policy =>
    {
        policy.WithOrigins("https://app.example.com")
            .WithMethods("GET", "POST")
            .AllowCredentials();
    });
});

app.MapHub<StatusHub>("/statusHub", options =>
{
    options.ApplicationMaxBufferSize = 16 * 1024;
    options.TransportMaxBufferSize = 16 * 1024;
}).RequireCors("SignalRPolicy");

[Authorize]
public class StatusHub : Hub
{
    public Task SubscribePublicStatus()
        => Groups.AddToGroupAsync(Context.ConnectionId, "public-status");
}

Why this is a false positive risk:

The current .NET supplement has strong coverage for controllers, Minimal APIs, GraphQL, and gRPC, but it has no SignalR-specific review path. If reviewers map every MapHub or Hub class to generic "missing API authorization" or generic WebSocket risk, they can over-report benign hubs that already have an explicit origin/CORS policy, authorization, small buffer limits, and non-sensitive channel membership.

Coverage Gaps

Missed variant 1: browser-accessible SignalR hub accepts credentials from broad origins

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
    {
        policy.AllowAnyHeader()
            .AllowAnyMethod()
            .SetIsOriginAllowed(_ => true)
            .AllowCredentials();
    });
});

app.MapHub<AccountHub>("/accountHub");

[Authorize]
public class AccountHub : Hub
{
    public Task SubscribeAccount(Guid accountId)
        => Groups.AddToGroupAsync(Context.ConnectionId, $"account:{accountId}");
}

Why it should be caught:

SignalR browser clients commonly rely on cookies or bearer tokens during the negotiation/WebSocket/SSE path. Microsoft documents that cross-origin SignalR must only allow trusted origins, and also notes that CORS protections do not apply to WebSockets in the same way. The skill should require reviewers to capture the hub path, browser exposure, credential mode, CORS/origin restriction, and hub endpoint policy rather than only checking ordinary REST CORS.

Missed variant 2: hub authorization is only connection-level, not method or group scoped

[Authorize]
public class SupportHub : Hub
{
    public Task JoinTenant(string tenantId)
        => Groups.AddToGroupAsync(Context.ConnectionId, $"tenant:{tenantId}");

    public Task SendAdminCommand(string tenantId, string command)
        => Clients.Group($"tenant:{tenantId}").SendAsync("AdminCommand", command);
}

Why it should be caught:

[Authorize] on the hub proves the caller is authenticated, but it does not prove the caller can join a requested tenant group or invoke a privileged hub method. Long-lived SignalR connections can also outlive role changes, tenant removal, token revocation, or account disablement. The review workflow should require evidence for per-method authorization, group membership checks, disconnect/revalidation behavior, and command/channel sensitivity.

Missed variant 3: access tokens in query strings are logged by default

builder.Services.AddAuthentication()
    .AddJwtBearer(options =>
    {
        options.Events = new JwtBearerEvents
        {
            OnMessageReceived = context =>
            {
                var accessToken = context.Request.Query["access_token"];
                if (!StringValues.IsNullOrEmpty(accessToken))
                    context.Token = accessToken;
                return Task.CompletedTask;
            }
        };
    });

Why it should be caught:

Microsoft documents that browser SignalR clients send access tokens in the query string for WebSockets and Server-Sent Events, and that ASP.NET Core logs request URLs by default. The .NET supplement currently rejects query-string tokens broadly in JWT auth examples, but SignalR is a documented exception that needs a more precise gate: only allow query token extraction for known hub paths, require HTTPS, redact or suppress query-string access-token logging, and avoid accepting access_token on normal API routes.

Missed variant 4: SignalR buffer and detailed-error settings are not reviewed

builder.Services.AddSignalR(options =>
{
    options.EnableDetailedErrors = true;
    options.MaximumReceiveMessageSize = null;
});

app.MapHub<ImportHub>("/importHub", options =>
{
    options.ApplicationMaxBufferSize = 0;
    options.TransportMaxBufferSize = 0;
});

Why it should be caught:

SignalR hubs are API surfaces with per-connection memory pressure and server-to-client exception exposure. Microsoft documents default buffer behavior and warns that removing limits can allow malicious clients to allocate excessive memory. The skill should extend API4/API8 review guidance to include SignalR MaximumReceiveMessageSize, ApplicationMaxBufferSize, TransportMaxBufferSize, EnableDetailedErrors, and per-connection quotas.

Edge Cases

  • Non-browser SignalR clients may use bearer tokens and omit meaningful browser Origin; reviewers should classify browser-exposed hubs separately from service-to-service clients.
  • Query-string access tokens are a documented SignalR transport pattern, so the finding should not be "all query tokens are bad." The finding should be missing path restriction, HTTPS, short token lifetime, and log redaction.
  • A hub-level [Authorize] can be sufficient for purely user-private notification channels when group membership is server-assigned and no client-selected tenant/channel parameters exist.
  • Public broadcast hubs still need abuse controls, message-size limits, and exception hygiene even when data sensitivity is low.

Remediation Quality

  • Fix resolves the issue
  • Fix does not introduce new security issues
  • Fix does not break functionality
  • Issues found: Add SignalR-specific inventory and evidence gates to the .NET supplement for MapHub, Hub classes, CORS/origin policy, hub/method authorization, group membership, access-token query handling, log redaction, buffer limits, detailed errors, and disconnect/revalidation behavior.

Comparison to Other Tools

Tool / Reference Catches this? Notes
Microsoft SignalR security docs Yes Covers trusted CORS origins, WebSocket origin restriction, query-token logging, detailed errors, and buffer limits.
Microsoft SignalR auth docs Partial Covers hub and method authorization, but the skill needs review tables and examples.
Existing api-security skill Partial Covers REST/GraphQL/gRPC auth, CORS, rate limiting, and upstream validation, but not SignalR hubs.
Existing WebSocket/SSE review issue Partial Covers generic streaming APIs, not ASP.NET Core SignalR-specific CORS, hub auth, group membership, or query-token logging exceptions.

Overall Assessment

Strengths:

  • Strong .NET coverage for controllers, Minimal APIs, GraphQL, and gRPC.
  • Good examples for JWT validation, policy authorization, rate limits, CORS, and message-size limits in gRPC.
  • Clear grep patterns for common ASP.NET Core API risks.

Needs improvement:

  • No SignalR discovery patterns such as MapHub<, Hub, Hub<T>, Groups.AddToGroupAsync, Clients.All, OnConnectedAsync, or access_token handling inside JwtBearerEvents.
  • No distinction between hub-level authentication and method/group-level authorization.
  • No SignalR-specific handling for browser credential flow, origin restriction, access-token query logging, detailed errors, or buffer limits.

Priority recommendations:

  1. Add a SignalR section to skills/appsec/api-security/csharp-dotnet.md.
  2. Add vulnerable and secure examples for hub mapping, CORS/origin restriction, method authorization, and tenant group membership.
  3. Add a SignalR checklist covering hub path, auth policy, browser exposure, origin policy, access-token query extraction scope, log redaction, group membership authorization, detailed errors, buffer limits, and reconnect/revalidation handling.
  4. Add grep patterns for MapHub<, class .* : Hub, Groups.AddToGroupAsync, Clients.All, EnableDetailedErrors = true, MaximumReceiveMessageSize = null, and access_token query extraction.

Sources Checked

Bounty Info

  • I have read and agree to the CONTRIBUTING.md bounty terms
  • Preferred payment method: PayPal; details can be provided privately after acceptance.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions