We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
There was an error while loading. Please reload this page.
1 parent ac9b635 commit 9f93298Copy full SHA for 9f93298
doc/changelog.md
@@ -4,6 +4,7 @@
4
- (new) more auto-refresh options: 12h & 24h (thanks to @aswerkljh for suggestion)
5
- (fix) smooth scrolling on iOS (thanks to gatheraled)
6
- (etc) cookie security measures (thanks to Tom Fitzhenry)
7
+- (etc) restrict access to internal IPs for page crawler (thanks to Omar Kurt)
8
9
# v2.5 (2025-03-26)
10
src/server/routes.go
@@ -513,6 +513,10 @@ func (s *Server) handlePageCrawl(c *router.Context) {
513
})
514
return
515
}
516
+ if isInternalFromURL(url) {
517
+ log.Printf("attempt to access internal IP %s from %s", url, c.Req.RemoteAddr)
518
+ return
519
+ }
520
521
body, err := worker.GetBody(url)
522
if err != nil {
src/server/util.go
@@ -0,0 +1,35 @@
1
+package server
2
+
3
+import (
+ "net"
+ "net/url"
+ "strings"
+)
+func isInternalFromURL(urlStr string) bool {
+ parsedURL, err := url.Parse(urlStr)
11
+ if err != nil {
12
+ return false
13
14
15
+ host := parsedURL.Host
16
17
+ // Handle "host:port" format
18
+ if strings.Contains(host, ":") {
19
+ host, _, err = net.SplitHostPort(host)
20
21
22
23
24
25
+ if host == "localhost" {
26
+ return true
27
28
29
+ ip := net.ParseIP(host)
30
+ if ip == nil {
31
32
33
34
+ return ip.IsPrivate() || ip.IsLoopback() || ip.IsLinkLocalUnicast()
35
+}
src/server/util_test.go
@@ -0,0 +1,31 @@
+import "testing"
+func TestIsInternalFromURL(t *testing.T) {
+ tests := []struct {
+ url string
+ expected bool
+ }{
+ {"http://192.168.1.1:8080", true},
+ {"http://10.0.0.5", true},
+ {"http://172.16.0.1", true},
+ {"http://172.31.255.255", true},
+ {"http://172.32.0.1", false}, // outside private range
+ {"http://127.0.0.1", true},
+ {"http://127.0.0.1:7000", true},
+ {"http://127.0.0.1:7000/secret", true},
+ {"http://169.254.0.5", true},
+ {"http://localhost", true}, // resolves to 127.0.0.1
+ {"http://8.8.8.8", false},
+ {"http://google.com", false}, // resolves to public IPs
+ {"invalid-url", false}, // invalid format
+ {"", false}, // empty string
+ for _, test := range tests {
+ result := isInternalFromURL(test.url)
+ if result != test.expected {
+ t.Errorf("isInternalFromURL(%q) = %v; want %v", test.url, result, test.expected)
0 commit comments