mirror of
https://github.com/FiloSottile/age.git
synced 2025-12-23 05:25:14 +00:00
plugin: restrict characters in plugin names
Thanks to ⬡-49016 for reporting this issue. Fixes GHSA-32gq-x56h-299c
This commit is contained in:
14
cmd/age/testdata/plugin.txt
vendored
14
cmd/age/testdata/plugin.txt
vendored
@@ -10,6 +10,15 @@ age -d -i long-key.txt test.age
|
||||
cmp stdout input
|
||||
! stderr .
|
||||
|
||||
# check that path separators are rejected
|
||||
chmod 755 age-plugin-pwn/pwn
|
||||
mkdir $TMPDIR/age-plugin-pwn
|
||||
cp age-plugin-pwn/pwn $TMPDIR/age-plugin-pwn/pwn
|
||||
! age -r age1pwn/pwn19gt89dfz input
|
||||
! age -d -i pwn-identity.txt test.age
|
||||
! age -d -j pwn/pwn test.age
|
||||
! exists pwn
|
||||
|
||||
-- input --
|
||||
test
|
||||
-- key.txt --
|
||||
@@ -18,3 +27,8 @@ AGE-PLUGIN-TEST-10Q32NLXM
|
||||
age1test10pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7qj6rl8p
|
||||
-- long-key.txt --
|
||||
AGE-PLUGIN-TEST-10PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7RC0PU8S7Q5U8SUD
|
||||
-- pwn-identity.txt --
|
||||
AGE-PLUGIN-PWN/PWN-19GYK4WLY
|
||||
-- age-plugin-pwn/pwn --
|
||||
#!/bin/sh
|
||||
touch "$WORK/pwn"
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
exec "golang.org/x/sys/execabs"
|
||||
@@ -178,6 +179,9 @@ func NewIdentity(s string, ui *ClientUI) (*Identity, error) {
|
||||
|
||||
func NewIdentityWithoutData(name string, ui *ClientUI) (*Identity, error) {
|
||||
s := EncodeIdentity(name, nil)
|
||||
if s == "" {
|
||||
return nil, fmt.Errorf("invalid plugin name: %q", name)
|
||||
}
|
||||
return &Identity{
|
||||
name: name, encoding: s, ui: ui,
|
||||
}, nil
|
||||
@@ -390,6 +394,8 @@ func openClientConnection(name, protocol string) (*clientConnection, error) {
|
||||
path := "age-plugin-" + name
|
||||
if testOnlyPluginPath != "" {
|
||||
path = filepath.Join(testOnlyPluginPath, path)
|
||||
} else if strings.ContainsRune(name, os.PathSeparator) {
|
||||
return nil, fmt.Errorf("invalid plugin name: %q", name)
|
||||
}
|
||||
cmd := exec.Command(path, "--age-plugin="+protocol)
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@ import (
|
||||
// EncodeIdentity encodes a plugin identity string for a plugin with the given
|
||||
// name. If the name is invalid, it returns an empty string.
|
||||
func EncodeIdentity(name string, data []byte) string {
|
||||
if !validPluginName(name) {
|
||||
return ""
|
||||
}
|
||||
s, _ := bech32.Encode("AGE-PLUGIN-"+strings.ToUpper(name)+"-", data)
|
||||
return s
|
||||
}
|
||||
@@ -30,12 +33,18 @@ func ParseIdentity(s string) (name string, data []byte, err error) {
|
||||
}
|
||||
name = strings.TrimSuffix(strings.TrimPrefix(hrp, "AGE-PLUGIN-"), "-")
|
||||
name = strings.ToLower(name)
|
||||
if !validPluginName(name) {
|
||||
return "", nil, fmt.Errorf("invalid plugin name: %q", name)
|
||||
}
|
||||
return name, data, nil
|
||||
}
|
||||
|
||||
// EncodeRecipient encodes a plugin recipient string for a plugin with the given
|
||||
// name. If the name is invalid, it returns an empty string.
|
||||
func EncodeRecipient(name string, data []byte) string {
|
||||
if !validPluginName(name) {
|
||||
return ""
|
||||
}
|
||||
s, _ := bech32.Encode("age1"+strings.ToLower(name), data)
|
||||
return s
|
||||
}
|
||||
@@ -51,5 +60,21 @@ func ParseRecipient(s string) (name string, data []byte, err error) {
|
||||
return "", nil, fmt.Errorf("not a plugin recipient: %v", err)
|
||||
}
|
||||
name = strings.TrimPrefix(hrp, "age1")
|
||||
if !validPluginName(name) {
|
||||
return "", nil, fmt.Errorf("invalid plugin name: %q", name)
|
||||
}
|
||||
return name, data, nil
|
||||
}
|
||||
|
||||
func validPluginName(name string) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
}
|
||||
allowed := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-._"
|
||||
for _, r := range name {
|
||||
if !strings.ContainsRune(allowed, r) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user