[GH-ISSUE #1614] Denial on IP Rules should not indicate 401 or that the resource exists #6758

Closed
opened 2026-04-25 15:40:24 -05:00 by GiteaMirror · 13 comments
Owner

Originally created by @curious-debug on GitHub (Oct 4, 2025).
Original GitHub issue: https://github.com/fosrl/pangolin/issues/1614

Describe the Bug

When visiting a resource having Resource Rules that the IP of the end user does not pass (i.e., IP is denied), the response is currently "401 unauthorized". Not only is this incorrect per IETF HTTP Semantics, but this presents a security concern, as the end user now has knowledge that the URL exists. A better security posture should not return any response.

Per insightful discussion with @hhftechnology below, and this comment, the best path forward is this:

When not satisfying any IP Rules, admin should be able to select one of these for what happens next:

  1. send client to Auth page;
  2. select from list of HTTP status codes to send to client (e.g.: 401 Unauthorized, 403 Forbidden, 404 Not Found, 405 Method Not Allowed, 503 Service Unavailable, custom status code, etc.); or
  3. drop connection (send no response to client).

My original post primarily suggested sending no response, so as to not inform the failed IP visitor that the resource exists. @hhftechnology suggested keeping the 401 for its use case. Thus, the best option is to allow the admin flexibility to choose the course of action when visiting a resource fails all IP Rules, allowing the admin to pursue further logging/tracking and/or security, as best determined by the admin.

Below is original post.


In this discussion requesting "Always Deny if NOT IP Address Match", I discovered that I can create a "catch all" rule using 0.0.0.0/24 to deny visitors from visiting a resource if their IP address does not match. However, when visiting the resource from outside the allowed IP range, the response is "401 Unauthorized". This raised a red flag. Attackers visiting this resource now have knowledge that there indeed is a live resource behind the URL, and that resource can be now probed/attacked. A better response to visiting a resource that fails the IP check should be no response at all.

Environment

  • OS Type & Version: Ubuntu 24.04
  • Pangolin Version: Community Edition (I'm not using Pangolin cloud, but it's probably the same there also)

To Reproduce

  • Create Resource
  • Create/Enable Resource Rule to "Always Deny"
  • Visit the Resource, satisfying the "Always Deny" condition
  • "401 Unauthorized" is returned

Expected Behavior

The request should not return anything.

Per IETF docs: "The 401 (Unauthorized) status code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource." So, returning a 401 is not really right here, because the issue isn’t missing credentials; it’s denial of access regardless of credentials.

"403 Forbidden" means “we know what you’re asking for, but you’re not allowed," and although this is the most technically correct status to reject a request due to an access control policy (like an IP restriction), that also reveals knowledge that the URL/path exists.

"404 Not Found" still indicates that a server is present at that resource URL/subdomain name.

To obtain security by obscurity, Pangolin shouldn't inform outsiders that the resource exists, so it should silently drop the connection.

Or, we should at least have the option of choosing what to do if the Resource Rules config fails (e.g. choose 403, 404, or no response/connection drop).

Originally created by @curious-debug on GitHub (Oct 4, 2025). Original GitHub issue: https://github.com/fosrl/pangolin/issues/1614 ### Describe the Bug When visiting a resource having Resource Rules that the IP of the end user does not pass (i.e., IP is denied), the response is currently "401 unauthorized". Not only is this incorrect per IETF HTTP Semantics, but this presents a security concern, as the end user now has knowledge that the URL exists. A better security posture should not return any response. ------ ### UPDATED RECOMMENDED ACTION Per insightful discussion with @hhftechnology below, and this [comment](https://github.com/fosrl/pangolin/issues/1614#issuecomment-3387880656), the best path forward is this: **When not satisfying any IP Rules, admin should be able to select one of these for what happens next**: 1. send client to Auth page; 2. select from list of HTTP status codes to send to client (e.g.: 401 Unauthorized, 403 Forbidden, 404 Not Found, 405 Method Not Allowed, 503 Service Unavailable, custom status code, etc.); or 3. drop connection (send no response to client). My original post primarily suggested sending no response, so as to not inform the failed IP visitor that the resource exists. @hhftechnology suggested keeping the 401 for its use case. Thus, the best option is to allow the admin flexibility to choose the course of action when visiting a resource fails all IP Rules, allowing the admin to pursue further logging/tracking and/or security, as best determined by the admin. Below is original post. ------- In [this discussion](https://github.com/orgs/fosrl/discussions/1554) requesting "Always Deny if NOT IP Address Match", I discovered that I can create a "catch all" rule using 0.0.0.0/24 to deny visitors from visiting a resource if their IP address does not match. However, when visiting the resource from outside the allowed IP range, the response is "401 Unauthorized". This raised a red flag. Attackers visiting this resource now have knowledge that there indeed is a live resource behind the URL, and that resource can be now probed/attacked. A better response to visiting a resource that fails the IP check should be no response at all. ### Environment - OS Type & Version: Ubuntu 24.04 - Pangolin Version: Community Edition (I'm not using Pangolin cloud, but it's probably the same there also) ### To Reproduce - Create Resource - Create/Enable Resource Rule to "Always Deny" - Visit the Resource, satisfying the "Always Deny" condition - "401 Unauthorized" is returned ### Expected Behavior The request should not return anything. Per [IETF docs](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.2): "The 401 (Unauthorized) status code indicates that the request has not been applied **_because it lacks valid authentication credentials_** for the target resource." So, returning a 401 is not really right here, because the issue isn’t missing credentials; it’s denial of access regardless of credentials. "403 Forbidden" means “we know what you’re asking for, but you’re not allowed," and although this is the most technically correct status to reject a request due to an access control policy (like an IP restriction), that also reveals knowledge that the URL/path exists. "404 Not Found" still indicates that a server is present at that resource URL/subdomain name. **To obtain security by obscurity, Pangolin shouldn't inform outsiders that the resource exists, so it should silently drop the connection.** Or, we should at least have the option of choosing what to do if the Resource Rules config fails (e.g. choose 403, 404, or no response/connection drop).
GiteaMirror added the reverse proxySecurity labels 2026-04-25 15:40:25 -05:00
Author
Owner

@oschwartz10612 commented on GitHub (Oct 5, 2025):

Thanks for bringing this up! We should definitely implement this fix across badger and pangolin.

<!-- gh-comment-id:3368626973 --> @oschwartz10612 commented on GitHub (Oct 5, 2025): Thanks for bringing this up! We should definitely implement this fix across badger and pangolin.
Author
Owner

@curious-debug commented on GitHub (Oct 5, 2025):

You're welcome @oschwartz10612 . Also looking forward to the ability to manage Authentication and IP Rules in one place, so that authentication and rules can be applied to, and edited on, multiple resources, without having to edit each resource individually. @Pallavikumarimdb indicated working on this, but hopefully, whatever is done is a wholesome approach and considers Authentication Sets as well, and not just IP Rule Sets.

<!-- gh-comment-id:3368790896 --> @curious-debug commented on GitHub (Oct 5, 2025): You're welcome @oschwartz10612 . Also looking forward to the ability to manage [Authentication and IP Rules in one place](https://github.com/orgs/fosrl/discussions/1555), so that authentication and rules can be applied to, and edited on, multiple resources, without having to edit each resource individually. @Pallavikumarimdb indicated working on this, but hopefully, whatever is done is a wholesome approach and considers Authentication Sets as well, and not just IP Rule Sets.
Author
Owner

@hhftechnology commented on GitHub (Oct 5, 2025):

its was changed from 400 to 401.
401 is the correct code(404/ any other would be misleading). Why it is imp. because security apps like crowdsec reads these code and blocks and ban them if they continuously hammer this path.
if they all return 401 as unauthorized i don't think there is even a need for a custom collection/parser.
external display can be altered but i dont know how that will be helpful.
"Security through obscurity" is a weak and unreliable security approach

<!-- gh-comment-id:3368928853 --> @hhftechnology commented on GitHub (Oct 5, 2025): its was changed from 400 to 401. 401 is the correct code(404/ any other would be misleading). Why it is imp. because security apps like crowdsec reads these code and blocks and ban them if they continuously hammer this path. if they all return 401 as unauthorized i don't think there is even a need for a custom collection/parser. external display can be altered but i dont know how that will be helpful. "Security through obscurity" is a weak and unreliable security approach
Author
Owner

@hhftechnology commented on GitHub (Oct 5, 2025):

Thanks for bringing this up! We should definitely implement this fix across badger and pangolin.

not needed as per my understanding in security.

<!-- gh-comment-id:3369290638 --> @hhftechnology commented on GitHub (Oct 5, 2025): > Thanks for bringing this up! We should definitely implement this fix across badger and pangolin. not needed as per my understanding in security.
Author
Owner

@curious-debug commented on GitHub (Oct 8, 2025):

What was changed from 400 to 401?

As pointed out above, 401 is not correct, per IETF/RFC: "The 401 (Unauthorized) status code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource. The server generating a 401 response MUST send a WWW-Authenticate header field (Section 11.6.1) containing at least one challenge applicable to the target resource."

IP Rule failure in Pangolin is not due to a "lack of valid authentication credentials for the target resource", nor is Pangolin, in its 401 response here (or in any IP Rule failure response), then sending a WWW-Authenticate header field containing at least one challenge applicable to the target resource.

My aforementioned "security by obscurity" is not the correct terminology per se. It is simply this — "no response on IP Rule failure" — so that outsiders will not know that the resource exists.

Also, not everyone uses CrowdSec.

<!-- gh-comment-id:3380692251 --> @curious-debug commented on GitHub (Oct 8, 2025): What was changed from 400 to 401? As pointed out above, 401 is not correct, per [IETF/RFC](https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.2): "The 401 (Unauthorized) status code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource. The server generating a 401 response MUST send a WWW-Authenticate header field (Section 11.6.1) containing at least one challenge applicable to the target resource." IP Rule failure in Pangolin is not due to a "lack of valid authentication credentials for the target resource", nor is Pangolin, in its 401 response here (or in any IP Rule failure response), then sending a WWW-Authenticate header field containing at least one challenge applicable to the target resource. My aforementioned "security by obscurity" is not the correct terminology per se. It is simply this — "no response on IP Rule failure" — so that outsiders will not know that the resource exists. Also, not everyone uses CrowdSec.
Author
Owner

@hhftechnology commented on GitHub (Oct 8, 2025):

Also, not everyone uses CrowdSec.

Any reactive L7 firewall will need logs. how you plan to inform that firewall about bad actors if the error code is removed or manipulated?

Your words
Image

<!-- gh-comment-id:3382217872 --> @hhftechnology commented on GitHub (Oct 8, 2025): > Also, not everyone uses CrowdSec. Any reactive L7 firewall will need logs. how you plan to inform that firewall about bad actors if the error code is removed or manipulated? Your words <img width="697" height="60" alt="Image" src="https://github.com/user-attachments/assets/6876d330-eaee-4d7f-ac46-888db56bbed8" />
Author
Owner

@curious-debug commented on GitHub (Oct 9, 2025):

@hhftechnology

how you plan to inform that firewall about bad actors if the error code is removed or manipulated?

Provide the correct error code, or track the attempts and do something else. Give that option to the admin, as proposed above.

Also my words:
My aforementioned "security by obscurity" is not the correct terminology per se. It is simply this — "no response on IP Rule failure" — so that outsiders will not know that the resource exists.

Sounds like you are here just to argue, rather than propose solutions. People just love hanging out with those.

<!-- gh-comment-id:3386341448 --> @curious-debug commented on GitHub (Oct 9, 2025): @hhftechnology > how you plan to inform that firewall about bad actors if the error code is removed or manipulated? Provide the correct error code, or track the attempts and do something else. Give that option to the admin, as proposed above. Also my words: `My aforementioned "security by obscurity" is not the correct terminology per se. It is simply this — "no response on IP Rule failure" — so that outsiders will not know that the resource exists.` Sounds like you are here just to argue, rather than propose solutions. People just *love* hanging out with those.
Author
Owner

@hhftechnology commented on GitHub (Oct 9, 2025):

@hhftechnology

how you plan to inform that firewall about bad actors if the error code is removed or manipulated?

Provide the correct error code, or track the attempts and do something else. Give that option to the admin, as proposed above.

Also my words: My aforementioned "security by obscurity" is not the correct terminology per se. It is simply this — "no response on IP Rule failure" — so that outsiders will not know that the resource exists.

Sounds like you are here just to argue, rather than propose solutions. People just love hanging out with those.

for me 401 works, that was my solution. we don't have to create a separate parser if 401 code is there in the logs.

<!-- gh-comment-id:3386629786 --> @hhftechnology commented on GitHub (Oct 9, 2025): > [@hhftechnology](https://github.com/hhftechnology) > > > how you plan to inform that firewall about bad actors if the error code is removed or manipulated? > > Provide the correct error code, or track the attempts and do something else. Give that option to the admin, as proposed above. > > Also my words: `My aforementioned "security by obscurity" is not the correct terminology per se. It is simply this — "no response on IP Rule failure" — so that outsiders will not know that the resource exists.` > > Sounds like you are here just to argue, rather than propose solutions. People just _love_ hanging out with those. for me 401 works, that was my solution. we don't have to create a separate parser if 401 code is there in the logs.
Author
Owner

@curious-debug commented on GitHub (Oct 10, 2025):

@hhftechnology Got it. With that, I think giving us the option to choose what happens on an IP Rule denial would be best. For your use case, for example, 401 works. For others, they might want a 404 Not Found, or just no response altogether, so as to not inform the IP-failed requestor that there is a resource behind the URL.

The last sentence in the OP suggested that: Or, we should at least have the option of choosing what to do if the Resource Rules config fails (e.g. choose 403, 404, or no response/connection drop). Also should include 401 for your case. So, perhaps this:

When not satisfying any IP Rules, choose what happens:

  • send client to Auth page
  • send HTTP status code to client (enter HTTP status code here)
  • drop connection (send no response)

This would provide the best design for customer-desired flexibility, logging, security, and/or response.

<!-- gh-comment-id:3387880656 --> @curious-debug commented on GitHub (Oct 10, 2025): @hhftechnology Got it. With that, I think giving us the option to choose what happens on an IP Rule denial would be best. For your use case, for example, 401 works. For others, they might want a 404 Not Found, or just no response altogether, so as to not inform the IP-failed requestor that there is a resource behind the URL. The last sentence in the OP suggested that: `Or, we should at least have the option of choosing what to do if the Resource Rules config fails (e.g. choose 403, 404, or no response/connection drop).` Also should include 401 for your case. So, perhaps this: When not satisfying any IP Rules, choose what happens: - send client to Auth page - send HTTP status code to client (enter HTTP status code here) - drop connection (send no response) This would provide the best design for customer-desired flexibility, logging, security, and/or response.
Author
Owner

@curious-debug commented on GitHub (Oct 10, 2025):

FYI: To capture the flexibility approach from my previous comment, I updated the first post to include a section entitled "UPDATED RECOMMENDED ACTION", suggesting pursuit of the options listed above.

<!-- gh-comment-id:3388200286 --> @curious-debug commented on GitHub (Oct 10, 2025): FYI: To capture the flexibility approach from [my previous comment](https://github.com/fosrl/pangolin/issues/1614#issuecomment-3387880656), I updated the first post to include a section entitled "UPDATED RECOMMENDED ACTION", suggesting pursuit of the options listed above.
Author
Owner
<!-- gh-comment-id:3388993366 --> @hhftechnology commented on GitHub (Oct 10, 2025): Just an FYI, https://github.com/traefik/traefik/issues/10290 404 to drop. https://community.traefik.io/t/is-there-a-way-to-for-traefik-to-silently-drop-requests-instead-of-sending-a-404-responses/20541/2
Author
Owner

@hhftechnology commented on GitHub (Oct 10, 2025):

Just an FYI, traefik/traefik#10290

404 to drop.

https://community.traefik.io/t/is-there-a-way-to-for-traefik-to-silently-drop-requests-instead-of-sending-a-404-responses/20541/2

so basically, in traefik its not possible so it will not be in pangolin. but you can definitely change codes with plugins, a lot of them are available. you don't need devs permission or help to do. you can do that for each resource (a different code)

<!-- gh-comment-id:3391591419 --> @hhftechnology commented on GitHub (Oct 10, 2025): > Just an FYI, [traefik/traefik#10290](https://github.com/traefik/traefik/issues/10290) > > 404 to drop. > > https://community.traefik.io/t/is-there-a-way-to-for-traefik-to-silently-drop-requests-instead-of-sending-a-404-responses/20541/2 so basically, in traefik its not possible so it will not be in pangolin. but you can definitely change codes with plugins, a lot of them are available. you don't need devs permission or help to do. you can do that for each resource (a different code)
Author
Owner

@hhftechnology commented on GitHub (Oct 19, 2025):

@oschwartz10612 can you please close this issues

<!-- gh-comment-id:3419899581 --> @hhftechnology commented on GitHub (Oct 19, 2025): @oschwartz10612 can you please close this issues
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/pangolin#6758