go.template.security.ssti.go-ssti

profile photo of returntocorpreturntocorp
Author
unknown
Download Count*

A server-side template injection occurs when an attacker is able to use native template syntax to inject a malicious payload into a template, which is then executed server-side. When using "html/template" always check that user inputs are validated and sanitized before included within the template.

Run Locally

Run in CI

Defintion

rules:
  - id: go-ssti
    patterns:
      - pattern-inside: |
          import ("html/template")
          ...
      - pattern: $TEMPLATE = fmt.Sprintf("...", $ARG, ...)
      - patterns:
          - pattern-either:
              - pattern-inside: |
                  func $FN(..., $REQ *http.Request, ...){
                  ...
                  }
              - pattern-inside: |
                  func $FN(..., $REQ http.Request, ...){
                  ...
                  }
              - pattern-inside: |
                  func(..., $REQ *http.Request, ...){
                  ...
                  }
      - patterns:
          - pattern-either:
              - pattern-inside: |
                  $ARG := $REQ.URL.Query().Get(...)
                  ...
                  $T, $ERR := $TMPL.Parse($TEMPLATE)
              - pattern-inside: |
                  $ARG := $REQ.Form.Get(...)
                  ...
                  $T, $ERR := $TMPL.Parse($TEMPLATE)
              - pattern-inside: |
                  $ARG := $REQ.PostForm.Get(...)
                  ...
                  $T, $ERR := $TMPL.Parse($TEMPLATE)
    message: A server-side template injection occurs when an attacker is able to use
      native template syntax to inject a malicious payload into a template,
      which is then executed server-side. When using "html/template" always
      check that user inputs are validated and sanitized before included within
      the template.
    languages:
      - go
    severity: ERROR
    metadata:
      category: security
      cwe:
        - "CWE-1336: Improper Neutralization of Special Elements Used in a
          Template Engine"
      references:
        - https://www.onsecurity.io/blog/go-ssti-method-research/
        - http://blog.takemyhand.xyz/2020/05/ssti-breaking-gos-template-engine-to.html
      technology:
        - go
      confidence: MEDIUM
      subcategory:
        - vuln
      likelihood: LOW
      impact: HIGH
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]

Examples

ssti.go

package main

import (
	"fmt"
	"html/template"
	"net/http"
)

type User struct {
	ID       int
	Email    string
	Password string
}

func match1(w http.ResponseWriter, req *http.Request) {

	var user1 = &User{1, "user@gmail.com", "Sup3rSecr3t123!"}
	query := req.URL.Query().Get("query")
	// ruleid:go-ssti
	var text = fmt.Sprintf(`
	<html>
	<head>
	<title>SSTI</title>
	</head>
	<body>
		<h2>Hello {{ .Email }}</h2>
		<p>Search result for %s</p>
	</body></html>
	`, query)
	tmpl := template.New("hello")
	tmpl, err := tmpl.Parse(text)
	if err != nil {
		fmt.Println(err)
	}
	tmpl.Execute(w, user1)
}

func match2(w http.ResponseWriter, req *http.Request) {

	var user1 = &User{1, "user@gmail.com", "Sup3rSecr3t123!"}
	if err := req.ParseForm(); err != nil {
		fmt.Fprintf(w, "ParseForm() err: %v", err)
		return
	}
	query := req.Form.Get("query")
	// ruleid:go-ssti
	var text = fmt.Sprintf(`
	<html>
	<head>
	<title>SSTI</title>
	</head>
	<body>
		<h2>Hello {{ .Email }}</h2>
		<p>Search result for %s</p>
	</body></html>
	`, query)
	tmpl := template.New("hello")
	tmpl, err := tmpl.Parse(text)
	if err != nil {
		fmt.Println(err)
	}
	tmpl.Execute(w, user1)
}

func no_match(w http.ResponseWriter, req *http.Request) {

	var user1 = &User{1, "user@gmail.com", "Sup3rSecr3t123!"}
	query := "constant string"
	// ok:go-ssti
	var text = fmt.Sprintf(`
	<html>
	<head>
	<title>SSTI</title>
	</head>
	<body>
		<h2>Hello {{ .Email }}</h2>
		<p>Search result for %s</p>
	</body></html>
	`, query)
	tmpl := template.New("hello")
	tmpl, err := tmpl.Parse(text)
	if err != nil {
		fmt.Println(err)
	}
	tmpl.Execute(w, user1)
}