fix(kap-server): close auth bypass via percent-encoded API paths - #1753
Merged
sailist merged 3 commits intoJul 15, 2026
Conversation
The auth hook checked the raw, still percent-encoded request URL against its bypass policy, while find-my-way matches routes against the decoded path. A raw /%61pi/v1/... URL therefore skipped the bearer-token check yet still reached the /api/... handlers, allowing unauthenticated access to every API route. Decode the request path the same way the router does before matching, and fail closed when the path cannot be decoded. Add tests covering encoded /api/ paths, encoded meta documents, the encoded healthz probe, and unaffected non-API bypasses.
🦋 Changeset detectedLatest commit: 7477fde The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
SessionFsService confined paths only lexically, so a symlink planted inside the workspace could steer read, list, stat, mkdir, resolvePath and resolveDownload to host files outside the session directory. - add IHostFileSystem.realpath (Node fs.realpath semantics) and implement it in the node-local HostFileSystem - resolveWithin now re-verifies each candidate through realpath of the longest existing prefix (so not-yet-created paths still work) and rejects paths escaping the canonicalized workspace roots, which are resolved once and cached - cover symlink escapes for every fs entry point plus kap-server read/download e2e; in-workspace symlink targets remain allowed
WorkspaceRegistryService.createOrTouch probes the root with the
lstat-based IHostFileSystem.stat, so a root given as a symlink to a
directory reported isDirectory=false and session creation was rejected
with fs.path_not_found ("not a directory").
Re-check a non-directory root through IHostFileSystem.realpath before
failing, while keeping the workspace identity lexical (v1 deliberately
never realpaths the root either). Covered by a unit test for a
symlink-form root and a kap-server e2e that creates a session with a
symlinked cwd and reads a file through it.
Merged
7723qqq
pushed a commit
to 7723qqq/kimi-code
that referenced
this pull request
Jul 15, 2026
…nshotAI#1753) * fix(kap-server): fail closed on percent-encoded API paths in auth bypass The auth hook checked the raw, still percent-encoded request URL against its bypass policy, while find-my-way matches routes against the decoded path. A raw /%61pi/v1/... URL therefore skipped the bearer-token check yet still reached the /api/... handlers, allowing unauthenticated access to every API route. Decode the request path the same way the router does before matching, and fail closed when the path cannot be decoded. Add tests covering encoded /api/ paths, encoded meta documents, the encoded healthz probe, and unaffected non-API bypasses. * fix(agent-core-v2): make session fs path confinement symlink-aware SessionFsService confined paths only lexically, so a symlink planted inside the workspace could steer read, list, stat, mkdir, resolvePath and resolveDownload to host files outside the session directory. - add IHostFileSystem.realpath (Node fs.realpath semantics) and implement it in the node-local HostFileSystem - resolveWithin now re-verifies each candidate through realpath of the longest existing prefix (so not-yet-created paths still work) and rejects paths escaping the canonicalized workspace roots, which are resolved once and cached - cover symlink escapes for every fs entry point plus kap-server read/download e2e; in-workspace symlink targets remain allowed * fix(agent-core-v2): accept workspace roots given through a symlink WorkspaceRegistryService.createOrTouch probes the root with the lstat-based IHostFileSystem.stat, so a root given as a symlink to a directory reported isDirectory=false and session creation was rejected with fs.path_not_found ("not a directory"). Re-check a non-directory root through IHostFileSystem.realpath before failing, while keeping the workspace identity lexical (v1 deliberately never realpaths the root either). Covered by a unit test for a symlink-form root and a kap-server e2e that creates a session with a symlinked cwd and reads a file through it.
7723qqq
added a commit
to 7723qqq/kimi-code
that referenced
this pull request
Jul 15, 2026
…oonshotAI#1676 MoonshotAI#1625 MoonshotAI#1746 MoonshotAI#1753 MoonshotAI#1757) Critical fixes cherry-picked from upstream v0.24.x: - fix(agent-core-v2): align rate-limit retries with v1 (MoonshotAI#1598) - fix: preserve empty reasoning across providers (MoonshotAI#1676) - fix: resolve and synchronize thinking effort (MoonshotAI#1625) - fix: align Anthropic-compatible model capabilities (MoonshotAI#1746) - fix(kap-server): close auth bypass via percent-encoded API paths (MoonshotAI#1753) - fix: preserve the crash error in diagnostic logs on unexpected exit (MoonshotAI#1757)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related Issue
No linked issue — the problem is explained below.
Problem
The kap-server auth hook decided whether a request could skip bearer-token authentication by inspecting
req.url— the raw, still percent-encoded URL. The router (find-my-way), however, matches routes against the decoded path. A request to/%61pi/v1/sessions(percent-encoded/api/v1/sessions) therefore failed the hook's/api/prefix check, skipped authentication, yet still matched the/api/v1/sessionsroute — giving unauthenticated clients access to every API route.What changed
packages/kap-server/src/middleware/auth.ts: decode the request path (query string stripped) withdecodeURIComponentbefore applying the bypass policy, so the auth decision sees the same path the router matches against. If the path cannot be decoded, fail closed — the request is never treated as bypassed.packages/kap-server/test/rateLimit.test.ts: regression tests covering percent-encoded/api/paths (401 without a token, 200 with a valid token), a percent-encoded meta document, the percent-encoded healthz probe (still bypassed), and non-API paths (still bypassed).@moonshot-ai/kimi-code.Keeping the decode at the single point where the bypass policy is evaluated aligns the auth decision with routing semantics, instead of special-casing encoded variants in every bypass rule.
Checklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.