1Panel IP Access Control Bypass via Untrusted X-Forwarded-For Headers
Description
1Panel is an open-source, web-based control panel for Linux server management. Versions 2.0.14 and below use Gin's default configuration which trusts all IP addresses as proxies (TrustedProxies = 0.0.0.0/0), allowing any client to spoof the X-Forwarded-For header. Since all IP-based access controls (AllowIPs, API whitelists, localhost-only checks) rely on ClientIP(), attackers can bypass these protections by simply sending X-Forwarded-For: 127.0.0.1 or any whitelisted IP. This renders all IP-based security controls ineffective. This issue is fixed in version 2.0.14.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/1Panel-dev/1PanelGo | < 2.0.14 | 2.0.14 |
github.com/1Panel-dev/1Panel/agentGo | < 0.0.0-20251201063338-94f7d78cc976 | 0.0.0-20251201063338-94f7d78cc976 |
Affected products
1- Range: < 2.0.14
Patches
194f7d78cc976fix: Fix iptables state persistence issue (#11137)
4 files changed · +118 −41
agent/app/service/iptables.go+23 −1 modified@@ -8,6 +8,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/app/model" + "github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/firewall/client" @@ -189,9 +190,14 @@ func (s *IptablesService) Operate(req dto.IptablesOp) error { if err := iptables.SaveRulesToFile(iptables.FilterTab, iptables.Chain1PanelBasicAfter, iptables.BasicAfterFileName); err != nil { return err } + _ = settingRepo.Update("IptablesStatus", constant.StatusEnable) return nil case "init-forward": - return client.EnableIptablesForward() + if err := client.EnableIptablesForward(); err != nil { + return err + } + _ = settingRepo.Update("IptablesForwardStatus", constant.StatusEnable) + return nil case "init-advance": if err := iptables.AddChain(iptables.FilterTab, iptables.Chain1PanelInput); err != nil { return err @@ -206,6 +212,8 @@ func (s *IptablesService) Operate(req dto.IptablesOp) error { if err := iptables.BindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelInput, number); err != nil { return err } + _ = settingRepo.Update("IptablesInputStatus", constant.StatusEnable) + _ = settingRepo.Update("IptablesOutputStatus", constant.StatusEnable) return nil case "bind-base": if err := initPreRules(); err != nil { @@ -220,6 +228,7 @@ func (s *IptablesService) Operate(req dto.IptablesOp) error { if err := iptables.BindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicAfter, 3); err != nil { return err } + _ = settingRepo.Update("IptablesStatus", constant.StatusEnable) return nil case "unbind-base": if err := iptables.UnbindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicAfter); err != nil { @@ -231,16 +240,29 @@ func (s *IptablesService) Operate(req dto.IptablesOp) error { if err := iptables.UnbindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasic); err != nil { return err } + _ = settingRepo.Update("IptablesStatus", constant.StatusDisable) return nil case "bind": if err := iptables.BindChain(iptables.FilterTab, targetChain, req.Name, loadBindNumber(req.Name)); err != nil { return err } + if req.Name == iptables.Chain1PanelInput { + _ = settingRepo.Update("IptablesInputStatus", constant.StatusEnable) + } + if req.Name == iptables.Chain1PanelOutput { + _ = settingRepo.Update("IptablesOutputStatus", constant.StatusEnable) + } return nil case "unbind": if err := iptables.UnbindChain(iptables.FilterTab, targetChain, req.Name); err != nil { return err } + if req.Name == iptables.Chain1PanelInput { + _ = settingRepo.Update("IptablesInputStatus", constant.StatusDisable) + } + if req.Name == iptables.Chain1PanelOutput { + _ = settingRepo.Update("IptablesOutputStatus", constant.StatusDisable) + } return nil } return nil
agent/init/firewall/firewall.go+75 −40 modified@@ -2,21 +2,30 @@ package firewall import ( "fmt" + "os" "github.com/1Panel-dev/1Panel/agent/app/dto" + "github.com/1Panel-dev/1Panel/agent/app/repo" "github.com/1Panel-dev/1Panel/agent/app/service" + "github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/firewall" firewallClient "github.com/1Panel-dev/1Panel/agent/utils/firewall/client" "github.com/1Panel-dev/1Panel/agent/utils/firewall/client/iptables" ) func Init() { + if !needInit() { + return + } + global.LOG.Info("initializing firewall settings...") client, err := firewall.NewFirewallClient() if err != nil { return } clientName := client.Name() + + settingRepo := repo.NewISettingRepo() if clientName == "ufw" || clientName == "iptables" { if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelForward, iptables.ForwardFileName); err != nil { global.LOG.Errorf("load forward rules from file failed, err: %v", err) @@ -30,65 +39,91 @@ func Init() { global.LOG.Errorf("load postrouting rules from file failed, err: %v", err) return } - if err := firewallClient.EnableIptablesForward(); err != nil { - global.LOG.Errorf("enable iptables forward failed, err: %v", err) - return - } global.LOG.Infof("loaded iptables rules for forward from file successfully") + + iptablesForwardStatus, _ := settingRepo.GetValueByKey("IptablesForwardStatus") + if iptablesForwardStatus == constant.StatusEnable { + if err := firewallClient.EnableIptablesForward(); err != nil { + global.LOG.Errorf("enable iptables forward failed, err: %v", err) + return + } + } } + if clientName == "ufw" { _ = iptables.UnbindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicAfter) _ = iptables.UnbindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicBefore) _ = iptables.UnbindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasic) _ = iptables.UnbindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelInput) _ = iptables.UnbindChain(iptables.FilterTab, iptables.ChainOutput, iptables.Chain1PanelOutput) } - if clientName == "iptables" { - if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelBasicBefore, iptables.BasicBeforeFileName); err != nil { - global.LOG.Errorf("load basic before rules from file failed, err: %v", err) - return - } - if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelBasic, iptables.BasicFileName); err != nil { - global.LOG.Errorf("load basic rules from file failed, err: %v", err) - return - } - if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelBasicAfter, iptables.BasicAfterFileName); err != nil { - global.LOG.Errorf("load basic after rules from file failed, err: %v", err) - return - } - if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelInput, iptables.InputFileName); err != nil { - global.LOG.Errorf("load input rules from file failed, err: %v", err) - return - } - if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelOutput, iptables.OutputFileName); err != nil { - global.LOG.Errorf("load output rules from file failed, err: %v", err) - return - } - global.LOG.Infof("loaded iptables rules for basic, input and output from file successfully") - panelPort := service.LoadPanelPort() - if len(panelPort) == 0 { - global.LOG.Errorf("find 1panel service port failed") - return - } - if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasicBefore, fmt.Sprintf("-p tcp -m tcp --dport %v -j ACCEPT", panelPort)); err != nil { - global.LOG.Errorf("add port accept rule %v failed, err: %v", panelPort, err) + if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelBasicBefore, iptables.BasicBeforeFileName); err != nil { + global.LOG.Errorf("load basic before rules from file failed, err: %v", err) + return + } + if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelBasic, iptables.BasicFileName); err != nil { + global.LOG.Errorf("load basic rules from file failed, err: %v", err) + return + } + if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelBasicAfter, iptables.BasicAfterFileName); err != nil { + global.LOG.Errorf("load basic after rules from file failed, err: %v", err) + return + } + panelPort := service.LoadPanelPort() + if len(panelPort) == 0 { + global.LOG.Errorf("find 1panel service port failed") + return + } + if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasicBefore, fmt.Sprintf("-p tcp -m tcp --dport %v -j ACCEPT", panelPort)); err != nil { + global.LOG.Errorf("add port accept rule %v failed, err: %v", panelPort, err) + return + } + global.LOG.Infof("loaded iptables rules for basic from file successfully") + iptablesService := service.IptablesService{} + iptablesStatus, _ := settingRepo.GetValueByKey("IptablesStatus") + if iptablesStatus == constant.StatusEnable { + if err := iptablesService.Operate(dto.IptablesOp{Operate: "bind-base"}); err != nil { + global.LOG.Errorf("bind base chains failed, err: %v", err) return } + } - iptablesService := service.IptablesService{} - if err := iptablesService.Operate(dto.IptablesOp{Operate: "bind-base"}); err != nil { - global.LOG.Errorf("bind base chains failed, err: %v", err) + if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelInput, iptables.InputFileName); err != nil { + global.LOG.Errorf("load input rules from file failed, err: %v", err) + return + } + if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelOutput, iptables.OutputFileName); err != nil { + global.LOG.Errorf("load output rules from file failed, err: %v", err) + return + } + global.LOG.Infof("loaded iptables rules for input and output from file successfully") + iptablesInputStatus, _ := settingRepo.GetValueByKey("IptablesInputStatus") + if iptablesInputStatus == constant.StatusEnable { + if err := iptablesService.Operate(dto.IptablesOp{Name: iptables.Chain1PanelInput, Operate: "bind"}); err != nil { + global.LOG.Errorf("bind input chains failed, err: %v", err) return } + } + iptablesOutputStatus, _ := settingRepo.GetValueByKey("IptablesOutputStatus") + if iptablesOutputStatus == constant.StatusEnable { if err := iptablesService.Operate(dto.IptablesOp{Name: iptables.Chain1PanelOutput, Operate: "bind"}); err != nil { global.LOG.Errorf("bind output chains failed, err: %v", err) return } - if err := iptablesService.Operate(dto.IptablesOp{Name: iptables.Chain1PanelInput, Operate: "bind"}); err != nil { - global.LOG.Errorf("bind input chains failed, err: %v", err) - return - } } +} +func needInit() bool { + file, err := os.OpenFile("/run/1panel_boot_mark", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0644) + if err != nil { + if os.IsExist(err) { + return false + } + global.LOG.Errorf("check boot mark file failed: %v", err) + return true + } + defer file.Close() + fmt.Fprintf(file, "Boot Mark for 1panel\n") + return true }
agent/init/migration/migrate.go+1 −0 modified@@ -56,6 +56,7 @@ func InitAgentDB() { migrations.UpdateDatabase, migrations.AddGPUMonitor, migrations.UpdateDatabaseMysql, + migrations.InitIptablesStatus, }) if err := m.Migrate(); err != nil { global.LOG.Error(err)
agent/init/migration/migrations/init.go+19 −0 modified@@ -756,3 +756,22 @@ var UpdateDatabaseMysql = &gormigrate.Migration{ return nil }, } + +var InitIptablesStatus = &gormigrate.Migration{ + ID: "20251201-init-iptables-status", + Migrate: func(tx *gorm.DB) error { + if err := tx.Create(&model.Setting{Key: "IptablesStatus", Value: constant.StatusDisable}).Error; err != nil { + return err + } + if err := tx.Create(&model.Setting{Key: "IptablesForwardStatus", Value: constant.StatusDisable}).Error; err != nil { + return err + } + if err := tx.Create(&model.Setting{Key: "IptablesInputStatus", Value: constant.StatusDisable}).Error; err != nil { + return err + } + if err := tx.Create(&model.Setting{Key: "IptablesOutputStatus", Value: constant.StatusDisable}).Error; err != nil { + return err + } + return nil + }, +}
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-7cqv-qcq2-r765ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-66508ghsaADVISORY
- github.com/1Panel-dev/1Panel/commit/94f7d78cc9768ee244da33e09408017d1f68b5edghsax_refsource_MISCWEB
- github.com/1Panel-dev/1Panel/security/advisories/GHSA-7cqv-qcq2-r765ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.