Skip to content

Commit 39a3d33

Browse files
authored
fix(certifier): harden request validation and prevent info leakage (#1498)
Signed-off-by: atharrva01 <atharvaborade568@gmail.com>
1 parent d6592ab commit 39a3d33

2 files changed

Lines changed: 33 additions & 1 deletion

File tree

token/services/certifier/interactive/config.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,14 @@ const (
2727
// DefaultResponseTimeout is the maximum time the client waits for the certifier
2828
// to respond before treating the request as failed.
2929
DefaultResponseTimeout = 60 * time.Second
30+
31+
// MaxTokensPerRequest is the maximum number of token IDs accepted in a single
32+
// certification request. Requests exceeding this limit are rejected to prevent
33+
// resource exhaustion on the certifier node.
34+
MaxTokensPerRequest = 500
35+
36+
// MaxRequestBytes is the maximum byte-length of the cryptographic request payload
37+
// in a CertificationRequest. Requests exceeding this limit are rejected to prevent
38+
// memory exhaustion on the certifier node.
39+
MaxRequestBytes = 1 << 20 // 1 MiB
3040
)

token/services/certifier/interactive/service.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,14 @@ func (c *CertificationService) Call(context view.Context) (interface{}, error) {
8989
return nil, errors.Errorf("invalid certification request: no token IDs provided [%s]", cr)
9090
}
9191

92+
if len(cr.IDs) > MaxTokensPerRequest {
93+
return nil, errors.Errorf("invalid certification request: too many token IDs (%d > %d) [%s]", len(cr.IDs), MaxTokensPerRequest, cr)
94+
}
95+
96+
if len(cr.Request) > MaxRequestBytes {
97+
return nil, errors.Errorf("invalid certification request: request payload too large (%d > %d bytes) [%s]", len(cr.Request), MaxRequestBytes, cr)
98+
}
99+
92100
logger.Debugf("received certification request [%v]", cr)
93101

94102
// 3. load token outputs
@@ -97,6 +105,13 @@ func (c *CertificationService) Call(context view.Context) (interface{}, error) {
97105
return nil, errors.WithMessagef(err, "failed getting tokens [%s:%s][%v]", cr.Channel, cr.Namespace, cr.IDs)
98106
}
99107

108+
if len(tokenOutputs) != len(cr.IDs) {
109+
return nil, errors.Errorf(
110+
"token output count mismatch: backend returned %d outputs for %d IDs [%s]",
111+
len(tokenOutputs), len(cr.IDs), cr,
112+
)
113+
}
114+
100115
// 4. certify token output
101116
logger.Debugf("certify commitments for [%v]...", cr.IDs)
102117
tms, err := token2.GetManagementService(
@@ -160,7 +175,7 @@ type CertificationRequest struct {
160175
}
161176

162177
func (cr *CertificationRequest) String() string {
163-
return fmt.Sprintf("CertificationRequest[%s,%s,%s][%v]", cr.Request, cr.Channel, cr.Namespace, cr.IDs)
178+
return fmt.Sprintf("CertificationRequest[%s:%s:%s][ids=%d,req=%d bytes]", cr.Network, cr.Channel, cr.Namespace, len(cr.IDs), len(cr.Request))
164179
}
165180

166181
type CertificationRequestView struct {
@@ -252,6 +267,13 @@ func (i *CertificationRequestView) Call(context view.Context) (interface{}, erro
252267
return nil, errors.WithMessagef(err, "failed verifying certifications of [%v] from [%s]", i.ids, i.certifier)
253268
}
254269

270+
if len(processedCertifications) != len(i.ids) {
271+
return nil, errors.Errorf(
272+
"certification manager returned %d processed certifications for %d token IDs from [%s]",
273+
len(processedCertifications), len(i.ids), i.certifier,
274+
)
275+
}
276+
255277
logger.Debugf("certifications of [%v] from [%s] are valid", i.ids, i.certifier)
256278

257279
// 5. return token certifications in the form of a map

0 commit comments

Comments
 (0)