mirror of
https://github.com/caddyserver/caddy.git
synced 2026-06-05 13:35:19 -04:00
templates: Patch for GHSA-vcc4-2c75-vc9v (#7785)
Tests / test (s390x on IBM Z) (push) Has been skipped
Tests / goreleaser-check (push) Has been skipped
Cross-Build / build (~1.26.0, 1.26, aix) (push) Successful in 2m48s
Cross-Build / build (~1.26.0, 1.26, darwin) (push) Successful in 2m47s
Tests / test (./cmd/caddy/caddy, ~1.26.0, ubuntu-latest, 0, 1.26, linux) (push) Failing after 3m14s
Cross-Build / build (~1.26.0, 1.26, dragonfly) (push) Successful in 1m31s
Cross-Build / build (~1.26.0, 1.26, freebsd) (push) Successful in 1m44s
Cross-Build / build (~1.26.0, 1.26, illumos) (push) Successful in 1m58s
Cross-Build / build (~1.26.0, 1.26, linux) (push) Successful in 1m31s
Cross-Build / build (~1.26.0, 1.26, netbsd) (push) Successful in 1m40s
Cross-Build / build (~1.26.0, 1.26, openbsd) (push) Successful in 2m5s
Cross-Build / build (~1.26.0, 1.26, solaris) (push) Successful in 1m31s
Cross-Build / build (~1.26.0, 1.26, windows) (push) Successful in 1m46s
Lint / govulncheck (push) Successful in 1m33s
Lint / dependency-review (push) Failing after 1m2s
Lint / lint (ubuntu-latest, linux) (push) Successful in 2m54s
OpenSSF Scorecard supply-chain security / Scorecard analysis (push) Failing after 5m49s
Tests / test (./cmd/caddy/caddy, ~1.26.0, macos-14, 0, 1.26, mac) (push) Has been cancelled
Tests / test (./cmd/caddy/caddy.exe, ~1.26.0, windows-latest, True, 1.26, windows) (push) Has been cancelled
Lint / lint (macos-14, mac) (push) Has been cancelled
Lint / lint (windows-latest, windows) (push) Has been cancelled
Tests / test (s390x on IBM Z) (push) Has been skipped
Tests / goreleaser-check (push) Has been skipped
Cross-Build / build (~1.26.0, 1.26, aix) (push) Successful in 2m48s
Cross-Build / build (~1.26.0, 1.26, darwin) (push) Successful in 2m47s
Tests / test (./cmd/caddy/caddy, ~1.26.0, ubuntu-latest, 0, 1.26, linux) (push) Failing after 3m14s
Cross-Build / build (~1.26.0, 1.26, dragonfly) (push) Successful in 1m31s
Cross-Build / build (~1.26.0, 1.26, freebsd) (push) Successful in 1m44s
Cross-Build / build (~1.26.0, 1.26, illumos) (push) Successful in 1m58s
Cross-Build / build (~1.26.0, 1.26, linux) (push) Successful in 1m31s
Cross-Build / build (~1.26.0, 1.26, netbsd) (push) Successful in 1m40s
Cross-Build / build (~1.26.0, 1.26, openbsd) (push) Successful in 2m5s
Cross-Build / build (~1.26.0, 1.26, solaris) (push) Successful in 1m31s
Cross-Build / build (~1.26.0, 1.26, windows) (push) Successful in 1m46s
Lint / govulncheck (push) Successful in 1m33s
Lint / dependency-review (push) Failing after 1m2s
Lint / lint (ubuntu-latest, linux) (push) Successful in 2m54s
OpenSSF Scorecard supply-chain security / Scorecard analysis (push) Failing after 5m49s
Tests / test (./cmd/caddy/caddy, ~1.26.0, macos-14, 0, 1.26, mac) (push) Has been cancelled
Tests / test (./cmd/caddy/caddy.exe, ~1.26.0, windows-latest, True, 1.26, windows) (push) Has been cancelled
Lint / lint (macos-14, mac) (push) Has been cancelled
Lint / lint (windows-latest, windows) (push) Has been cancelled
* Patch GHSA-vcc4-2c75-vc9v in stripHTML templates: fix funcStripHTML bypass via depth counter The previous false-start approach allowed XSS bypass via inputs like <<>img src=x onerror=alert(1)> and failed on stacked angle brackets. Replace the tagStart/inTag state machine with a depth counter that mirrors PHP strip_tags behaviour: each '<' increments depth, each '>' decrements it, and text is only emitted at depth zero. Quoted attribute values (both single and double) are tracked so '>' inside href values does not prematurely close a tag. Signed-off-by: JM Sanchez <77505889+jmrcsnchz@users.noreply.github.com> * Update tplcontext_test.go Templates: expand TestStripHTML with attack path coverage Signed-off-by: JM Sanchez <77505889+jmrcsnchz@users.noreply.github.com> --------- Signed-off-by: JM Sanchez <77505889+jmrcsnchz@users.noreply.github.com>
This commit is contained in:
@@ -312,35 +312,32 @@ func (c TemplateContext) Host() (string, error) {
|
||||
return host, nil
|
||||
}
|
||||
|
||||
// funcStripHTML returns s without HTML tags. It is fairly naive
|
||||
// but works with most valid HTML inputs.
|
||||
// funcStripHTML returns s without HTML tags. Similar to PHP's strip_tags()
|
||||
func (TemplateContext) funcStripHTML(s string) string {
|
||||
var buf bytes.Buffer
|
||||
var inTag, inQuotes bool
|
||||
var tagStart int
|
||||
for i, ch := range s {
|
||||
if inTag {
|
||||
if ch == '>' && !inQuotes {
|
||||
inTag = false
|
||||
} else if ch == '<' && !inQuotes {
|
||||
// false start
|
||||
buf.WriteString(s[tagStart:i])
|
||||
tagStart = i
|
||||
} else if ch == '"' {
|
||||
inQuotes = !inQuotes
|
||||
depth := 0
|
||||
var quoteChar rune
|
||||
for _, ch := range s {
|
||||
switch {
|
||||
case depth > 0 && quoteChar == 0 && (ch == '"' || ch == '\''):
|
||||
// entering a quoted attribute value
|
||||
quoteChar = ch
|
||||
case depth > 0 && ch == quoteChar:
|
||||
// leaving a quoted attribute value
|
||||
quoteChar = 0
|
||||
case ch == '<' && quoteChar == 0:
|
||||
depth++
|
||||
case ch == '>' && quoteChar == 0:
|
||||
if depth > 0 {
|
||||
depth--
|
||||
} else {
|
||||
buf.WriteRune(ch) // stray '>' with no opening '<', keep it
|
||||
}
|
||||
default:
|
||||
if depth == 0 {
|
||||
buf.WriteRune(ch)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if ch == '<' {
|
||||
inTag = true
|
||||
tagStart = i
|
||||
continue
|
||||
}
|
||||
buf.WriteRune(ch)
|
||||
}
|
||||
if inTag {
|
||||
// false start
|
||||
buf.WriteString(s[tagStart:])
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
@@ -419,14 +419,44 @@ func TestStripHTML(t *testing.T) {
|
||||
expect: `h1`,
|
||||
},
|
||||
{
|
||||
// tags not closed
|
||||
// unclosed tag — trailing text must be stripped, not emitted
|
||||
input: `<h1`,
|
||||
expect: `<h1`,
|
||||
expect: ``,
|
||||
},
|
||||
{
|
||||
// false start
|
||||
input: `<h1<b>hi`,
|
||||
expect: `<h1hi`,
|
||||
// false start — second '<' increments depth, single '>' only closes one level
|
||||
input: `<h1<b>hi`,
|
||||
expect: ``,
|
||||
},
|
||||
{
|
||||
// XSS bypass via double opening bracket
|
||||
input: `<<>img src=x onerror=alert('XSS')>`,
|
||||
expect: ``,
|
||||
},
|
||||
{
|
||||
// stacked angle brackets (PHP strip_tags parity)
|
||||
input: `<<<<<>>>>><b>hello</b>`,
|
||||
expect: `hello`,
|
||||
},
|
||||
{
|
||||
// unclosed tag strips trailing text
|
||||
input: `hello <world`,
|
||||
expect: `hello `,
|
||||
},
|
||||
{
|
||||
// '>' inside double-quoted attribute must not close tag early
|
||||
input: `<a href="foo>bar">text</a>`,
|
||||
expect: `text`,
|
||||
},
|
||||
{
|
||||
// '>' inside single-quoted attribute must not close tag early
|
||||
input: `<a href='foo>bar'>text</a>`,
|
||||
expect: `text`,
|
||||
},
|
||||
{
|
||||
// stray '>' with no opening '<' is preserved
|
||||
input: `stray > bracket`,
|
||||
expect: `stray > bracket`,
|
||||
},
|
||||
} {
|
||||
actual := tplContext.funcStripHTML(test.input)
|
||||
|
||||
Reference in New Issue
Block a user