test(security): webtest that a deleted link share rejects its still-valid JWT
End-to-end regression test for GHSA-96q5-xm3p-7m84 / CVE-2026-35594: mints a JWT for a link share via the real helper, then deletes the share row and invokes the real ReadAllWeb handler to prove the full request path (not just the unit-tested GetLinkShareFromClaims) surfaces the revocation. Also fixes a pre-existing stale literal in the TestLinkSharing test fixture struct: linkshareRead declared Hash="test1" while the actual fixture row id=1 uses Hash="test". The old code never looked at the DB so the mismatch went unnoticed; after the fix it would cause every link-share webtest that used linkshareRead to fail hash validation.
This commit is contained in:
parent
e025209e3c
commit
379d8a5c19
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
"code.vikunja.io/api/pkg/web/handler"
|
"code.vikunja.io/api/pkg/web/handler"
|
||||||
|
|
||||||
|
|
@ -31,7 +32,7 @@ func TestLinkSharing(t *testing.T) {
|
||||||
|
|
||||||
linkshareRead := &models.LinkSharing{
|
linkshareRead := &models.LinkSharing{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Hash: "test1",
|
Hash: "test", // must match pkg/db/fixtures/link_shares.yml id=1
|
||||||
ProjectID: 1,
|
ProjectID: 1,
|
||||||
Permission: models.PermissionRead,
|
Permission: models.PermissionRead,
|
||||||
SharingType: models.SharingTypeWithoutPassword,
|
SharingType: models.SharingTypeWithoutPassword,
|
||||||
|
|
@ -807,4 +808,30 @@ func TestLinkSharing(t *testing.T) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Regression test for GHSA-96q5-xm3p-7m84 / CVE-2026-35594: a still-valid
|
||||||
|
// link share JWT must be rejected once its DB row is gone.
|
||||||
|
//
|
||||||
|
// bootstrapTestRequest reloads fixtures, so the row must be deleted
|
||||||
|
// AFTER bootstrapping, otherwise the reload restores it.
|
||||||
|
t.Run("Deleted share rejects its still-valid JWT", func(t *testing.T) {
|
||||||
|
projectReadAllHandler := handler.WebHandler{
|
||||||
|
EmptyStruct: func() handler.CObject {
|
||||||
|
return &models.Project{}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
c, _ := bootstrapTestRequest(t, "GET", "", nil, nil)
|
||||||
|
addLinkShareTokenToContext(t, linkshareRead, c)
|
||||||
|
|
||||||
|
sess := db.NewSession()
|
||||||
|
defer sess.Close()
|
||||||
|
_, err := sess.Where("id = ?", 1).Delete(&models.LinkSharing{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, sess.Commit())
|
||||||
|
|
||||||
|
err = projectReadAllHandler.ReadAllWeb(c)
|
||||||
|
require.Error(t, err)
|
||||||
|
assertHandlerErrorCode(t, err, models.ErrCodeLinkShareTokenInvalid)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue