list_webhooks (crates/gitlawb-node/src/api/webhooks.rs:73) is mounted on the optional_signature read-routes group (crates/gitlawb-node/src/server.rs:344-365), takes no AuthenticatedDid, and performs no ownership or visibility check. Its siblings create_webhook and delete_webhook both call require_repo_owner; list_webhooks does not. get_repo applies no is_public filter, so private repos resolve the same as public ones.
Any unauthenticated caller who knows a repo's owner/name can therefore enumerate every webhook registered on it. Secrets are redacted to ***, but the full target url, the created_by_did, and the event subscriptions are returned. Webhook URLs routinely embed internal-infra hostnames, third-party integration endpoints, and tokens or signed params in the path or query. The deliberate secret redaction shows these records are treated as sensitive; the directly actionable URL field is left open.
Where
crates/gitlawb-node/src/server.rs:344-365 mounts the route under optional_signature
crates/gitlawb-node/src/api/webhooks.rs:73-97 handler has no auth param and no require_repo_owner
crates/gitlawb-node/src/api/webhooks.rs:88-90 redacts secret only
crates/gitlawb-node/src/db/mod.rs get_repo has no is_public predicate
Fix
Move list_webhooks into an authenticated group and add require_repo_owner (mirroring create_webhook / delete_webhook), or gate it on the repo's authorization model if collaborator read access is intended. Keep the existing secret redaction.
Related
The same optional_signature read group also carries list_protected_branches, list_replicas, and list_repo_events. If any are meant to be visibility-gated for private repos, they share this missing-gate pattern and are worth tracing together, since get_repo applies no visibility filter.
list_webhooks(crates/gitlawb-node/src/api/webhooks.rs:73) is mounted on theoptional_signatureread-routes group (crates/gitlawb-node/src/server.rs:344-365), takes noAuthenticatedDid, and performs no ownership or visibility check. Its siblingscreate_webhookanddelete_webhookboth callrequire_repo_owner;list_webhooksdoes not.get_repoapplies nois_publicfilter, so private repos resolve the same as public ones.Any unauthenticated caller who knows a repo's
owner/namecan therefore enumerate every webhook registered on it. Secrets are redacted to***, but the full targeturl, thecreated_by_did, and the event subscriptions are returned. Webhook URLs routinely embed internal-infra hostnames, third-party integration endpoints, and tokens or signed params in the path or query. The deliberate secret redaction shows these records are treated as sensitive; the directly actionable URL field is left open.Where
crates/gitlawb-node/src/server.rs:344-365mounts the route underoptional_signaturecrates/gitlawb-node/src/api/webhooks.rs:73-97handler has no auth param and norequire_repo_ownercrates/gitlawb-node/src/api/webhooks.rs:88-90redactssecretonlycrates/gitlawb-node/src/db/mod.rsget_repohas nois_publicpredicateFix
Move
list_webhooksinto an authenticated group and addrequire_repo_owner(mirroringcreate_webhook/delete_webhook), or gate it on the repo's authorization model if collaborator read access is intended. Keep the existing secret redaction.Related
The same
optional_signatureread group also carrieslist_protected_branches,list_replicas, andlist_repo_events. If any are meant to be visibility-gated for private repos, they share this missing-gate pattern and are worth tracing together, sinceget_repoapplies no visibility filter.