Repository navigation
Commit b05d78e
fix(httpapi): percent-decode the {tool} path param before the approval lookup (#1750)
# Pull Request
## Description
chi routes on `RawPath`, so path params arrive percent-encoded whenever
the client's encoding differs from Go's default. MCP-1118 fixed this for
`{id}` with `decodeServerIDParam` on the `/servers/{id}` subtree, but
the nested `{tool}` param is still read raw by its two handlers:
- `GET /api/v1/servers/{id}/tools/{tool}/diff` (`handleGetToolDiff`)
- `POST /api/v1/servers/{id}/tools/{tool}/enabled`
(`handleSetToolEnabled`)
**Trigger.** The Web UI builds both URLs with
`encodeURIComponent(toolName)` (`frontend/src/services/api.ts:577`,
`:618`), which encodes `:` as `%3A` and `/` as `%2F`. Go's default path
encoding leaves `:` alone, so for a tool named `ns:erase` the request
has a non-empty `RawPath`, chi hands the handler `ns%3Aerase`, and the
exact-match approval lookup misses. The Review diff for that tool never
loads and the per-tool enable/disable toggle fails. Tool names carrying
`:` or `/` are upstream-defined and already accounted for elsewhere (see
`canonicalIdentity` in `internal/profile/glob.go`).
`decodeServerIDParam` cannot cover `{tool}`: it runs as subtree
middleware, before the nested route has been matched and the param
populated. So the fix is the same `decodePathParam` call in the two
handlers, as `handleAddFromRegistry` already does for `{serverId}`.
## Testing
- [x] I have tested these changes locally
- [x] I have added/updated tests that prove my fix is effective or my
feature works
- [x] All existing tests pass
`TestToolSubresource_EncodedToolNameUnescaped`
(`internal/httpapi/tool_path_param_decode_test.go`) drives both routes
through `Server.ServeHTTP` with `ns%3Aerase` and `ns%2Ferase` and
asserts the decoded name reaches the lookup.
```
CGO_ENABLED=0 go test ./internal/httpapi -count=1 # ok
# with server.go reverted:
CGO_ENABLED=0 go test ./internal/httpapi -run TestToolSubresource -count=1 # FAIL, all 4 subtests
gofmt -l <changed files> # clean
```
(`CGO_ENABLED=0` only because my local macOS SDK cannot link cgo test
binaries; nothing here uses cgo.)
## Note on the CodeQL alert
CodeQL reports `go/reflected-xss` at `internal/httpapi/middleware.go:85`
(`statusRecorder.Write`) because the decoded tool name now reaches the
response. The only sinks are `writeSuccess` / `writeError`, both of
which go through `writeJSON`: `Content-Type: application/json` plus
`json.Encoder` with its default HTML escaping (`<`, `>`, `&` become
`\u003c` and so on). The raw `chi.URLParam` value already reached the
same sinks before this change. The decode only turns `%3A` into `:` so
the controller lookup matches.
Co-authored-by: Cursor <cursoragent@cursor.com>1 parent 98e568b commit b05d78e
2 files changed
Lines changed: 69 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7275 | 7275 | | |
7276 | 7276 | | |
7277 | 7277 | | |
7278 | | - | |
| 7278 | + | |
7279 | 7279 | | |
7280 | 7280 | | |
7281 | 7281 | | |
| |||
7402 | 7402 | | |
7403 | 7403 | | |
7404 | 7404 | | |
7405 | | - | |
| 7405 | + | |
7406 | 7406 | | |
7407 | 7407 | | |
7408 | 7408 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
0 commit comments