mirror of
https://github.com/grafana/grafana.git
synced 2026-02-03 20:49:50 -05:00
fix: don't split query URL params in validatePath (#111296)
This commit is contained in:
parent
cfbf64c3fd
commit
c37bb1d0a6
2 changed files with 12 additions and 14 deletions
|
|
@ -167,9 +167,9 @@ describe('validatePath', () => {
|
|||
expect(validatePath(urlWithDots)).toBe(urlWithDots);
|
||||
});
|
||||
|
||||
it('should allow query parameters that contain dots', () => {
|
||||
const urlWithDotsInQuery = 'https://api.example.com/search?version=1.2.3&file=../config';
|
||||
expect(validatePath(urlWithDotsInQuery)).toBe(urlWithDotsInQuery);
|
||||
it('should block query parameters that contain path traversal', () => {
|
||||
const urlWithTraversalInQuery = 'https://api.example.com/search?version=1.2.3&file=../config';
|
||||
expect(() => validatePath(urlWithTraversalInQuery)).toThrow(PathValidationError);
|
||||
});
|
||||
|
||||
it('should handle malformed URLs gracefully', () => {
|
||||
|
|
|
|||
|
|
@ -146,27 +146,25 @@ export class PathValidationError extends Error {
|
|||
*/
|
||||
export function validatePath<OriginalPath extends string>(path: OriginalPath): OriginalPath {
|
||||
try {
|
||||
let originalDecoded: string = path; // down-cast to a string to indicate this can't be returned
|
||||
let decoded: string = path;
|
||||
while (true) {
|
||||
const nextDecode = decodeURIComponent(originalDecoded);
|
||||
if (nextDecode === originalDecoded) {
|
||||
const nextDecode = decodeURIComponent(decoded);
|
||||
if (nextDecode === decoded) {
|
||||
break; // String is fully decoded.
|
||||
}
|
||||
originalDecoded = nextDecode;
|
||||
decoded = nextDecode;
|
||||
}
|
||||
|
||||
// Remove query params and fragments to check only the path portion
|
||||
const cleaned = originalDecoded.split(/[\?#]/)[0];
|
||||
originalDecoded = cleaned;
|
||||
|
||||
// If the original string contains traversal attempts, block it
|
||||
if (/\.\.|\/\\|[\t\n\r]/.test(originalDecoded)) {
|
||||
// Validate the entire decoded string for traversal attempts
|
||||
// This prevents attacks that use query separators to hide traversal payloads
|
||||
if (/\.\.|\/\\|[\t\n\r]/.test(decoded)) {
|
||||
throw new PathValidationError();
|
||||
}
|
||||
|
||||
// Return the original path (not the decoded version) to preserve the full URL
|
||||
return path;
|
||||
} catch (err) {
|
||||
// Rethrow the original InvalidPathError to preserve the stack trace
|
||||
// Rethrow the original PathValidationError to preserve the stack trace
|
||||
if (err instanceof PathValidationError) {
|
||||
throw err;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue