Fixes #7698.
authorgzagatti <gzagatti@users.noreply.github.com>
Mon, 11 Jan 2021 08:46:31 +0000 (16:46 +0800)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 22 Feb 2021 12:52:04 +0000 (13:52 +0100)
markup: Allow installed arbitrary Asciidoc extension via path validation.

docs/content/en/content-management/formats.md
markup/asciidocext/asciidocext_config/config.go
markup/asciidocext/convert.go
markup/asciidocext/convert_test.go

index 576ce2fa3309a33239fbb9982da1cee462f88c65..5654be7f0f02657ca9cf79f2c4cae353f2d155cc 100644 (file)
@@ -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:
 
 ```
index ac6e0cda4e41e7c6723e4f97f77bf1b8de623323..1409b2783eaeee9800814b63e20bd344705e7b55 100644 (file)
@@ -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,
index 51f114be2d1771f97e4fe59c2487e1e1c2d590e7..10e16810ea54a6faf7513cf4da921d332be3e16a 100644 (file)
@@ -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)
        }
 
index fa3aef404b1e08d4cdd94cee6410f3120e3d4f9d..4c183f7bb9b171d38ef3f0ece7dc2ffee7740409 100644 (file)
@@ -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()