tl;dr: Don't print untrusted data, escape it first. If in doubt or a hurry, use %q instead of %s.
Go's string formatting methods are, indeed, memory-safe, and the specific class of vulnerabilities you're worried about and which were so prevalent in C are not applicable.
However, it is not generally safe in any language to output untrusted, unsanitized input via any means without careful consideration. One well-known example of why is cross-site scripting. Less well-known than XSS attacks, however, are terminal escape sequence attacks.
Common terminals respond to a wide variety of escape sequences that can potentially do nasty things directly, or to help exploit another vulnerability. Attackers can include these sequences in messages to a targeted system - say, in the URL of a request to a webserver - and await an admin cat
ing the logs or similar. This can also be used to hide information - including backspace sequences effectively hides whatever came before from view in a terminal.
The quickest option is to simply use %q
instead of %s
. This outputs the string as a Go string literal, suitable for use in Go source code. This is convenient and safe for printing, but if you're trying to match a specific format, may not be ideal. (strconv.Quote(s string) string
will also perform the same operation directly).
This answer to another question has a more involved but easily customized option using strings.Map, however in the given form it removes all non-printable characters rather than escaping them.
One way or another, sanitize your output. You will save someone a lot of pain later, possibly yourself.
package main
import (
"fmt"
"strconv"
)
func main() {
s := "a string with some control\x08\x08\x08\x08\x08\x08\x08hidden characters"
// Prints with the control characters intact. Terminal output:
// a string with some hidden characters
fmt.Printf("%s\n", s)
// Prints as Go string literal. Terminal output:
// "a string with some control\b\b\b\b\b\b\bhidden characters"
fmt.Printf("%q\n", s)
// Prints as Go string literal, but without surrounding double-quotes.
// Terminal output:
// a string with some control\b\b\b\b\b\b\bhidden characters
x := strconv.Quote(s)
fmt.Printf("%s\n", x[1:len(x)-1])
}