fix(02-03): scrub PKCE and OAuth form fields by name

Value-based replace can miss a code_verifier when an authorization code is a substring of it, which 502'd MCP token capture.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jakub Zych
2026-09-17 13:43:27 +02:00
parent 2eb9b4b0c9
commit 7a6c669e3a
2 changed files with 56 additions and 0 deletions

View File

@@ -403,3 +403,42 @@ func TestScrubShortNumericIDsDoNotCorruptPaths(t *testing.T) {
t.Fatalf("substring replace leaked: %s", body)
}
}
func TestScrubFormFieldDespiteSubstringSecrets(t *testing.T) {
store, err := OpenStore("")
if err != nil {
t.Fatal(err)
}
code := "overlapSECRET99"
verifier := "xx" + code + "yyPKCEverifierValue"
store.Set("oauth:code", code)
step := Step{
ID: "20",
Request: Request{
Method: "POST",
Path: "/oauth/mcp/token",
Body: Body("grant_type=authorization_code&code=" + code + "&code_verifier=" + verifier),
},
Response: Response{Status: 200, Body: Body(`{"ok":true}`)},
Capture: []CaptureRule{
{From: "request.form", Name: "code_verifier", As: "pkce:mcp", Category: "pkce"},
{From: "request.form", Name: "code", As: "oauth:code", Category: "oauth_code"},
},
}
if err := CaptureStep(store, &step); err != nil {
t.Fatal(err)
}
if err := ScrubStep(store, &step); err != nil {
t.Fatal(err)
}
got := string(step.Request.Body)
if strings.Contains(got, verifier) || strings.Contains(got, code) {
t.Fatalf("form still live: %s", got)
}
if !strings.Contains(got, "code_verifier={{pkce:mcp}}") {
t.Fatalf("verifier placeholder: %s", got)
}
if !strings.Contains(got, "code={{oauth:code}}") {
t.Fatalf("code placeholder: %s", got)
}
}