Context & Current Behavior
As discussed in #135, the new generic receiver is a fantastic addition.
My understanding of the current implementation is that the secretRef provided to the Receiver resource is used as a seed to generate a unique, hash-based token. This token then becomes part of the webhook URL (e.g., /hook/<generated-token>).
This provides a layer of security by obscurity, as the full path is required to successfully send a notification.
Problem Statement
This approach, while functional, presents two potential issues:
Confusing User Experience (UX): When a user is asked to provide a secretRef, the immediate and common expectation is that the secret's value will be used for active authentication (e.g., as a password, an API key, a Bearer token, or an HMAC signature key). Using it only to generate a URL path violates the "principle of least surprise." It can make the user feel like the secret is "not really being used" for auth, which can be confusing.
Weaker Security Posture: Relying solely on an obscure URL for security is generally considered less robust than explicit authentication. If this URL is ever accidentally leaked (e.g., in CI/CD logs, monitoring dashboards, or server logs), the endpoint is left completely exposed. An attacker with the URL can send notifications without needing any further credentials.
Proposed Solution
Would it make sense to enhance the generic receiver to use the provided secret for an explicit authentication check?
A straightforward and standard-compliant implementation could be to require the secret's value to be passed in the Authorization header as a Bearer token.
The workflow would be:
- An event is
POSTed to the receiver's URL.
- The
notification-controller receives the request and inspects the Authorization: Bearer <token> header.
- It fetches the
secretRef associated with that receiver.
- It performs a constant-time comparison between the secret's value and the provided
<token>.
- If they match, the event is processed (200 OK).
- If they do not match (or the header is missing), the request is rejected (401 Unauthorized).
The URL path itself could then either remain the unique hash or be simplified to just use the receiver's name (e.g., /hook/<receiver-name>), as the security is no longer dependent on the path's obscurity.
Benefits
This change would:
- Improve Security: Add a true authentication layer, protecting the endpoint even if the URL is leaked.
- Improve UX: Make the purpose of the
secretRef clear and intuitive, aligning with user expectations.
Happy to discuss this proposal further.
Linked to: #135
Context & Current Behavior
As discussed in #135, the new generic receiver is a fantastic addition.
My understanding of the current implementation is that the
secretRefprovided to theReceiverresource is used as a seed to generate a unique, hash-based token. This token then becomes part of the webhook URL (e.g.,/hook/<generated-token>).This provides a layer of security by
obscurity, as the full path is required to successfully send a notification.Problem Statement
This approach, while functional, presents two potential issues:
Confusing User Experience (UX): When a user is asked to provide a
secretRef, the immediate and common expectation is that the secret's value will be used for active authentication (e.g., as a password, an API key, a Bearer token, or an HMAC signature key). Using it only to generate a URL path violates the "principle of least surprise." It can make the user feel like the secret is "not really being used" for auth, which can be confusing.Weaker Security Posture: Relying solely on an obscure URL for security is generally considered less robust than explicit authentication. If this URL is ever accidentally leaked (e.g., in CI/CD logs, monitoring dashboards, or server logs), the endpoint is left completely exposed. An attacker with the URL can send notifications without needing any further credentials.
Proposed Solution
Would it make sense to enhance the generic receiver to use the provided secret for an explicit authentication check?
A straightforward and standard-compliant implementation could be to require the secret's value to be passed in the
Authorizationheader as a Bearer token.The workflow would be:
POSTed to the receiver's URL.notification-controllerreceives the request and inspects theAuthorization: Bearer <token>header.secretRefassociated with that receiver.<token>.The URL path itself could then either remain the unique hash or be simplified to just use the receiver's name (e.g.,
/hook/<receiver-name>), as the security is no longer dependent on the path's obscurity.Benefits
This change would:
secretRefclear and intuitive, aligning with user expectations.Happy to discuss this proposal further.
Linked to: #135