diff --git a/go.mod b/go.mod index 82ce8b7126..38187d0266 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/MicahParks/keyfunc/v2 v2.1.0 github.com/Nerzal/gocloak/v13 v13.9.0 github.com/bbalet/stopwords v1.0.0 - github.com/beevik/etree v1.6.0 + github.com/beevik/etree v1.7.0 github.com/blevesearch/bleve/v2 v2.6.0 github.com/cenkalti/backoff v2.2.1+incompatible github.com/coreos/go-oidc/v3 v3.20.0 diff --git a/go.sum b/go.sum index d4d95c24ab..86ad20f141 100644 --- a/go.sum +++ b/go.sum @@ -132,8 +132,8 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W github.com/aws/aws-sdk-go v1.37.27/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bbalet/stopwords v1.0.0 h1:0TnGycCtY0zZi4ltKoOGRFIlZHv0WqpoIGUsObjztfo= github.com/bbalet/stopwords v1.0.0/go.mod h1:sAWrQoDMfqARGIn4s6dp7OW7ISrshUD8IP2q3KoqPjc= -github.com/beevik/etree v1.6.0 h1:u8Kwy8pp9D9XeITj2Z0XtA5qqZEmtJtuXZRQi+j03eE= -github.com/beevik/etree v1.6.0/go.mod h1:bh4zJxiIr62SOf9pRzN7UUYaEDa9HEKafK25+sLc0Gc= +github.com/beevik/etree v1.7.0 h1:xjBk9O4p4x7D1YajePjfLzdaFC4/uYUENA7P0pv6gXA= +github.com/beevik/etree v1.7.0/go.mod h1:bh4zJxiIr62SOf9pRzN7UUYaEDa9HEKafK25+sLc0Gc= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= diff --git a/vendor/github.com/beevik/etree/RELEASE_NOTES.md b/vendor/github.com/beevik/etree/RELEASE_NOTES.md index 96fe151389..7a01758c44 100644 --- a/vendor/github.com/beevik/etree/RELEASE_NOTES.md +++ b/vendor/github.com/beevik/etree/RELEASE_NOTES.md @@ -1,3 +1,27 @@ +Release 1.7.0 +============= + +**Changes** + +**Breaking changes** + +* To address a security issue, it was necessary to add a `MaxDepth` option to + `ReadSettings` to limit the depth of XML trees during parsing. A generous + default value of 1024 was chosen to avoid breaking most existing code. + However, if your code is processing XML hierarchies with a depth greater + than 1024, you will need to assign your `Document` a `ReadSettings` that has + a `MaxDepth` set to a higher value. + +**Security Fixes** + +* Limited the depth of XML trees processed by all `ReadFrom` functions during + parsing. +* Fixed a `CompilePath` index-out-of-range panic that could be caused by a + missing path filter key. +* Sanitized the contents of XML text, comment, ProcInst and Directive tokens + provided by the user. + + Release 1.6.0 ============= diff --git a/vendor/github.com/beevik/etree/etree.go b/vendor/github.com/beevik/etree/etree.go index bfe1f06e82..0fd1e7ed67 100644 --- a/vendor/github.com/beevik/etree/etree.go +++ b/vendor/github.com/beevik/etree/etree.go @@ -13,6 +13,7 @@ import ( "errors" "io" "iter" + "maps" "os" "slices" "strings" @@ -27,6 +28,10 @@ const ( // ErrXML is returned when XML parsing fails due to incorrect formatting. var ErrXML = errors.New("etree: invalid XML format") +// ErrMaxDepth is returned when the depth of the XML tree being read exceeds +// the maximum depth allowed by ReadSettings.MaxDepth. +var ErrMaxDepth = errors.New("etree: XML tree exceeds maximum depth") + // cdataPrefix is used to detect CDATA text when ReadSettings.PreserveCData is // true. var cdataPrefix = []byte(" maxDepth { + return r.Bytes(), ErrMaxDepth + } e := newElement(t.Name.Space, t.Name.Local, top) if settings.PreserveDuplicateAttrs || len(t.Attr) < 2 { for _, a := range t.Attr { @@ -1622,7 +1636,7 @@ func (c *CharData) Index() int { func (c *CharData) WriteTo(w Writer, s *WriteSettings) { if c.IsCData() { w.WriteString(``) } else { var m escapeMode @@ -1704,7 +1718,7 @@ func (c *Comment) Index() int { // WriteTo serialies the comment to the writer. func (c *Comment) WriteTo(w Writer, s *WriteSettings) { w.WriteString("") } @@ -1769,7 +1783,7 @@ func (d *Directive) Index() int { // WriteTo serializes the XML directive to the writer. func (d *Directive) WriteTo(w Writer, s *WriteSettings) { w.WriteString("") } @@ -1837,10 +1851,10 @@ func (p *ProcInst) Index() int { // WriteTo serializes the processing instruction to the writer. func (p *ProcInst) WriteTo(w Writer, s *WriteSettings) { w.WriteString("") } diff --git a/vendor/github.com/beevik/etree/helpers.go b/vendor/github.com/beevik/etree/helpers.go index ea789b62a7..e4e0ac1064 100644 --- a/vendor/github.com/beevik/etree/helpers.go +++ b/vendor/github.com/beevik/etree/helpers.go @@ -384,6 +384,120 @@ func escapeString(w Writer, s string, m escapeMode) { w.WriteString(s[last:]) } +// sanitizeCData writes the sanitized contents of a CDATA section to the +// writer. XML provides no way to escape the "]]>" sequence within a CDATA +// section, so any occurrence of it is split across two CDATA sections. +func sanitizeCData(w Writer, s string) { + for { + i := strings.Index(s, "]]>") + if i < 0 { + break + } + w.WriteString(s[:i+2]) + w.WriteString("]]>" sequence within a +// processing instruction, so a space is inserted between the two characters. +func sanitizeProcInst(w Writer, s string) { + for { + i := strings.Index(s, "?>") + if i < 0 { + break + } + w.WriteString(s[:i+1]) + w.WriteByte(' ') + s = s[i+1:] + } + w.WriteString(s) +} + +// sanitizeDirective writes the sanitized contents of an XML directive to the +// writer. +func sanitizeDirective(w Writer, s string) { + // The XML decoder reserves the character following "" as an unterminated + // directive. Insert a space to avoid conflicts with reserved sequences. + scan := s + if s == "" || s[0] == '-' || s[0] == '[' { + w.WriteByte(' ') + } else { + scan = s[1:] + } + + // A directive's contents may legitimately contain '<' and '>' characters, + // so write them without modification when they are balanced. + if isDirectiveBalanced(scan) { + w.WriteString(s) + return + } + + // The contents are unbalanced, so escape every character in the string. + escapeString(w, s, escapeNormal) +} + +// isDirectiveBalanced returns true if the interpreted portion of an XML +// directive's contents may be enclosed by "" without changing the +// extents of the resulting directive. +func isDirectiveBalanced(s string) bool { + var quote byte + var depth int + for i := 0; i < len(s); i++ { + switch c := s[i]; { + case quote != 0: + if c == quote { + quote = 0 + } + case c == '\'' || c == '"': + quote = c + case c == '>': + if depth == 0 { + return false + } + depth-- + case c == '<': + if !strings.HasPrefix(s[i+1:], "!--") { + depth++ + break + } + j := strings.Index(s[i+4:], "-->") + if j < 0 { + return false + } + i += 4 + j + 2 + } + } + return quote == 0 && depth == 0 +} + func isInCharacterRange(r rune) bool { return r == 0x09 || r == 0x0A || diff --git a/vendor/github.com/beevik/etree/path.go b/vendor/github.com/beevik/etree/path.go index 21760d34d4..7e9e67a1a3 100644 --- a/vendor/github.com/beevik/etree/path.go +++ b/vendor/github.com/beevik/etree/path.go @@ -281,7 +281,11 @@ func (c *compiler) parseSegment(path string) segment { c.err = ErrPath("path has invalid filter [brackets].") break } - seg.filters = append(seg.filters, c.parseFilter(fpath[:len(fpath)-1])) + filter := c.parseFilter(fpath[:len(fpath)-1]) + if c.err != ErrPath("") { + break + } + seg.filters = append(seg.filters, filter) } return seg } @@ -320,7 +324,11 @@ func (c *compiler) parseFilter(path string) filter { // Filter contains [@attr='val'], [@attr="val"], [fn()='val'], // [fn()="val"], [tag='val'] or [tag="val"]? eqindex := strings.IndexByte(path, '=') - if eqindex >= 0 && eqindex+1 < len(path) { + if eqindex == 0 { + c.err = ErrPath("path contains a filter expression with no key.") + return nil + } + if eqindex > 0 && eqindex+1 < len(path) { quote := path[eqindex+1] if quote == '\'' || quote == '"' { rindex := nextIndex(path, quote, eqindex+2) @@ -334,6 +342,10 @@ func (c *compiler) parseFilter(path string) filter { switch { case key[0] == '@': + if len(key) == 1 { + c.err = ErrPath("path contains a filter expression with no key.") + return nil + } return newFilterAttrVal(key[1:], value) case strings.HasSuffix(key, "()"): name := key[:len(key)-2] diff --git a/vendor/modules.txt b/vendor/modules.txt index 6c17e2b6eb..e99af0830f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -106,7 +106,7 @@ github.com/asaskevich/govalidator # github.com/bbalet/stopwords v1.0.0 ## explicit github.com/bbalet/stopwords -# github.com/beevik/etree v1.6.0 +# github.com/beevik/etree v1.7.0 ## explicit; go 1.23.0 github.com/beevik/etree # github.com/beorn7/perks v1.0.1