README.md
1## `filepath-securejoin` ##
2
3[![Build Status](https://travis-ci.org/cyphar/filepath-securejoin.svg?branch=master)](https://travis-ci.org/cyphar/filepath-securejoin)
4
5An implementation of `SecureJoin`, a [candidate for inclusion in the Go
6standard library][go#20126]. The purpose of this function is to be a "secure"
7alternative to `filepath.Join`, and in particular it provides certain
8guarantees that are not provided by `filepath.Join`.
9
10This is the function prototype:
11
12```go
13func SecureJoin(root, unsafePath string) (string, error)
14```
15
16This library **guarantees** the following:
17
18* If no error is set, the resulting string **must** be a child path of
19 `SecureJoin` and will not contain any symlink path components (they will all
20 be expanded).
21
22* When expanding symlinks, all symlink path components **must** be resolved
23 relative to the provided root. In particular, this can be considered a
24 userspace implementation of how `chroot(2)` operates on file paths. Note that
25 these symlinks will **not** be expanded lexically (`filepath.Clean` is not
26 called on the input before processing).
27
28* Non-existant path components are unaffected by `SecureJoin` (similar to
29 `filepath.EvalSymlinks`'s semantics).
30
31* The returned path will always be `filepath.Clean`ed and thus not contain any
32 `..` components.
33
34A (trivial) implementation of this function on GNU/Linux systems could be done
35with the following (note that this requires root privileges and is far more
36opaque than the implementation in this library, and also requires that
37`readlink` is inside the `root` path):
38
39```go
40package securejoin
41
42import (
43 "os/exec"
44 "path/filepath"
45)
46
47func SecureJoin(root, unsafePath string) (string, error) {
48 unsafePath = string(filepath.Separator) + unsafePath
49 cmd := exec.Command("chroot", root,
50 "readlink", "--canonicalize-missing", "--no-newline", unsafePath)
51 output, err := cmd.CombinedOutput()
52 if err != nil {
53 return "", err
54 }
55 expanded := string(output)
56 return filepath.Join(root, expanded), nil
57}
58```
59
60[go#20126]: https://github.com/golang/go/issues/20126
61
62### License ###
63
64The license of this project is the same as Go, which is a BSD 3-clause license
65available in the `LICENSE` file.
66