fix(DB): validates db name for path traversal

This commit is contained in:
Lewis Wynne 2025-12-18 15:04:32 +00:00
parent 3e3c55d0b6
commit e806bd9046
4 changed files with 45 additions and 2 deletions

View file

@ -51,6 +51,9 @@ func ParseKey(raw string, defaults bool) (KeySpec, error) {
if strings.TrimSpace(rawDB) == "" {
return KeySpec{}, fmt.Errorf("bad key format, use KEY@DB")
}
if err := validateDBName(rawDB); err != nil {
return KeySpec{}, err
}
}
key := strings.ToLower(rawKey)

View file

@ -178,6 +178,9 @@ func (s *Store) parseDB(v string, defaults bool) (string, error) {
}
return "", fmt.Errorf("cannot parse db: bad db format, use DB or @DB")
}
if err := validateDBName(db); err != nil {
return "", fmt.Errorf("cannot parse db: %w", err)
}
return strings.ToLower(db), nil
}
@ -197,7 +200,11 @@ func (s *Store) path(args ...string) (string, error) {
if err := os.MkdirAll(override, 0o750); err != nil {
return "", err
}
return filepath.Join(append([]string{override}, args...)...), nil
target := filepath.Join(append([]string{override}, args...)...)
if err := ensureSubpath(override, target); err != nil {
return "", err
}
return target, nil
}
scope := gap.NewVendorScope(gap.User, "pda", "stores")
dir, err := scope.DataPath("")
@ -207,7 +214,11 @@ func (s *Store) path(args ...string) (string, error) {
if err := os.MkdirAll(dir, 0o750); err != nil {
return "", err
}
return filepath.Join(append([]string{dir}, args...)...), nil
target := filepath.Join(append([]string{dir}, args...)...)
if err := ensureSubpath(dir, target); err != nil {
return "", err
}
return target, nil
}
func (s *Store) suggestStores(target string) ([]string, error) {
@ -229,6 +240,33 @@ func (s *Store) suggestStores(target string) ([]string, error) {
return suggestions, nil
}
func ensureSubpath(base, target string) error {
absBase, err := filepath.Abs(base)
if err != nil {
return err
}
absTarget, err := filepath.Abs(target)
if err != nil {
return err
}
rel, err := filepath.Rel(absBase, absTarget)
if err != nil {
return err
}
sep := string(filepath.Separator)
if rel == ".." || strings.HasPrefix(rel, ".."+sep) {
return fmt.Errorf("path escapes store root")
}
return nil
}
func validateDBName(name string) error {
if strings.ContainsAny(name, `/\`) {
return fmt.Errorf("bad db format, use DB or @DB")
}
return nil
}
func formatExpiry(expiresAt uint64) string {
if expiresAt == 0 {
return "never"

View file

@ -19,6 +19,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package main
import "github.com/llywelwyn/pda/cmd"

View file

@ -19,6 +19,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package main
import (