Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,14 @@ Error messages should never include raw values from sensitive sources like envir
**Prevention:**
1. Avoid including raw values in error messages when the source is potentially sensitive (env vars, auth headers).
2. Use generic error messages for validation failures of sensitive data.
## 2026-05-17 - [HIGH] Path Traversal By Missing Dot Encoding

**Vulnerability:**
The `CompositeExecutor` and `MCPServer` were using `encodeURIComponent` to encode path segments, but `encodeURIComponent` does not encode dot (`.`) characters. This left the system vulnerable to path traversal attacks if an attacker injected `..` into a path segment.

**Learning:**
`encodeURIComponent` is insufficient for preventing path traversal in path segments if the underlying HTTP client or server parses the injected dots before forwarding or resolving the path. In URL specifications, unencoded dots can still traverse directory structures.

**Prevention:**
1. Always replace `.` with `%2E` after calling `encodeURIComponent` when substituting user input into path segments.
2. Ensure test cases explicitly check for the encoded dot characters (`%2E%2E`) rather than just checking that the payload passed through.
2 changes: 1 addition & 1 deletion src/mcp/mcp-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1205,7 +1205,7 @@ export class MCPServer {
*/
private encodePathSegment(value: unknown): string {
const val = String(value);
return val.includes('/') ? encodeURIComponent(val) : val;
return val.includes('/') ? encodeURIComponent(val).replace(/\./g, '%2E') : val.replace(/\./g, '%2E');
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/tooling/composite-executor-security.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ describe('CompositeExecutor Security', () => {
// Fixed behavior: path contains encoded "%2E%2E"
// Note: encodeURIComponent('../admin/secrets') => ..%2Fadmin%2Fsecrets
// The slashes inside the injected value are encoded, preventing directory traversal
const expectedFixedPath = '/users/..%2Fadmin%2Fsecrets/profile';
const expectedFixedPath = '/users/%2E%2E%2Fadmin%2Fsecrets/profile';

expect(capturedPaths[0]).toBe(expectedFixedPath);
});
Expand Down
4 changes: 2 additions & 2 deletions src/tooling/composite-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,14 +171,14 @@ export class CompositeExecutor {
return template.replace(/\{(\w+)\}/g, (_, key) => {
// Try direct match first
if (args[key] !== undefined) {
return encodeURIComponent(String(args[key]));
return encodeURIComponent(String(args[key])).replace(/\./g, '%2E');
}

// Try aliases from profile
const possibleAliases = this.parameterAliases[key] || [];
for (const alias of possibleAliases) {
if (args[alias] !== undefined) {
return encodeURIComponent(String(args[alias]));
return encodeURIComponent(String(args[alias])).replace(/\./g, '%2E');
}
}

Expand Down
Loading