Description
Predictable filenames or excessive permissions in shared directories such as /tmp can expose temporary files. Another user may create the name first or place a symbolic link there, causing a program to overwrite an unintended file. Other users may also read or modify inadequately protected contents.
Potential impact
- File precreation or symbolic links may redirect writes to configuration or log files.
- Excessive permissions may expose sensitive temporary data.
- A privileged application may be tricked into overwriting protected system files.
Remediation
- Use
os.CreateTempor the olderioutil.TempFile, which delegates to it, to create files with randomized names. - Avoid fixed names such as
/tmp/myfile; supply a prefix and let the library generate the rest. os.CreateTempcreates files with0o600permissions before the umask. Ensure the directory and file permissions prevent modification by other users.- Remove files with
os.Removeas soon as they are no longer needed. - Avoid temporary filesystem storage of passwords, tokens, or personal data where possible; use memory or appropriate secure storage.
Examples
Before
go
package main
import (
"fmt"
"os"
)
func unsafeTemp() {
// Before: use a fixed filename under /tmp
path := "/tmp/report.log"
// Another user or process may create this filename first
// or place a symbolic link at that path
f, err := os.Create(path)
if err != nil {
fmt.Println("failed to create temp file:", err)
return
}
defer f.Close()
// Default permissions, such as 0644, may allow
// other users to read the contents
if _, err := f.WriteString("user session token: abc123\n"); err != nil {
fmt.Println("failed to write:", err)
return
}
}
func main() {
unsafeTemp()
}
After
go
package main
import (
"fmt"
"os"
)
func safeTemp() {
// Create a temporary file in /tmp using the report- prefix
// A random suffix reduces filename collisions
f, err := os.CreateTemp("/tmp", "report-")
if err != nil {
fmt.Println("failed to create temp file:", err)
return
}
// Save the name and schedule removal with defer
tempName := f.Name()
defer os.Remove(tempName)
defer f.Close()
// Restrict permissions for sensitive data, for example to 0600
if err := os.Chmod(tempName, 0o600); err != nil {
fmt.Println("failed to chmod temp file:", err)
return
}
if _, err := f.WriteString("temporary processing data\n"); err != nil {
fmt.Println("failed to write:", err)
return
}
fmt.Println("temp file created:", tempName)
}
func main() {
safeTemp()
}
Explanation:
- Before: The fixed
/tmp/report.logname allows precreation, symbolic-link substitution, or collisions between processes. Default permissions may also expose the file to other users. - After:
os.CreateTempcreates a unique file with a randomized name and0o600permissions from the start. The example'sos.Chmodreapplies that mode. Deferred cleanup removes the file after use, reducing the chance that sensitive temporary data remains on disk.