Skip to content

Commit 833a29f

Browse files
authored
Fix arbitrary file write via path traversal in X-Zone-Id header (#1208)
1 parent e5296da commit 833a29f

File tree

1 file changed

+27
-22
lines changed

1 file changed

+27
-22
lines changed

server/router.go

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,13 @@ func esmRouter(db Database, esmStorage storage.Storage, logger *log.Logger) rex.
112112
fmt.Fprintf(h, "%v", options.Minify)
113113
hash := hex.EncodeToString(h.Sum(nil))
114114

115+
zoneId := ctx.R.Header.Get("X-Zone-Id")
116+
if zoneId != "" && !valid.IsDomain(zoneId) {
117+
zoneId = ""
118+
}
119+
savePath := normalizeSavePath(zoneId, fmt.Sprintf("modules/transform/%s.mjs", hash))
120+
115121
// if previous build exists, return it directly
116-
savePath := normalizeSavePath(ctx.R.Header.Get("X-Zone-Id"), fmt.Sprintf("modules/transform/%s.mjs", hash))
117122
if file, _, err := esmStorage.Get(savePath); err == nil {
118123
data, err := io.ReadAll(file)
119124
file.Close()
@@ -408,7 +413,11 @@ func esmRouter(db Database, esmStorage storage.Storage, logger *log.Logger) rex.
408413
if len(hash) != 40 || !valid.IsHexString(hash) {
409414
return rex.Status(404, "Not Found")
410415
}
411-
savePath := normalizeSavePath(ctx.R.Header.Get("X-Zone-Id"), fmt.Sprintf("modules/transform/%s.%s", hash, ext))
416+
zoneId := ctx.R.Header.Get("X-Zone-Id")
417+
if zoneId != "" && !valid.IsDomain(zoneId) {
418+
zoneId = ""
419+
}
420+
savePath := normalizeSavePath(zoneId, fmt.Sprintf("modules/transform/%s.%s", hash, ext))
412421
f, fi, err := esmStorage.Get(savePath)
413422
if err != nil {
414423
return rex.Status(500, err.Error())
@@ -485,27 +494,23 @@ func esmRouter(db Database, esmStorage storage.Storage, logger *log.Logger) rex.
485494
npmrc = DefaultNpmRC()
486495
}
487496

488-
zoneIdHeader := ctx.R.Header.Get("X-Zone-Id")
489-
if zoneIdHeader != "" {
490-
if !valid.IsDomain(zoneIdHeader) {
491-
zoneIdHeader = ""
492-
} else {
493-
var scopeName string
494-
if pkgName := toPackageName(pathname[1:]); strings.HasPrefix(pkgName, "@") {
495-
scopeName = pkgName[:strings.Index(pkgName, "/")]
496-
}
497-
if scopeName != "" {
498-
reg, ok := npmrc.ScopedRegistries[scopeName]
499-
if !ok || (reg.Registry == jsrRegistry && reg.Token == "" && (reg.User == "" || reg.Password == "")) {
500-
zoneIdHeader = ""
501-
}
502-
} else if npmrc.Registry == npmRegistry && npmrc.Token == "" && (npmrc.User == "" || npmrc.Password == "") {
503-
zoneIdHeader = ""
497+
zoneId := ctx.R.Header.Get("X-Zone-Id")
498+
if zoneId != "" {
499+
var scopeName string
500+
if pkgName := toPackageName(pathname[1:]); strings.HasPrefix(pkgName, "@") {
501+
scopeName = pkgName[:strings.Index(pkgName, "/")]
502+
}
503+
if scopeName != "" {
504+
reg, ok := npmrc.ScopedRegistries[scopeName]
505+
if !ok || (reg.Registry == jsrRegistry && reg.Token == "" && (reg.User == "" || reg.Password == "")) {
506+
zoneId = ""
504507
}
508+
} else if npmrc.Registry == npmRegistry && npmrc.Token == "" && (npmrc.User == "" || npmrc.Password == "") {
509+
zoneId = ""
505510
}
506511
}
507-
if zoneIdHeader != "" {
508-
npmrc.zoneId = zoneIdHeader
512+
if zoneId != "" && valid.IsDomain(zoneId) {
513+
npmrc.zoneId = zoneId
509514
}
510515

511516
if strings.HasPrefix(pathname, "/http://") || strings.HasPrefix(pathname, "/https://") {
@@ -560,7 +565,7 @@ func esmRouter(db Database, esmStorage storage.Storage, logger *log.Logger) rex.
560565
h.Write([]byte(ctxParam))
561566
h.Write([]byte(target))
562567
h.Write([]byte(v))
563-
savePath := normalizeSavePath(zoneIdHeader, path.Join("modules/x", hex.EncodeToString(h.Sum(nil))+".css"))
568+
savePath := normalizeSavePath(npmrc.zoneId, path.Join("modules/x", hex.EncodeToString(h.Sum(nil))+".css"))
564569
r, fi, err := esmStorage.Get(savePath)
565570
if err != nil && err != storage.ErrNotFound {
566571
return rex.Status(500, err.Error())
@@ -704,7 +709,7 @@ func esmRouter(db Database, esmStorage storage.Storage, logger *log.Logger) rex.
704709
h.Write([]byte(im))
705710
h.Write([]byte(target))
706711
h.Write([]byte(v))
707-
savePath := normalizeSavePath(zoneIdHeader, path.Join("modules/x", hex.EncodeToString(h.Sum(nil))+".mjs"))
712+
savePath := normalizeSavePath(npmrc.zoneId, path.Join("modules/x", hex.EncodeToString(h.Sum(nil))+".mjs"))
708713
content, fi, err := esmStorage.Get(savePath)
709714
if err != nil && err != storage.ErrNotFound {
710715
return rex.Status(500, err.Error())

0 commit comments

Comments
 (0)