--- /dev/null
+// Copyright 2020 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package hexec
+
+import (
+       "context"
+
+       "os/exec"
+
+       "github.com/cli/safeexec"
+)
+
+// SafeCommand is a wrapper around os/exec Command which uses a LookPath
+// implementation that does not search in current directory before looking in PATH.
+// See https://github.com/cli/safeexec and the linked issues.
+func SafeCommand(name string, arg ...string) (*exec.Cmd, error) {
+       bin, err := safeexec.LookPath(name)
+       if err != nil {
+               return nil, err
+       }
+
+       return exec.Command(bin, arg...), nil
+}
+
+// SafeCommandContext wraps CommandContext
+// See SafeCommand for more context.
+func SafeCommandContext(ctx context.Context, name string, arg ...string) (*exec.Cmd, error) {
+       bin, err := safeexec.LookPath(name)
+       if err != nil {
+               return nil, err
+       }
+
+       return exec.CommandContext(ctx, bin, arg...), nil
+}
 
 
        "io"
        "os"
-       "os/exec"
        "path/filepath"
        "strings"
 
+       "github.com/gohugoio/hugo/common/hexec"
        "github.com/gohugoio/hugo/hugofs/files"
 
        "github.com/gohugoio/hugo/hugofs"
                jww.FEEDBACK.Printf("Editing %s with %q ...\n", targetPath, editor)
 
                editorCmd := append(strings.Fields(editor), contentPath)
-               cmd := exec.Command(editorCmd[0], editorCmd[1:]...)
+               cmd, err := hexec.SafeCommand(editorCmd[0], editorCmd[1:]...)
+               if err != nil {
+                       return err
+               }
                cmd.Stdin = os.Stdin
                cmd.Stdout = os.Stdout
                cmd.Stderr = os.Stderr
 
        github.com/bep/gitmap v1.1.2
        github.com/bep/golibsass v0.7.0
        github.com/bep/tmc v0.5.1
+       github.com/cli/safeexec v1.0.0
        github.com/disintegration/gift v1.2.1
        github.com/dlclark/regexp2 v1.4.0 // indirect
        github.com/dustin/go-humanize v1.0.0
 
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764=
 github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
