|
| 1 | +/* |
| 2 | + * The contents of this file are subject to the terms of the Common Development and |
| 3 | + * Distribution License (the License). You may not use this file except in compliance with the |
| 4 | + * License. |
| 5 | + * |
| 6 | + * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the |
| 7 | + * specific language governing permission and limitations under the License. |
| 8 | + * |
| 9 | + * When distributing Covered Software, include this CDDL Header Notice in each file and include |
| 10 | + * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL |
| 11 | + * Header, with the fields enclosed by brackets [] replaced by your own identifying |
| 12 | + * information: "Portions copyright [year] [name of copyright owner]". |
| 13 | + * |
| 14 | + * Copyright 2026 3A Systems, LLC |
| 15 | + */ |
| 16 | + |
| 17 | +/** |
| 18 | + * Tests against auth/queryFilter.js, the helper used by the authentication augmentation scripts |
| 19 | + * (auth/populateAsManagedUser.js and auth/amSessionCheck.js) to safely embed an untrusted |
| 20 | + * authenticationId into a managed/user query filter (GHSA-64q4-cp2r-m7rg). |
| 21 | + */ |
| 22 | +exports.test = function () { |
| 23 | + var queryFilter = require("auth/queryFilter"); |
| 24 | + |
| 25 | + testEscapeStringValue(); |
| 26 | + testInjectionIsNeutralized(); |
| 27 | + |
| 28 | + function testEscapeStringValue() { |
| 29 | + // [ rawValue, expectedEscapedValue ] |
| 30 | + [ |
| 31 | + // ordinary identifiers are untouched |
| 32 | + ["jsmith", "jsmith"], |
| 33 | + ["", ""], |
| 34 | + ["user@example.com", "user@example.com"], |
| 35 | + // the GHSA-64q4-cp2r-m7rg payload: the closing quote is escaped so it can no longer |
| 36 | + // terminate the literal and start a second predicate |
| 37 | + ['zzz" or /userName eq "victim', 'zzz\\" or /userName eq \\"victim'], |
| 38 | + // a bare double-quote is escaped |
| 39 | + ['a"b', 'a\\"b'], |
| 40 | + // a backslash is escaped (and must be escaped before quotes) |
| 41 | + ["a\\b", "a\\\\b"], |
| 42 | + // a trailing backslash cannot escape the closing delimiter once doubled |
| 43 | + ["foo\\", "foo\\\\"], |
| 44 | + // backslash immediately before a quote: both are escaped independently |
| 45 | + ['a\\"b', 'a\\\\\\"b'] |
| 46 | + ].map(function (testcase) { |
| 47 | + (function (rawValue, expectedEscapedValue) { |
| 48 | + var escaped = queryFilter.escapeStringValue(rawValue) + ""; |
| 49 | + if (escaped !== expectedEscapedValue) { |
| 50 | + throw { |
| 51 | + "message": "escapeStringValue(<" + rawValue + ">) returned <" + escaped |
| 52 | + + ">, expected <" + expectedEscapedValue + ">" |
| 53 | + }; |
| 54 | + } |
| 55 | + }).apply(null, testcase); |
| 56 | + }); |
| 57 | + } |
| 58 | + |
| 59 | + /** |
| 60 | + * Verifies that, once escaped, the value contributes no syntactically significant (unescaped) |
| 61 | + * double-quote to the filter, so the only unescaped quotes are the two delimiters the script |
| 62 | + * adds around the value. This is what prevents the injected |
| 63 | + * <code>" or /userName eq "victim</code> from becoming a second predicate. |
| 64 | + */ |
| 65 | + function testInjectionIsNeutralized() { |
| 66 | + [ |
| 67 | + "jsmith", |
| 68 | + 'zzz" or /userName eq "victim', |
| 69 | + 'a"b"c', |
| 70 | + "trailingBackslash\\", |
| 71 | + 'mixed\\"quote' |
| 72 | + ].map(function (rawValue) { |
| 73 | + var filter = '/userName eq "' + queryFilter.escapeStringValue(rawValue) + '"'; |
| 74 | + // Remove every escaped pair (\\ or \") so that only structural characters remain; |
| 75 | + // any double-quote left is then an actual filter delimiter. |
| 76 | + var structural = filter.replace(/\\[\\"]/g, ""); |
| 77 | + var unescapedQuotes = (structural.match(/"/g) || []).length; |
| 78 | + if (unescapedQuotes !== 2) { |
| 79 | + throw { |
| 80 | + "message": "filter for <" + rawValue + "> has " + unescapedQuotes |
| 81 | + + " unescaped quote(s), expected exactly 2 delimiters; filter was <" + filter + ">" |
| 82 | + }; |
| 83 | + } |
| 84 | + }); |
| 85 | + } |
| 86 | +}; |
0 commit comments