Documentation
¶
Overview ¶
Package io provides guarded file I/O wrappers for ctx.
What these functions guard against ¶
All Safe* functions apply two checks before touching the filesystem:
- Path cleaning: filepath.Clean removes redundant separators, dot segments, and trailing slashes.
- System prefix rejection: the resolved absolute path is checked against a deny list of system directories (/bin, /etc, /proc, /sys, /dev, /boot, /lib, /sbin, /usr/bin, /usr/lib, /usr/sbin, and the filesystem root itself). Any match returns an error before the underlying syscall executes.
SafeReadFile additionally enforces containment: the resolved path must stay within the provided base directory.
What these functions do NOT guard against ¶
- Symlink attacks: a cleaned path that passes the prefix check could still resolve to a different location through a symlink in a parent directory. Use [validation.CheckSymlinks] separately when the directory tree is untrusted.
- Race conditions (TOCTOU): the check and the I/O are not atomic. A malicious actor with write access to the parent directory could swap a path between validation and use.
- Permission escalation: these wrappers run with the calling process's permissions. They do not drop privileges.
- Content validation: the wrappers check where data is read from or written to, not what the data contains.
- Windows paths: the deny list uses Unix prefixes. On Windows, the prefix check is effectively a no-op.
Assumptions ¶
Callers are expected to provide paths that are already logically correct (e.g., constructed from known config constants or user input that has been validated for format). These wrappers are a safety net against accidental system directory access, not a substitute for input validation at the application boundary.
When to use which function ¶
- SafeReadFile: path is base + filename (boundary-checked read)
- SafeReadUserFile: single path from any source (deny-list read)
- SafeOpenUserFile: single path, need a file handle (deny-list open)
- SafeWriteFile: single path (deny-list write)
Index ¶
- func SafeAppendFile(path string, perm os.FileMode) (*os.File, error)
- func SafeCreateFile(path string, perm os.FileMode) (*os.File, error)
- func SafeOpenUserFile(path string) (*os.File, error)
- func SafePost(rawURL, contentType string, body []byte, timeout time.Duration) (*http.Response, error)
- func SafeReadFile(baseDir, filename string) ([]byte, error)
- func SafeReadUserFile(path string) ([]byte, error)
- func SafeWriteFile(path string, data []byte, perm os.FileMode) error
- func TouchFile(path string)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func SafeAppendFile ¶
SafeAppendFile opens a file for appending after cleaning the path and rejecting system directory prefixes. Creates the file if it does not exist.
Parameters:
- path: file path to open
- perm: file permission bits used when creating the file
Returns:
- *os.File: open file handle in append mode (caller must close)
- error: non-nil on validation or open failure
func SafeCreateFile ¶
SafeCreateFile creates a new file for writing after cleaning the path and rejecting system directory prefixes. If the file already exists it is truncated.
Parameters:
- path: file path to create
- perm: file permission bits
Returns:
- *os.File: open file handle (caller must close)
- error: non-nil on validation or create failure
func SafeOpenUserFile ¶
SafeOpenUserFile opens a file for reading after cleaning the path and rejecting system directory prefixes.
Parameters:
- path: file path to open
Returns:
- *os.File: open file handle (caller must close)
- error: non-nil on validation or open failure
func SafePost ¶
func SafePost( rawURL, contentType string, body []byte, timeout time.Duration, ) (*http.Response, error)
SafePost sends an HTTP POST with the given content type and body.
Designed for static endpoint URLs that originate from trusted, user-configured sources (e.g., webhook URLs stored in AES-256-GCM encrypted storage). Centralizes gosec suppression so callers don't each need their own nolint pragma.
Protections applied:
- Scheme validation: rejects everything except http and https, preventing file://, gopher://, and other protocol smuggling.
- Redirect cap: follows at most 3 redirects (Go default is 10). Limits open-redirect abuse where a trusted URL bounces to an unintended destination.
- Caller-specified timeout: bounds total request duration including redirects.
Threats explicitly not mitigated (and why that is acceptable):
- SSRF to private IPs: the URL is a static, user-configured endpoint (not attacker-controlled input). Blocking RFC 1918 ranges would break legitimate local webhook receivers.
- Response body size: callers are fire-and-forget (close body immediately), so unbounded reads are not a concern.
- TLS certificate pinning: the endpoint is user-chosen; standard system CA validation is appropriate.
Parameters:
- rawURL: destination endpoint (trusted, user-configured origin)
- contentType: MIME type for the Content-Type header
- body: request payload
- timeout: per-request timeout (includes redirect hops)
Returns:
- *http.Response: the HTTP response (caller must close Body)
- error: on scheme validation failure, redirect cap, or HTTP error
func SafeReadFile ¶
SafeReadFile resolves filename within baseDir, verifies the result stays within the base directory boundary, and reads the file content.
Unlike SafeReadUserFile, this function enforces containment: the resolved path must remain under baseDir. Use it when the path is constructed from a trusted base and a filename component.
Parameters:
- baseDir: trusted root directory
- filename: file name (or relative path) to join and validate
Returns:
- []byte: file content
- error: non-nil if resolution fails, path escapes baseDir, or read fails
func SafeReadUserFile ¶
SafeReadUserFile reads a file after cleaning the path and rejecting system directory prefixes.
Parameters:
- path: file path to read
Returns:
- []byte: file content
- error: non-nil on validation or read failure
func SafeWriteFile ¶
SafeWriteFile writes data to a file after cleaning the path and rejecting system directory prefixes.
Parameters:
- path: file path to write
- data: content to write
- perm: file permission bits
Returns:
- error: non-nil on validation or write failure
Types ¶
This section is empty.