Summary
When the GitHub webhook handler in src/app/api/webhooks/github/route.ts fails to persist an event, it serialises the raw Supabase PostgrestError object directly into the JSON response. This exposes internal database schema details to any caller that can reach the endpoint.
Affected File
src/app/api/webhooks/github/route.ts
Root Cause
On INSERT failure the handler returns:
return NextResponse.json(
{
error: 'persist failed',
code: insertErr.code,
message: insertErr.message,
details: insertErr.details,
hint: insertErr.hint,
},
{ status: 500 },
);
A PostgrestError from Supabase populates all four fields with values sourced directly from PostgreSQL:
| Field |
Example value |
code |
23505 (unique_violation) |
message |
duplicate key value violates unique constraint "github_events_pkey" |
details |
Key (id)=(gh_evt_abc123) already exists. |
hint |
Change the conflicting key or use ON CONFLICT. |
Together these reveal table names, column names, constraint names, and primary-key formats to any party that can trigger a webhook delivery failure (including GitHub itself, or an attacker who can send crafted payloads to the endpoint).
Impact
- Schema enumeration: Table and column names are visible without any database credentials.
- Constraint discovery: Index names disclose the primary-key scheme and uniqueness strategy of the events table.
- Replay-attack facilitation: Knowing the PK format (
gh_evt_<id>) makes it easier to craft collision payloads.
- Compliance risk: Leaking internal infrastructure details in API responses is flagged by most security audits (OWASP API Security Top 10, item API3:2023 - Broken Object Property Level Authorization).
Steps to Reproduce
- Send a webhook payload that causes a unique-constraint violation on the
github_events table (e.g., a duplicate delivery ID).
- Inspect the HTTP 500 response body.
- Observe that
code, message, details, and hint contain raw PostgreSQL error text.
Expected Behaviour
Log the full error server-side for debugging, and return only a generic message to the caller:
console.error('[webhook] persist failed', insertErr);
return NextResponse.json(
{ error: 'internal error' },
{ status: 500 },
);
If structured error codes are needed for GitHub's retry logic, expose only a stable, application-defined code that does not map 1:1 to Postgres error codes.
Severity
High - Information disclosure in a production-facing endpoint. No authentication is required to receive the 500 body; GitHub (and any network observer) can read it on every failed delivery.
Summary
When the GitHub webhook handler in
src/app/api/webhooks/github/route.tsfails to persist an event, it serialises the raw SupabasePostgrestErrorobject directly into the JSON response. This exposes internal database schema details to any caller that can reach the endpoint.Affected File
src/app/api/webhooks/github/route.tsRoot Cause
On INSERT failure the handler returns:
A
PostgrestErrorfrom Supabase populates all four fields with values sourced directly from PostgreSQL:code23505(unique_violation)messageduplicate key value violates unique constraint "github_events_pkey"detailsKey (id)=(gh_evt_abc123) already exists.hintChange the conflicting key or use ON CONFLICT.Together these reveal table names, column names, constraint names, and primary-key formats to any party that can trigger a webhook delivery failure (including GitHub itself, or an attacker who can send crafted payloads to the endpoint).
Impact
gh_evt_<id>) makes it easier to craft collision payloads.Steps to Reproduce
github_eventstable (e.g., a duplicate delivery ID).code,message,details, andhintcontain raw PostgreSQL error text.Expected Behaviour
Log the full error server-side for debugging, and return only a generic message to the caller:
If structured error codes are needed for GitHub's retry logic, expose only a stable, application-defined
codethat does not map 1:1 to Postgres error codes.Severity
High - Information disclosure in a production-facing endpoint. No authentication is required to receive the 500 body; GitHub (and any network observer) can read it on every failed delivery.