cosmo icon indicating copy to clipboard operation
cosmo copied to clipboard

Variable validation errors leak entire variable in statusMessage telemetry.

Open Sam-tesouro opened this issue 1 year ago • 4 comments

Component(s)

router, studio, otelcollector

Is your feature request related to a problem? Please describe.

When a request to a federated Supergraph doesn't match spec and an $variable is used for input the entire $variable is leaked on the statusMessage via telemetry, potentially leaking sensitive information. https://github.com/wundergraph/graphql-go-tools/blob/master/v2/pkg/variablesvalidation/variablesvalidation.go

The response will also contain sensitive information if the $variable has sensitive information included.

Describe the solution you'd like

It would be amazing to have a config item where I could globally enable/disable said $variable being included in statusMessage on telemetry and/or the Error message on the response.

Even better would be some way to define types containing PII that would then be automatically masked, either via router config or schema annotation, whilst still providing the additional benefit of returning the input $variable context.

Describe alternatives you've considered

It's possible to resolve the tracing leaks with an OTEL collector filter processor, but that unfortunately doesn't resolve the response also potentially including sensitive data.

Additional context

variableContent on the message leaks.

func (v *variablesVisitor) renderVariableInvalidObjectTypeError(typeName []byte, variablesNode astjson.Node) {
	out := &bytes.Buffer{}
	err := v.variables.PrintNode(variablesNode, out)
	if err != nil {
		v.err = err
		return
	}
	variableContent := out.String()
	v.err = &InvalidVariableError{
		Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Expected type "%s" to be an object.`, string(v.currentVariableName), variableContent, string(typeName)),
	}
}

func (v *variablesVisitor) renderVariableRequiredNotProvidedError(fieldName []byte, typeRef int) {
	out := &bytes.Buffer{}
	err := v.variables.PrintNode(v.variables.Nodes[v.currentVariableJsonNodeRef], out)
	if err != nil {
		v.err = err
		return
	}
	variableContent := out.String()
	out.Reset()
	err = v.definition.PrintType(typeRef, out)
	if err != nil {
		v.err = err
		return
	}
	v.err = &InvalidVariableError{
		Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Field "%s" of required type "%s" was not provided.`, string(v.currentVariableName), variableContent, string(fieldName), out.String()),
	}
}

Really appreciate the work y'all are doing!

Sam-tesouro avatar Sep 17 '24 17:09 Sam-tesouro