Skip to content

Fix information disclosure via unhandled exceptions in GetGodAsync#7

Draft
Copilot wants to merge 2 commits intomainfrom
copilot/fix-unhandled-exception-issues
Draft

Fix information disclosure via unhandled exceptions in GetGodAsync#7
Copilot wants to merge 2 commits intomainfrom
copilot/fix-unhandled-exception-issues

Conversation

Copy link

Copilot AI commented Feb 19, 2026

GetGodAsync used FirstAsync(), throwing InvalidOperationException for non-existent IDs. In development mode, this exposed stack traces with database schema, file paths, and framework versions (CWE-209).

Changes

Repository Layer

  • FirstAsync()FirstOrDefaultAsync() with nullable Task<God?> return type
  • Added .Include(g => g.Aliases) for proper entity loading

Endpoint Layer

  • Input validation: 400 Bad Request for id <= 0
  • Null handling: 404 Not Found with structured JSON error messages
  • Extracted inline lambda to named method for testability

Global Exception Handler

  • Created ExceptionHandlingMiddleware to catch unhandled exceptions
  • Returns appropriate status codes by exception type
  • Production mode: generic error messages
  • Development mode: full exception details
  • All responses include trace IDs

Example

// Before: throws InvalidOperationException
public async Task<God> GetGodAsync(GodParameter parameter)
    => await _context.Gods.FirstAsync(x => x.Id == parameter.Id);

// After: returns null for missing entities
public async Task<God?> GetGodAsync(GodParameter parameter)
    => await _context.Gods
        .Include(g => g.Aliases)
        .FirstOrDefaultAsync(x => x.Id == parameter.Id);

// Endpoint handles null and validates input
public static async Task<IResult> GetGodById(int id, IGodRepository repository)
{
    if (id <= 0)
        return Results.BadRequest(new { error = "ID must be a positive integer" });
        
    var god = await repository.GetGodAsync(new GodParameter(id));
    return god is null 
        ? Results.NotFound(new { error = $"God with ID {id} not found" })
        : Results.Ok(god);
}

Response changes:

  • GET /api/v1/gods/99999: 500 with stack trace → 404 with {"error": "God with ID 99999 not found"}
  • GET /api/v1/gods/-1: 500 with stack trace → 400 with {"error": "ID must be a positive integer"}

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 105.130.85.20.in-addr.arpa
    • Triggering command: /usr/bin/lsof lsof -i -P (dns block)
  • 24.113.82.140.in-addr.arpa
    • Triggering command: /usr/bin/lsof lsof -i -P (dns block)
  • 34.11.16.104.in-addr.arpa
    • Triggering command: /usr/bin/lsof lsof -i -P (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>🔴 CRITICAL: Unhandled Exceptions Expose System Information</issue_title>
<issue_description>## Description

The GetGodAsync method in GodRepository.cs (line 63) uses FirstAsync() without null checking, causing unhandled exceptions that expose sensitive system information to clients. Additionally, the application lacks global exception handling middleware.

Vulnerable Code:

public async Task<God> GetGodAsync(GodParameter parameter)
{
    return await _context.Gods.FirstAsync(x => x.Id == parameter.Id);
}

When a non-existent ID is requested via GET /api/v1/gods/{id}, this throws an InvalidOperationException that bubbles up unhandled. In development mode, this returns a 500 error with a full stack trace exposing:

  • Database schema details
  • File system paths
  • Framework versions
  • Internal implementation details

Security Implications

  • Information Disclosure: Stack traces reveal internal architecture to attackers
  • Reconnaissance Aid: Exposed paths and versions help attackers identify vulnerable dependencies
  • Poor User Experience: Clients receive 500 errors instead of proper 404 responses
  • Denial of Service: Unhandled exceptions can crash the application or exhaust resources
  • OWASP 2025 Category: A10:2025 - Mishandling of Exceptional Conditions
  • CWE: CWE-209 (Generation of Error Message Containing Sensitive Information)

Example

# Request non-existent god
curl -i http://localhost:5000/api/v1/gods/99999

# Returns 500 with full stack trace in development mode:
# System.InvalidOperationException: Sequence contains no elements
#    at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstAsync[...]
#    at MythApi.Gods.DBRepositories.GodRepository.GetGodAsync(GodParameter parameter) in /Users/[...]/GodRepository.cs:line 63
#    [... more internal paths and details ...]

Solution

Implement proper exception handling at both the repository and middleware levels.

Step 1: Fix Repository Method

File: src/Gods/DBRepositories/GodRepository.cs (lines 63-66)

public async Task<God?> GetGodAsync(GodParameter parameter)
{
    return await _context.Gods
        .Include(g => g.Aliases)
        .FirstOrDefaultAsync(x => x.Id == parameter.Id);
}

Update Interface: src/Gods/Interfaces/IGodRepository.cs

Task<God?> GetGodAsync(GodParameter parameter); // Note the nullable return type

Step 2: Handle Null in Endpoint

File: src/Endpoints/v1/Gods.cs (line 16)

gods.MapGet("{id}", async (int id, IGodRepository repository) =>
{
    if (id <= 0)
        return Results.BadRequest(new { error = "ID must be a positive integer" });
        
    var god = await repository.GetGodAsync(new GodParameter(id));
    return god is null 
        ? Results.NotFound(new { error = $"God with ID {id} not found" })
        : Results.Ok(god);
});

Step 3: Add Global Exception Handler Middleware

Create: src/Common/Middleware/ExceptionHandlingMiddleware.cs

using System.Net;
using System.Text.Json;

namespace MythApi.Common.Middleware;

public class ExceptionHandlingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<ExceptionHandlingMiddleware> _logger;
    private readonly IHostEnvironment _environment;

    public ExceptionHandlingMiddleware(
        RequestDelegate next,
        ILogger<ExceptionHandlingMiddleware> logger,
        IHostEnvironment environment)
    {
        _next = next;
        _logger = logger;
        _environment = environment;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Unhandled exception occurred: {Message}", ex.Message);
            await HandleExceptionAsync(context, ex);
        }
    }

    private async Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        context.Response.ContentType = "application/json";
        
        var response = new
        {
            error = "An error occurred processing your request.",
            traceId = context.TraceIdentifier
        };

        switch (exception)
        {
            case ArgumentException:
            case InvalidOperationException:
                context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                break;
            case UnauthorizedAccessException:
                context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                break;
            default:
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                break;
        }

        // Only include stack trace in development
        if (_environment.IsDevelopment())
        {
            response = new
            {
                ...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes SolidifyDemo/mythapi-demo#6

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.

Co-authored-by: aatmmr <15815012+aatmmr@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix unhandled exceptions in GetGodAsync method Fix information disclosure via unhandled exceptions in GetGodAsync Feb 19, 2026
Copilot AI requested a review from aatmmr February 19, 2026 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments