Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSanaei <ho3ein.sanaei@gmail.com>2025-09-21 19:05:26 +0300
committerGitHub <noreply@github.com>2025-09-21 19:05:26 +0300
commit806ecbd7c59b178b54a0567ad1f21e3819c4cd09 (patch)
tree6eb4c88d6b52da648b86c90c8fd0bbb94cd24703
parent37c17357fc45b9acec387f3097be5db074ce880d (diff)
parentae79b43cdb1fdcec772e9c411bb81243cae1de0a (diff)
Merge pull request #3528 from MHSanaei/security
Security issue fixed
-rw-r--r--.github/workflows/docker.yml3
-rw-r--r--config/config.go10
-rw-r--r--main.go2
-rw-r--r--util/random/random.go16
-rw-r--r--web/service/server.go49
5 files changed, 65 insertions, 15 deletions
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 0e460d24..9ec4c870 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -1,4 +1,7 @@
name: Release 3X-UI for Docker
+permissions:
+ contents: read
+ packages: write
on:
workflow_dispatch:
push:
diff --git a/config/config.go b/config/config.go
index c9a3e83c..17c9a77f 100644
--- a/config/config.go
+++ b/config/config.go
@@ -23,11 +23,11 @@ type LogLevel string
// Logging level constants
const (
- Debug LogLevel = "debug"
- Info LogLevel = "info"
- Notice LogLevel = "notice"
- Warn LogLevel = "warn"
- Error LogLevel = "error"
+ Debug LogLevel = "debug"
+ Info LogLevel = "info"
+ Notice LogLevel = "notice"
+ Warning LogLevel = "warning"
+ Error LogLevel = "error"
)
// GetVersion returns the version string of the 3x-ui application.
diff --git a/main.go b/main.go
index 119dc4d9..8ab8b13f 100644
--- a/main.go
+++ b/main.go
@@ -35,7 +35,7 @@ func runWebServer() {
logger.InitLogger(logging.INFO)
case config.Notice:
logger.InitLogger(logging.NOTICE)
- case config.Warn:
+ case config.Warning:
logger.InitLogger(logging.WARNING)
case config.Error:
logger.InitLogger(logging.ERROR)
diff --git a/util/random/random.go b/util/random/random.go
index 9610e26c..c746df63 100644
--- a/util/random/random.go
+++ b/util/random/random.go
@@ -2,7 +2,8 @@
package random
import (
- "math/rand"
+ "crypto/rand"
+ "math/big"
)
var (
@@ -40,12 +41,21 @@ func init() {
func Seq(n int) string {
runes := make([]rune, n)
for i := 0; i < n; i++ {
- runes[i] = allSeq[rand.Intn(len(allSeq))]
+ idx, err := rand.Int(rand.Reader, big.NewInt(int64(len(allSeq))))
+ if err != nil {
+ panic("crypto/rand failed: " + err.Error())
+ }
+ runes[i] = allSeq[idx.Int64()]
}
return string(runes)
}
// Num generates a random integer between 0 and n-1.
func Num(n int) int {
- return rand.Intn(n)
+ bn := big.NewInt(int64(n))
+ r, err := rand.Int(rand.Reader, bn)
+ if err != nil {
+ panic("crypto/rand failed: " + err.Error())
+ }
+ return int(r.Int64())
}
diff --git a/web/service/server.go b/web/service/server.go
index 9fe42e2c..a268a13e 100644
--- a/web/service/server.go
+++ b/web/service/server.go
@@ -697,14 +697,39 @@ func (s *ServerService) GetLogs(count string, level string, syslog string) []str
var lines []string
if syslog == "true" {
- cmdArgs := []string{"journalctl", "-u", "x-ui", "--no-pager", "-n", count, "-p", level}
- // Run the command
- cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
+ // Check if running on Windows - journalctl is not available
+ if runtime.GOOS == "windows" {
+ return []string{"Syslog is not supported on Windows. Please use application logs instead by unchecking the 'Syslog' option."}
+ }
+
+ // Validate and sanitize count parameter
+ countInt, err := strconv.Atoi(count)
+ if err != nil || countInt < 1 || countInt > 10000 {
+ return []string{"Invalid count parameter - must be a number between 1 and 10000"}
+ }
+
+ // Validate level parameter - only allow valid syslog levels
+ validLevels := map[string]bool{
+ "0": true, "emerg": true,
+ "1": true, "alert": true,
+ "2": true, "crit": true,
+ "3": true, "err": true,
+ "4": true, "warning": true,
+ "5": true, "notice": true,
+ "6": true, "info": true,
+ "7": true, "debug": true,
+ }
+ if !validLevels[level] {
+ return []string{"Invalid level parameter - must be a valid syslog level"}
+ }
+
+ // Use hardcoded command with validated parameters
+ cmd := exec.Command("journalctl", "-u", "x-ui", "--no-pager", "-n", strconv.Itoa(countInt), "-p", level)
var out bytes.Buffer
cmd.Stdout = &out
- err := cmd.Run()
+ err = cmd.Run()
if err != nil {
- return []string{"Failed to run journalctl command!"}
+ return []string{"Failed to run journalctl command! Make sure systemd is available and x-ui service is registered."}
}
lines = strings.Split(out.String(), "\n")
} else {
@@ -983,7 +1008,19 @@ func (s *ServerService) UpdateGeofile(fileName string) error {
{"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat", "geoip_RU.dat"},
{"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat", "geosite_RU.dat"},
}
-
+ // Strict allowlist check to avoid writing uncontrolled files
+ if fileName != "" {
+ isAllowed := false
+ for _, file := range files {
+ if fileName == file.FileName {
+ isAllowed = true
+ break
+ }
+ }
+ if !isAllowed {
+ return common.NewErrorf("Invalid geofile name: %s", fileName)
+ }
+ }
downloadFile := func(url, destPath string) error {
resp, err := http.Get(url)
if err != nil {