+github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI=
+github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
 github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s=
 
 import (
        "fmt"
        "os"
-       "os/exec"
        "path/filepath"
        "runtime"
        "testing"
 
+       "github.com/gohugoio/hugo/common/hexec"
+
        "github.com/gohugoio/hugo/htesting"
 
        "github.com/spf13/viper"
 
        b.WithSourceFile("assets/js/included.js", includedJS)
 
-       out, err := exec.Command("npm", "install").CombinedOutput()
+       cmd, err := hexec.SafeCommand("npm", "install")
+       b.Assert(err, qt.IsNil)
+       out, err := cmd.CombinedOutput()
        b.Assert(err, qt.IsNil, qt.Commentf(string(out)))
 
        b.Build(BuildCfg{})
 }`)
 
        b.Assert(os.Chdir(workDir), qt.IsNil)
-       _, err = exec.Command("npm", "install").CombinedOutput()
+       cmd, _ := hexec.SafeCommand("npm", "install")
+       _, err = cmd.CombinedOutput()
        b.Assert(err, qt.IsNil)
 
        b.Build(BuildCfg{})
 
 import (
        "bytes"
        "os"
-       "os/exec"
        "path/filepath"
        "runtime"
        "testing"
 
+       "github.com/gohugoio/hugo/common/hexec"
+
        jww "github.com/spf13/jwalterweatherman"
 
        "github.com/gohugoio/hugo/htesting"
        b.WithSourceFile("babel.config.js", babelConfig)
 
        b.Assert(os.Chdir(workDir), qt.IsNil)
-       _, err = exec.Command("npm", "install").CombinedOutput()
+       cmd, _ := hexec.SafeCommand("npm", "install")
+       _, err = cmd.CombinedOutput()
        b.Assert(err, qt.IsNil)
 
        b.Build(BuildCfg{})
 
        "math/rand"
        "os"
 
-       "os/exec"
+       "github.com/gohugoio/hugo/common/hexec"
+
        "path/filepath"
        "runtime"
        "strings"
        b.WithSourceFile("postcss.config.js", postcssConfig)
 
        b.Assert(os.Chdir(workDir), qt.IsNil)
-       _, err = exec.Command("npm", "install").CombinedOutput()
+       cmd, err := hexec.SafeCommand("npm", "install")
+       _, err = cmd.CombinedOutput()
        b.Assert(err, qt.IsNil)
        b.Build(BuildCfg{})
 
 
 
 import (
        "bytes"
-       "os/exec"
        "path/filepath"
 
+       "github.com/cli/safeexec"
+
        "github.com/gohugoio/hugo/identity"
        "github.com/gohugoio/hugo/markup/asciidocext/asciidocext_config"
        "github.com/gohugoio/hugo/markup/converter"
 }
 
 func getAsciidoctorExecPath() string {
-       path, err := exec.LookPath("asciidoctor")
+       path, err := safeexec.LookPath("asciidoctor")
        if err != nil {
                return ""
        }
 
 
 import (
        "bytes"
-       "os/exec"
        "strings"
 
+       "github.com/cli/safeexec"
+       "github.com/gohugoio/hugo/common/hexec"
+
        "github.com/gohugoio/hugo/markup/converter"
 )
 
        content []byte, path string, args []string) []byte {
 
        logger := cfg.Logger
-       cmd := exec.Command(path, args...)
+       cmd, err := hexec.SafeCommand(path, args...)
+       if err != nil {
+               logger.Errorf("%s rendering %s: %v", path, ctx.DocumentName, err)
+               return nil
+       }
        cmd.Stdin = bytes.NewReader(content)
        var out, cmderr bytes.Buffer
        cmd.Stdout = &out
        cmd.Stderr = &cmderr
-       err := cmd.Run()
+       err = cmd.Run()
        // Most external helpers exit w/ non-zero exit code only if severe, i.e.
        // halting errors occurred. -> log stderr output regardless of state of err
        for _, item := range strings.Split(cmderr.String(), "\n") {
 }
 
 func GetPythonExecPath() string {
-       path, err := exec.LookPath("python")
+       path, err := safeexec.LookPath("python")
        if err != nil {
-               path, err = exec.LookPath("python.exe")
+               path, err = safeexec.LookPath("python.exe")
                if err != nil {
                        return ""
                }
 
 package pandoc
 
 import (
-       "os/exec"
-
+       "github.com/cli/safeexec"
        "github.com/gohugoio/hugo/identity"
        "github.com/gohugoio/hugo/markup/internal"
 
 }
 
 func getPandocExecPath() string {
-       path, err := exec.LookPath("pandoc")
+       path, err := safeexec.LookPath("pandoc")
        if err != nil {
                return ""
        }
 
 
 import (
        "bytes"
-       "os/exec"
        "runtime"
 
+       "github.com/cli/safeexec"
+
        "github.com/gohugoio/hugo/identity"
        "github.com/gohugoio/hugo/markup/internal"
 
 }
 
 func getRstExecPath() string {
-       path, err := exec.LookPath("rst2html")
+       path, err := safeexec.LookPath("rst2html")
        if err != nil {
-               path, err = exec.LookPath("rst2html.py")
+               path, err = safeexec.LookPath("rst2html.py")
                if err != nil {
                        return ""
                }
 
        "path/filepath"
        "regexp"
 
+       "github.com/gohugoio/hugo/common/hexec"
+
        hglob "github.com/gohugoio/hugo/hugofs/glob"
 
        "github.com/gobwas/glob"
        }
 
        stderr := new(bytes.Buffer)
-       cmd := exec.CommandContext(ctx, "go", args...)
+       cmd, err := hexec.SafeCommandContext(ctx, "go", args...)
+       if err != nil {
+               return err
+       }
 
        cmd.Env = c.environ
        cmd.Dir = c.ccfg.WorkingDir
 
 
 import (
        "fmt"
-       "os/exec"
        "regexp"
        "sort"
        "strconv"
        "strings"
+
+       "github.com/gohugoio/hugo/common/hexec"
 )
 
 var issueRe = regexp.MustCompile(`(?i)[Updates?|Closes?|Fix.*|See] #(\d+)`)
 type gitInfos []gitInfo
 
 func git(args ...string) (string, error) {
-       cmd := exec.Command("git", args...)
+       cmd, _ := hexec.SafeCommand("git", args...)
        out, err := cmd.CombinedOutput()
        if err != nil {
                return "", fmt.Errorf("git failed: %q: %q (%q)", err, out, args)
 
        "io/ioutil"
        "log"
        "os"
-       "os/exec"
        "path/filepath"
        "regexp"
        "strings"
 
+       "github.com/gohugoio/hugo/common/hexec"
+
        "github.com/gohugoio/hugo/common/hugo"
        "github.com/pkg/errors"
 )
                args = append(args, "--skip-publish")
        }
 
