mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-27103] Add URL Check to Send (#17056)
* add dangerousPatters check to api service
This commit is contained in:
@@ -689,6 +689,32 @@ describe("Utils Service", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("invalidUrlPatterns", () => {
|
||||
it("should return false if no invalid patterns are found", () => {
|
||||
const urlString = "https://www.example.com/api/my/account/status";
|
||||
|
||||
const actual = Utils.invalidUrlPatterns(urlString);
|
||||
|
||||
expect(actual).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true if an invalid pattern is found", () => {
|
||||
const urlString = "https://www.example.com/api/%2e%2e/secret";
|
||||
|
||||
const actual = Utils.invalidUrlPatterns(urlString);
|
||||
|
||||
expect(actual).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true if an invalid pattern is found in a param", () => {
|
||||
const urlString = "https://www.example.com/api/history?someToken=../secret";
|
||||
|
||||
const actual = Utils.invalidUrlPatterns(urlString);
|
||||
|
||||
expect(actual).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getUrl", () => {
|
||||
it("assumes a http protocol if no protocol is specified", () => {
|
||||
const urlString = "www.exampleapp.com.au:4000";
|
||||
|
||||
@@ -612,6 +612,55 @@ export class Utils {
|
||||
return path.normalize(decodeURIComponent(denormalizedPath)).replace(/^(\.\.(\/|\\|$))+/, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an url checking against invalid patterns
|
||||
* @param url
|
||||
* @returns true if invalid patterns found, false if safe
|
||||
*/
|
||||
static invalidUrlPatterns(url: string): boolean {
|
||||
const invalidUrlPatterns = ["..", "%2e", "\\", "%5c"];
|
||||
|
||||
const decodedUrl = decodeURIComponent(url.toLocaleLowerCase());
|
||||
|
||||
// Check URL for invalidUrl patterns across entire URL
|
||||
if (invalidUrlPatterns.some((p) => decodedUrl.includes(p))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for additional invalid patterns inside URL params
|
||||
if (decodedUrl.includes("?")) {
|
||||
const hasInvalidParams = this.validateQueryParameters(decodedUrl);
|
||||
if (hasInvalidParams) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates query parameters for additional invalid patterns
|
||||
* @param url - The URL containing query parameters
|
||||
* @returns true if invalid patterns found, false if safe
|
||||
*/
|
||||
private static validateQueryParameters(url: string): boolean {
|
||||
try {
|
||||
let queryString: string;
|
||||
|
||||
if (url.includes("?")) {
|
||||
queryString = url.split("?")[1];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
const paramInvalidPatterns = ["/", "%2f", "#", "%23"];
|
||||
|
||||
return paramInvalidPatterns.some((p) => queryString.includes(p));
|
||||
} catch (error) {
|
||||
throw new Error(`Error validating query parameters: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
private static isMobile(win: Window) {
|
||||
let mobile = false;
|
||||
((a) => {
|
||||
|
||||
@@ -1588,8 +1588,16 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
);
|
||||
apiUrl = Utils.isNullOrWhitespace(apiUrl) ? env.getApiUrl() : apiUrl;
|
||||
|
||||
// Prevent directory traversal from malicious paths
|
||||
const pathParts = path.split("?");
|
||||
// Check for path traversal patterns from any URL.
|
||||
const fullUrlPath = apiUrl + pathParts[0] + (pathParts.length > 1 ? `?${pathParts[1]}` : "");
|
||||
|
||||
const isInvalidUrl = Utils.invalidUrlPatterns(fullUrlPath);
|
||||
if (isInvalidUrl) {
|
||||
throw new Error("The request URL contains dangerous patterns.");
|
||||
}
|
||||
|
||||
// Prevent directory traversal from malicious paths
|
||||
const requestUrl =
|
||||
apiUrl + Utils.normalizePath(pathParts[0]) + (pathParts.length > 1 ? `?${pathParts[1]}` : "");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user