hugo

Unnamed repository; edit this file 'description' to name the repository.

git clone git://git.shimmy1996.com/hugo.git
commit 01dd7c16af6204d18d530f9d3018689215482170
parent c8f45d1d861f596821afc068bd12eb1213aba5ce
Author: gzagatti <gzagatti@users.noreply.github.com>
Date:   Mon, 11 Jan 2021 16:46:31 +0800

Fixes #7698.

markup: Allow installed arbitrary Asciidoc extension via path validation.

Diffstat:
Mdocs/content/en/content-management/formats.md | 2++
Mmarkup/asciidocext/asciidocext_config/config.go | 12------------
Mmarkup/asciidocext/convert.go | 6+++---
Mmarkup/asciidocext/convert_test.go | 46+++++++++++++++++++++++++++++++++++++++-------
4 files changed, 44 insertions(+), 22 deletions(-)
diff --git a/docs/content/en/content-management/formats.md b/docs/content/en/content-management/formats.md
@@ -100,6 +100,8 @@ Below are all the AsciiDoc related settings in Hugo with their default values:
 
 {{< code-toggle config="markup.asciidocExt" />}}
 
+Notice that for security concerns only extensions that do not have path separators (either `\`, `/` or `.`) are allowed. That means that extensions can only be invoked if they are in one's ruby's `$LOAD_PATH` (ie. most likely, the extension has been installed by the user). Any extension declared relative to the website's path will not be accepted.
+
 Example of how to set extensions and attributes:
 
 ```
diff --git a/markup/asciidocext/asciidocext_config/config.go b/markup/asciidocext/asciidocext_config/config.go
@@ -37,18 +37,6 @@ var (
 		FailureLevel: "fatal",
 	}
 
-	AllowedExtensions = map[string]bool{
-		"asciidoctor-html5s":           true,
-		"asciidoctor-bibtex":           true,
-		"asciidoctor-diagram":          true,
-		"asciidoctor-interdoc-reftext": true,
-		"asciidoctor-katex":            true,
-		"asciidoctor-latex":            true,
-		"asciidoctor-mathematical":     true,
-		"asciidoctor-question":         true,
-		"asciidoctor-rouge":            true,
-	}
-
 	AllowedSafeMode = map[string]bool{
 		"unsafe": true,
 		"safe":   true,
diff --git a/markup/asciidocext/convert.go b/markup/asciidocext/convert.go
@@ -19,6 +19,7 @@ package asciidocext
 import (
 	"bytes"
 	"path/filepath"
+	"strings"
 
 	"github.com/gohugoio/hugo/htesting"
 
@@ -105,11 +106,10 @@ func (a *asciidocConverter) parseArgs(ctx converter.DocumentContext) []string {
 	args = a.appendArg(args, "-b", cfg.Backend, asciidocext_config.CliDefault.Backend, asciidocext_config.AllowedBackend)
 
 	for _, extension := range cfg.Extensions {
-		if !asciidocext_config.AllowedExtensions[extension] {
-			a.cfg.Logger.Errorln("Unsupported asciidoctor extension was passed in. Extension `" + extension + "` ignored.")
+		if strings.LastIndexAny(extension, `\/.`) > -1 {
+			a.cfg.Logger.Errorln("Unsupported asciidoctor extension was passed in. Extension `" + extension + "` ignored. Only installed asciidoctor extensions are allowed.")
 			continue
 		}
-
 		args = append(args, "-r", extension)
 	}
 
diff --git a/markup/asciidocext/convert_test.go b/markup/asciidocext/convert_test.go
@@ -91,7 +91,7 @@ func TestAsciidoctorDisallowedArgs(t *testing.T) {
 	cfg := viper.New()
 	mconf := markup_config.Default
 	mconf.AsciidocExt.Backend = "disallowed-backend"
-	mconf.AsciidocExt.Extensions = []string{"disallowed-extension"}
+	mconf.AsciidocExt.Extensions = []string{"./disallowed-extension"}
 	mconf.AsciidocExt.Attributes = map[string]string{"outdir": "disallowed-attribute"}
 	mconf.AsciidocExt.SafeMode = "disallowed-safemode"
 	mconf.AsciidocExt.FailureLevel = "disallowed-failurelevel"
@@ -115,14 +115,11 @@ func TestAsciidoctorDisallowedArgs(t *testing.T) {
 	c.Assert(args, qt.DeepEquals, expected)
 }
 
-func TestAsciidoctorDiagramArgs(t *testing.T) {
+func TestAsciidoctorArbitraryExtension(t *testing.T) {
 	c := qt.New(t)
 	cfg := viper.New()
 	mconf := markup_config.Default
-	mconf.AsciidocExt.NoHeaderOrFooter = true
-	mconf.AsciidocExt.Extensions = []string{"asciidoctor-html5s", "asciidoctor-diagram"}
-	mconf.AsciidocExt.Backend = "html5s"
-	mconf.AsciidocExt.Trace = false
+	mconf.AsciidocExt.Extensions = []string{"arbitrary-extension"}
 	p, err := Provider.New(
 		converter.ProviderConfig{
 			Cfg:          cfg,
@@ -139,10 +136,45 @@ func TestAsciidoctorDiagramArgs(t *testing.T) {
 	c.Assert(ac, qt.Not(qt.IsNil))
 
 	args := ac.parseArgs(converter.DocumentContext{})
-	expected := []string{"-b", "html5s", "-r", "asciidoctor-html5s", "-r", "asciidoctor-diagram", "--no-header-footer"}
+	expected := []string{"-r", "arbitrary-extension", "--no-header-footer"}
 	c.Assert(args, qt.DeepEquals, expected)
 }
 
+func TestAsciidoctorDisallowedExtension(t *testing.T) {
+	c := qt.New(t)
+	cfg := viper.New()
+	for _, disallowedExtension := range []string{
+		`foo-bar//`,
+		`foo-bar\\ `,
+		`../../foo-bar`,
+		`/foo-bar`,
+		`C:\foo-bar`,
+		`foo-bar.rb`,
+		`foo.bar`,
+	} {
+		mconf := markup_config.Default
+		mconf.AsciidocExt.Extensions = []string{disallowedExtension}
+		p, err := Provider.New(
+			converter.ProviderConfig{
+				Cfg:          cfg,
+				MarkupConfig: mconf,
+				Logger:       loggers.NewErrorLogger(),
+			},
+		)
+		c.Assert(err, qt.IsNil)
+
+		conv, err := p.New(converter.DocumentContext{})
+		c.Assert(err, qt.IsNil)
+
+		ac := conv.(*asciidocConverter)
+		c.Assert(ac, qt.Not(qt.IsNil))
+
+		args := ac.parseArgs(converter.DocumentContext{})
+		expected := []string{"--no-header-footer"}
+		c.Assert(args, qt.DeepEquals, expected)
+	}
+}
+
 func TestAsciidoctorWorkingFolderCurrent(t *testing.T) {
 	c := qt.New(t)
 	cfg := viper.New()