Fix remote code execution vulnerability in the PDF OCR converter (#110)

ENG-3252
This commit is contained in:
Helena Mariano
2022-07-07 14:16:47 +10:00
committed by GitHub
parent 44d6739947
commit b19021ade3
2 changed files with 53 additions and 1 deletions
+23 -1
View File
@@ -1,3 +1,4 @@
//go:build ocr
// +build ocr // +build ocr
package docconv package docconv
@@ -10,6 +11,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp"
"strings" "strings"
"sync" "sync"
) )
@@ -111,7 +113,8 @@ func ConvertPDFImages(path string) (BodyResult, error) {
// PdfHasImage verify if `path` (PDF) has images // PdfHasImage verify if `path` (PDF) has images
func PDFHasImage(path string) bool { func PDFHasImage(path string) bool {
cmd := "pdffonts -l 5 %s | tail -n +3 | cut -d' ' -f1 | sort | uniq" cmd := "pdffonts -l 5 %s | tail -n +3 | cut -d' ' -f1 | sort | uniq"
out, err := exec.Command("bash", "-c", fmt.Sprintf(cmd, path)).Output() out, err := exec.Command("bash", "-c", fmt.Sprintf(cmd, shellEscape(path))).CombinedOutput()
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return false return false
@@ -159,3 +162,22 @@ func ConvertPDF(r io.Reader) (string, map[string]string, error) {
return fullBody, metaResult.meta, nil return fullBody, metaResult.meta, nil
} }
var shellEscapePattern *regexp.Regexp
func init() {
shellEscapePattern = regexp.MustCompile(`[^\w@%+=:,./-]`)
}
// shellEscape returns a shell-escaped version of the string s. The returned value
// is a string that can safely be used as one token in a shell command line.
func shellEscape(s string) string {
if len(s) == 0 {
return "''"
}
if shellEscapePattern.MatchString(s) {
return "'" + strings.Replace(s, "'", "'\"'\"'", -1) + "'"
}
return s
}
+30
View File
@@ -0,0 +1,30 @@
//go:build ocr
// +build ocr
package docconv
import (
"os"
"testing"
)
func TestPDFHasImage_CannotExecuteCode(t *testing.T) {
// Try to inject code by passing a bad file path.
// If the code was successful it will create a file called foo in the working directory
badFilePath := "$(id >> foo).pdf"
if got, want := PDFHasImage(badFilePath), false; got != want {
t.Errorf("got %v, want %v", got, want)
}
if got, want := fileExists("foo"), false; got != want {
t.Errorf("got bad file exists, want not file to exist")
}
}
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}