-       cmd := exec.Command("goreleaser", args...)
+       cmd, _ := hexec.SafeCommand("goreleaser", args...)
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
        err := cmd.Run()
 
 import (
        "bytes"
        "io"
-       "os/exec"
        "path/filepath"
        "strconv"
 
+       "github.com/cli/safeexec"
+       "github.com/gohugoio/hugo/common/hexec"
        "github.com/gohugoio/hugo/common/loggers"
 
        "github.com/gohugoio/hugo/common/hugo"
 
        binary := csiBinPath
 
-       if _, err := exec.LookPath(binary); err != nil {
+       if _, err := safeexec.LookPath(binary); err != nil {
                // Try PATH
                binary = binaryName
-               if _, err := exec.LookPath(binary); err != nil {
+               if _, err := safeexec.LookPath(binary); err != nil {
 
                        // This may be on a CI server etc. Will fall back to pre-built assets.
                        return herrors.ErrFeatureNotAvailable
        }
        cmdArgs = append(cmdArgs, "--filename="+ctx.SourcePath)
 
-       cmd := exec.Command(binary, cmdArgs...)
+       cmd, err := hexec.SafeCommand(binary, cmdArgs...)
+       if err != nil {
+               return err
+       }
 
        cmd.Stdout = ctx.To
        cmd.Stderr = io.MultiWriter(infoW, &errBuf)
 
        "strconv"
        "strings"
 
+       "github.com/cli/safeexec"
+
+       "github.com/gohugoio/hugo/common/hexec"
+
        "github.com/gohugoio/hugo/common/hugo"
 
        "github.com/gohugoio/hugo/common/loggers"
        "github.com/gohugoio/hugo/hugofs"
        "github.com/pkg/errors"
 
-       "os/exec"
-
        "github.com/mitchellh/mapstructure"
 
        "github.com/gohugoio/hugo/common/herrors"
 
        binary := csiBinPath
 
-       if _, err := exec.LookPath(binary); err != nil {
+       if _, err := safeexec.LookPath(binary); err != nil {
                // Try PATH
                binary = binaryName
-               if _, err := exec.LookPath(binary); err != nil {
+               if _, err := safeexec.LookPath(binary); err != nil {
                        // This may be on a CI server etc. Will fall back to pre-built assets.
                        return herrors.ErrFeatureNotAvailable
                }
                cmdArgs = append(cmdArgs, optArgs...)
        }
 
-       cmd := exec.Command(binary, cmdArgs...)
+       cmd, err := hexec.SafeCommand(binary, cmdArgs...)
+       if err != nil {
+               return err
+       }
 
        var errBuf bytes.Buffer
        infoW := loggers.LoggerToWriterWithPrefix(logger.Info(), "postcss")
 
        "io/ioutil"
        "log"
        "os"
-       "os/exec"
        "path/filepath"
        "regexp"
        "strings"
 
+       "github.com/gohugoio/hugo/common/hexec"
+
        "github.com/gohugoio/hugo/common/hugio"
 
        "github.com/spf13/afero"
 }
 
 func rewrite(filename, rule string) {
-       cmf := exec.Command("gofmt", "-w", "-r", rule, filename)
+       cmf, _ := hexec.SafeCommand("gofmt", "-w", "-r", rule, filename)
        out, err := cmf.CombinedOutput()
        if err != nil {
                log.Fatal("gofmt failed:", string(out))
 }
 
 func goimports(dir string) {
-       cmf := exec.Command("goimports", "-w", dir)
+       cmf, _ := hexec.SafeCommand("goimports", "-w", dir)
        out, err := cmf.CombinedOutput()
        if err != nil {
                log.Fatal("goimports failed:", string(out))
 }
 
 func gofmt(dir string) {
-       cmf := exec.Command("gofmt", "-w", dir)
+       cmf, _ := hexec.SafeCommand("gofmt", "-w", dir)
        out, err := cmf.CombinedOutput()
        if err != nil {
                log.Fatal("gofmt failed:", string(out))
 
 import (
        "errors"
        "flag"
-       "github.com/gohugoio/hugo/tpl/internal/go_templates/cfg"
        "os"
        "os/exec"
        "path/filepath"
        "strings"
        "sync"
        "testing"
+
+       "github.com/cli/safeexec"
+       "github.com/gohugoio/hugo/tpl/internal/go_templates/cfg"
 )
 
 // Builder reports the name of the builder running this test
        if _, err := os.Stat(path); err == nil {
                return path, nil
        }
-       goBin, err := exec.LookPath("go" + exeSuffix)
+       goBin, err := safeexec.LookPath("go" + exeSuffix)
        if err != nil {
                return "", errors.New("cannot find go tool: " + err.Error())
        }
 
        err, found := execPaths.Load(path)
        if !found {
-               _, err = exec.LookPath(path)
+               _, err = safeexec.LookPath(path)
                err, _ = execPaths.LoadOrStore(path, err)
        }
        if err != nil {