types: accept only lowercase hex in auth IDs

This commit is contained in:
Kristoffer Dalby committed 2026-11-02 19:15:40 +01:00
1 parent c8e97384d7
commit 87c9659b20
3 files changed
+53 -3

No files matched your search

-3
View File
@@ -377,9 +377,6 @@ func authIDFromRequest(req *http.Request) (types.AuthID, error) {
return "", NewHTTPError(http.StatusBadRequest, "invalid auth id", fmt.Errorf("parsing auth_id from URL: %w", err))
}
// We need to make sure we dont open for XSS style injections, if the parameter that
// is passed as a key is not parsable/validated as a NodePublic key, then fail to render
// the template and log an error.
authId, err := types.AuthIDFromString(raw)
if err != nil {
return "", NewHTTPError(http.StatusBadRequest, "invalid auth id", fmt.Errorf("parsing auth_id from URL: %w", err))
+8
View File
@@ -26,6 +26,7 @@ var (
ErrCannotParsePrefix = errors.New("cannot parse prefix")
ErrInvalidAuthIDLength = errors.New("auth ID has invalid length")
ErrInvalidAuthIDPrefix = errors.New("auth ID has invalid prefix")
ErrInvalidAuthIDChars = errors.New("auth ID has invalid characters")
ErrRegistrationPayloadTooLarge = errors.New("registration payload exceeds size limit")
)
@@ -81,6 +82,13 @@ func (r AuthID) Validate() error {
)
}
for i := len(authIDPrefix); i < len(r); i++ {
c := r[i]
if (c < '0' || c > '9') && (c < 'a' || c > 'f') {
return ErrInvalidAuthIDChars
}
}
return nil
}
+45
View File
@@ -305,3 +305,48 @@ func TestDefaultBatcherWorkers(t *testing.T) {
t.Errorf("DefaultBatcherWorkers() = %d, expected value >= 1", result)
}
}
func TestAuthIDFromStringRejectsNonHex(t *testing.T) {
generated := MustAuthID()
parsed, err := AuthIDFromString(generated.String())
require.NoError(t, err)
require.Equal(t, generated, parsed)
_, err = AuthIDFromString(authIDPrefix + "0123456789abcdef01234567")
require.NoError(t, err)
_, err = AuthIDFromString("wrong-prefix" + strings.Repeat(";", authIDRandomLength))
require.ErrorIs(t, err, ErrInvalidAuthIDPrefix)
_, err = AuthIDFromString(authIDPrefix + ";")
require.ErrorIs(t, err, ErrInvalidAuthIDLength)
for _, tt := range []struct {
name string
bad string
}{
{name: "semicolon", bad: ";"},
{name: "substitution", bad: "$()"},
{name: "space", bad: " "},
{name: "newline", bad: "\n"},
{name: "uppercase", bad: "A"},
{name: "beyond f", bad: "g"},
{name: "underscore", bad: "_"},
{name: "non-ASCII", bad: "é"},
} {
for _, position := range []string{"start", "end"} {
t.Run(tt.name+"/"+position, func(t *testing.T) {
padding := strings.Repeat("a", authIDRandomLength-len(tt.bad))
suffix := tt.bad + padding
if position == "end" {
suffix = padding + tt.bad
}
parsed, err := AuthIDFromString(authIDPrefix + suffix)
require.ErrorIs(t, err, ErrInvalidAuthIDChars)
require.Empty(t, parsed)
})
}
}
}