diff --git a/package.json b/package.json index e1525f9da..04004ce88 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "homepage": "https://github.com/Enterprise-CMCS/macpro-mdct-mcr#readme", "dependencies": { "@enterprise-cmcs/serverless-waf-plugin": "^1.4.0", - "fast-xml-parser": "4.5.0", + "fast-xml-parser": "4.5.1", "loader-utils": "2.0.4" }, "devDependencies": { diff --git a/services/app-api/utils/sanitize/sanitize.test.ts b/services/app-api/utils/sanitize/sanitize.test.ts index 9130540e1..2a3cc9999 100644 --- a/services/app-api/utils/sanitize/sanitize.test.ts +++ b/services/app-api/utils/sanitize/sanitize.test.ts @@ -12,35 +12,13 @@ const safeUndefined = undefined; const cleanString = "test"; -const dirtyImgString = ''; -const cleanImgString = ''; - -const dirtyLinkString = ""; +const dirtyLinkString = ""; const cleanLinkString = ''; -const dirtyScriptString = - ""; -const cleanScriptString = ""; - -const dirtySvgString = ""; -const cleanSvgString = ""; - // ARRAYS -const dirtyStringArray = [ - cleanString, - dirtyImgString, - dirtyLinkString, - dirtySvgString, - dirtyScriptString, -]; -const cleanStringArray = [ - cleanString, - cleanImgString, - cleanLinkString, - cleanSvgString, - cleanScriptString, -]; +const dirtyStringArray = [cleanString, dirtyLinkString]; +const cleanStringArray = [cleanString, cleanLinkString]; const dirtyNestedStringArray = [dirtyStringArray, dirtyStringArray]; const cleanNestedStringArray = [cleanStringArray, cleanStringArray]; @@ -48,11 +26,11 @@ const cleanNestedStringArray = [cleanStringArray, cleanStringArray]; // OBJECTS const dirtyObject = { - string: dirtyImgString, + string: dirtyLinkString, array: dirtyStringArray, }; const cleanObject = { - string: cleanImgString, + string: cleanLinkString, array: cleanStringArray, }; @@ -61,10 +39,7 @@ const cleanObjectArray = [cleanObject, cleanObject]; const dirtyComplexObject = { string1: cleanString, - string2: dirtyImgString, - string3: dirtyLinkString, - string4: dirtySvgString, - string5: dirtyScriptString, + string2: dirtyLinkString, array: dirtyStringArray, nestedStringArray: dirtyNestedStringArray, nestedObjectArray: dirtyObjectArray, @@ -74,10 +49,7 @@ const dirtyComplexObject = { }; const cleanComplexObject = { string1: cleanString, - string2: cleanImgString, - string3: cleanLinkString, - string4: cleanSvgString, - string5: cleanScriptString, + string2: cleanLinkString, array: cleanStringArray, nestedStringArray: cleanNestedStringArray, nestedObjectArray: cleanObjectArray, @@ -93,10 +65,7 @@ describe("Test sanitizeString", () => { }); test("Test sanitizeString cleans dirty strings", () => { - expect(sanitizeString(dirtyImgString)).toEqual(cleanImgString); expect(sanitizeString(dirtyLinkString)).toEqual(cleanLinkString); - expect(sanitizeString(dirtySvgString)).toEqual(cleanSvgString); - expect(sanitizeString(dirtyScriptString)).toEqual(cleanScriptString); }); }); diff --git a/services/app-api/utils/sanitize/sanitize.ts b/services/app-api/utils/sanitize/sanitize.ts index f6cdb7a50..c75cd290a 100644 --- a/services/app-api/utils/sanitize/sanitize.ts +++ b/services/app-api/utils/sanitize/sanitize.ts @@ -4,6 +4,22 @@ import { JSDOM } from "jsdom"; const windowEmulator: any = new JSDOM("").window; const DOMPurify = createDOMPurify(windowEmulator); +/* + * DOMPurify prevents all XSS attacks by default. With these settings, it also + * prevents "deception" attacks. If an attacker could put
+ * into the site's admin banner, they could make give the banner any appearance, + * overlaid anywhere on the page. For example, a fake "session expired" modal + * with a malicious link. Thus, this very strict DOMPurify config. + */ +DOMPurify.setConfig({ + // Only these tags will be allowed through + ALLOWED_TAGS: ["ul", "ol", "li", "a", "#text"], + // On those tags, only these attributes are allowed + ALLOWED_ATTR: ["href", "alt"], + // If a tag is removed, so will all its child elements & text + KEEP_CONTENT: false, +}); + // sanitize string export const sanitizeString = (string: string) => { if (DOMPurify.isSupported) { diff --git a/services/ui-src/package.json b/services/ui-src/package.json index bb15bf9d9..56eb6fe93 100644 --- a/services/ui-src/package.json +++ b/services/ui-src/package.json @@ -19,12 +19,12 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", "@hookform/resolvers": "^2.9.11", - "@vitejs/plugin-react": "^4.3.2", + "@vitejs/plugin-react": "^4.3.4", "aws-amplify": "^6.10.0", "date-fns": "^2.30.0", "date-fns-tz": "^1.3.8", "dompurify": "^2.5.7", - "fast-xml-parser": "4.5.0", + "fast-xml-parser": "4.5.1", "framer-motion": "^4", "history": "^5.3.0", "html-react-parser": "^3.0.16", @@ -43,7 +43,7 @@ "react-uuid": "^1.0.3", "sass": "^1.83.0", "vite": "^6.0.0", - "vite-tsconfig-paths": "^5.1.2", + "vite-tsconfig-paths": "^5.1.4", "yup": "^0.32.11", "zustand": "^4.5.5" }, diff --git a/services/ui-src/src/components/alerts/Alert.tsx b/services/ui-src/src/components/alerts/Alert.tsx index 5cdc3084c..b65fe4462 100644 --- a/services/ui-src/src/components/alerts/Alert.tsx +++ b/services/ui-src/src/components/alerts/Alert.tsx @@ -45,7 +45,7 @@ export const Alert = ({ : alertIcon } sx={sx.icon} - alt={status} + alt={status || "alert"} /> )} diff --git a/services/ui-src/yarn.lock b/services/ui-src/yarn.lock index 4c03ed52f..263dcd803 100644 --- a/services/ui-src/yarn.lock +++ b/services/ui-src/yarn.lock @@ -796,7 +796,7 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/core@^7.25.2": +"@babel/core@^7.26.0": version "7.26.0" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40" integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg== @@ -1873,14 +1873,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-react-jsx-self@^7.24.7": +"@babel/plugin-transform-react-jsx-self@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz#c0b6cae9c1b73967f7f9eb2fca9536ba2fad2858" integrity sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg== dependencies: "@babel/helper-plugin-utils" "^7.25.9" -"@babel/plugin-transform-react-jsx-source@^7.24.7": +"@babel/plugin-transform-react-jsx-source@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz#4c6b8daa520b5f155b5fb55547d7c9fa91417503" integrity sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg== @@ -4485,14 +4485,14 @@ dependencies: "@types/node" "*" -"@vitejs/plugin-react@^4.3.2": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.3.tgz#28301ac6d7aaf20b73a418ee5c65b05519b4836c" - integrity sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA== +"@vitejs/plugin-react@^4.3.4": + version "4.3.4" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz#c64be10b54c4640135a5b28a2432330e88ad7c20" + integrity sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug== dependencies: - "@babel/core" "^7.25.2" - "@babel/plugin-transform-react-jsx-self" "^7.24.7" - "@babel/plugin-transform-react-jsx-source" "^7.24.7" + "@babel/core" "^7.26.0" + "@babel/plugin-transform-react-jsx-self" "^7.25.9" + "@babel/plugin-transform-react-jsx-source" "^7.25.9" "@types/babel__core" "^7.20.5" react-refresh "^0.14.2" @@ -5803,7 +5803,14 @@ fast-xml-parser@4.4.1: dependencies: strnum "^1.0.5" -fast-xml-parser@4.5.0, fast-xml-parser@^4.4.1: +fast-xml-parser@4.5.1: + version "4.5.1" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.5.1.tgz#a7e665ff79b7919100a5202f23984b6150f9b31e" + integrity sha512-y655CeyUQ+jj7KBbYMc4FG01V8ZQqjN+gDYGJ50RtfsUB8iG9AmwmwoAgeKLJdmueKKMrH1RJ7yXHTSoczdv5w== + dependencies: + strnum "^1.0.5" + +fast-xml-parser@^4.4.1: version "4.5.0" resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz#2882b7d01a6825dfdf909638f2de0256351def37" integrity sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg== @@ -9148,10 +9155,10 @@ v8-to-istanbul@^9.0.1: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^2.0.0" -vite-tsconfig-paths@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.2.tgz#975810f12cdaebcda196ce3c2cb4ba19df277bb1" - integrity sha512-gEIbKfJzSEv0yR3XS2QEocKetONoWkbROj6hGx0FHM18qKUojhvcokQsxQx5nMkelZq2n37zbSGCJn+FSODSjA== +vite-tsconfig-paths@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz#d9a71106a7ff2c1c840c6f1708042f76a9212ed4" + integrity sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w== dependencies: debug "^4.1.1" globrex "^0.1.2" diff --git a/yarn.lock b/yarn.lock index dcfabc7b0..a978e1035 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8985,10 +8985,10 @@ fast-xml-parser@4.4.1: dependencies: strnum "^1.0.5" -fast-xml-parser@4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz#2882b7d01a6825dfdf909638f2de0256351def37" - integrity sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg== +fast-xml-parser@4.5.1: + version "4.5.1" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.5.1.tgz#a7e665ff79b7919100a5202f23984b6150f9b31e" + integrity sha512-y655CeyUQ+jj7KBbYMc4FG01V8ZQqjN+gDYGJ50RtfsUB8iG9AmwmwoAgeKLJdmueKKMrH1RJ7yXHTSoczdv5w== dependencies: strnum "^1.0.5"