https://gnocchi-internal.googlesource.com/third_party/jquery, branch main). Mirrored on the legacy host https://appsheet-third-party.googlesource.com/jquery, which is the URL the AppSheet frontend actually resolves at install time.external/sizzle/dist/sizzle.js). Declared in METADATA as version: "3.6.2", last_upgrade_date: 2023-03-01.innerHTML writes performed during browser feature detection:src/core/support.js — under Trusted Types, short-circuits the Safari 8 support.createHTMLDocument probe instead of writing body.innerHTML = "<form></form><form></form>".src/manipulation/support.js — under Trusted Types, hardcodes support.noCloneChecked = true and support.option = true instead of probing via div.innerHTML = "<textarea>x</textarea>" / "<option></option>".external/sizzle/dist/sizzle.js — three sites: two assert() probes rebuilt with document.createElement / setAttribute / appendChild instead of innerHTML, and the legacy IE<8 / IE<9 addHandle( "type|href|height|width" ) and addHandle( "value" ) attribute-interpolation probes skipped entirely when window.trustedTypes.createPolicy exists.src/core.js — version reverted to the "@VERSION" build placeholder.dist/jquery.js, dist/jquery.min.js, and dist/jquery.min.map (banner v3.6.2-pre, Date: 2023-03-15T20:55Z), plus Google METADATA and LICENSE files.jQuery.fn.html, buildFragment, jQuery.parseHTML, jQuery.htmlPrefilter, jQuery.globalEval, DOMEval, and the Sizzle selector parser are byte-identical to upstream 3.6.2.src/), the vendored selector engine (external/sizzle/), and the committed prebuilt bundles (dist/) that are the artifacts actually consumed by AppSheet.jeenee/Nirvana/Content/package.json: "jquery": "git+https://appsheet-third-party.googlesource.com/jquery#1d60e5afef1b0287e855686a4d524d8cf3aa61ee" (with @types/jquery 3.5.14).Nirvana/Content/scripts/_shared/external/jqueryInit.js (import $ from 'jquery'; window.$ = window.jQuery = $;) publishes jQuery as a global; roughly 75 first-party .ts/.tsx files then consume $ / jQuery without importing it, concentrated in scripts/legacy/** (Form, List, Gallery, Deck, Calendar, Dashboard, GoogleMap, Graph, Search, FastTable, SlideShow controllers), scripts/_shared/lib/**, and scripts/_shared/models/LegacyViewManager.tsx.webpack.config.js resolves the package main (dist/jquery.js, unminified) into every SPA entry point (app-main, editor-main, site-main, my-apps-main, templates-main, app-gallery-main) and Terser-minifies it into the shipped build/[name].js; jQuery is explicitly excluded from babel-loader.<script nonce="@CspNonce" src="/Scripts/jquery-3.6.2.min.js"> (V3/MainServer/Views/Shared/_LegacyContentLayout.cshtml and friends).$ object: _shared/external/jqueryFileTree, jquery.exif, jquery.canvasresize.https://github.com/jquery/jquery, MIT).dist/jquery.js is compiled and minified into the proprietary AppSheet web bundles that are served to customer browsers, and a minified copy is served directly as /Scripts/jquery-3.6.2.min.js. It therefore executes as shipped, minified first-party JavaScript inside every AppSheet end-user and app-editor session, in the same origin and with the same privileges as AppSheet’s own code. A defect here is a defect in shipped AppSheet client software, not merely in a build-time dependency.buildFragment → tmp.innerHTML, jQuery.htmlPrefilter, jQuery.parseHTML, jQuery.fn.init HTML-string coercion), dynamic script execution (jQuery.globalEval → DOMEval script-element injection, the text script AJAX converter, JSONP callback injection in src/ajax/jsonp.js), a hand-written regex-based CSS selector parser (Sizzle), attribute/property writers, and a deep-merge utility (jQuery.extend). The fork additionally disables several feature-detection code paths, which changes runtime behavior.localStorage/localforage caches of record data, and the ability to issue authenticated first-party API calls on the victim's behalf.JeeneeBrowserAPI.ts, JSONHelp.ts) whose payloads are derived from (a) and (b); and (d) URL/hash and postMessage-adjacent values in the legacy controllers. None of these are trustworthy: an AppSheet app author is a different, lower-privileged principal than the end users of the app they publish.require-trusted-types-for 'script' (see go/appsheet-tt-oss). A regression in these patches either breaks the Trusted Types rollout (losing AppSheet’s primary DOM-XSS backstop) or breaks app rendering for all customers. A DOM-XSS in this library is a cross-customer, cross-tenant account-takeover primitive.Direct the agentic scanner as follows. Note that the only Google-authored code in this repository is the Trusted Types patch set; findings in that delta are strictly higher priority than findings in pristine upstream code.
src/core/support.js, src/manipulation/support.js, and external/sizzle/dist/sizzle.js. Verify that (a) the window.trustedTypes && window.trustedTypes.createPolicy guard is a sound proxy for the conditions the original probes tested, (b) hardcoding support.noCloneChecked = true and support.option = true does not cause jQuery.fn.clone / wrapMap to skip a correctness or safety step, and (c) skipping the Sizzle addHandle( "type|href|height|width" ) and addHandle( "value" ) registrations does not change how attribute selectors resolve href/src/type/value on any supported browser.support.createHTMLDocument type deviation. In the TT branch of src/core/support.js the IIFE is not invoked — support.createHTMLDocument is assigned a function object, where upstream assigns a boolean. Its sole consumer, jQuery.parseHTML in src/core/parseHTML.js, uses a truthy check, so the safe inert-document.implementation.createHTMLDocument branch is still taken; but confirm no other code (including jQuery plugins such as jqueryFileTree, jquery.exif, jquery.canvasresize, or jquery-migrate) performs a strict === true comparison that would silently fall through to parsing untrusted HTML in the live document, which would execute inline event handlers and load subresources immediately.src/manipulation/buildFragment.js (tmp.innerHTML = wrap[1] + jQuery.htmlPrefilter( elem ) + wrap[2]), jQuery.fn.html (src/manipulation.js, including the rnoInnerhtml shortcut and the try { elem.innerHTML = value } fallback), jQuery.htmlPrefilter, jQuery.parseHTML, and the HTML-string branch of jQuery.fn.init (src/core/init.js, rquickExpr). Confirm the trac-9521 / trac-11290 mitigations (leading-< requirement, #id prioritization) are intact and that no wrapper-map path can be used to smuggle <script>, <style>, <svg>, <math>, or mXSS-style mutation payloads. Explicitly re-verify the CVE-2020-11022 / CVE-2020-11023 htmlPrefilter remediations are present.jQuery.globalEval (src/core.js), DOMEval (src/core/DOMEval.js — creates a <script> element, copies type/src/nonce/noModule, appends to doc.head), src/manipulation/_evalUrl.js, the "text script" converter in src/ajax/script.js, and JSONP callback-name handling in src/ajax/jsonp.js (rjsonp, jsonpCallback, the window[ callbackName ] assignment). Pay particular attention to whether DOMEval‘s nonce propagation can be abused to launder attacker-controlled script past AppSheet’s script-src 'nonce-…' 'strict-dynamic' CSP.external/sizzle/dist/sizzle.js tokenizer regexes (rcomma, rcombinators, rattributeQuotes, matchExpr, rpseudo, runescape) and the :has(), :not(), :contains(), and attribute-selector handlers, for catastrophic backtracking and for cases where a selector string containing < is reinterpreted as HTML by jQuery.fn.init.jQuery.extend prototype pollution. src/core.js contains the CVE-2019-11358 fix (if ( name === "__proto__" || target === copy ) continue;). Verify it is present and complete in both src/ and the committed dist/jquery.js, and that jQuery.isPlainObject / jQuery.parseJSON-adjacent paths cannot reach constructor.prototype.dist/ provenance. The committed dist/jquery.js / jquery.min.js / jquery.min.map were built locally (banner 3.6.2-pre) and are the artifacts AppSheet actually ships. Diff them against src/ + external/sizzle/ to confirm they contain exactly the TT patch set and no unreviewed additional code.All entry points are client-side JavaScript API calls made by AppSheet frontend code; the library has no network listeners of its own. “Trusted?” describes the data that AppSheet actually passes.
| Entry Point | Type | Trusted? | Validation |
|---|---|---|---|
jQuery() / $( selector ) (src/core/init.js, jQuery.fn.init) | Selector string or HTML string → DOM | No | rquickExpr requires a leading < (and trailing >, length ≥ 3) to treat input as HTML; prioritizes #id over <tag> to blunt location.hash XSS (trac-9521). Anything else is handed to Sizzle as a selector. |
jQuery.fn.html( value ) (src/manipulation.js) | HTML string → innerHTML | No | rnoInnerhtml = /<script|<style|<link/i gates the direct-innerHTML fast path; jQuery.htmlPrefilter normalizes self-closing tags. No sanitization. |
jQuery.fn.append / prepend / after / before / replaceWith / wrap (domManip → buildFragment) | HTML string or node → DOM | No | rhtml = /<|&#?\w+;/ decides string-vs-text; HTML strings go to buildFragment and are parsed via innerHTML. No sanitization. |
jQuery.parseHTML( data, context, keepScripts ) (src/core/parseHTML.js) | HTML string → detached nodes | No | Parses into an inert document.implementation.createHTMLDocument( "" ) when support.createHTMLDocument is truthy (so scripts/inline handlers do not auto-run); strips <script> unless keepScripts. Note jQuery.fn.init calls it with keepScripts = true. |
jQuery.globalEval( code, options, doc ) (src/core.js → src/core/DOMEval.js) | Arbitrary JS string | No | None. Injects a <script> into doc.head, propagating type/src/nonce/noModule. Direct code-execution primitive. |
jQuery.ajax / $.get / $.post / $.getJSON (src/ajax.js, src/ajax/xhr.js) | URL, headers, body, response | No | URL is not validated or scheme-checked; crossDomain is inferred by comparing against src/ajax/var/location.js. Response is run through converters selected by dataType/Content-Type. |
dataType: "script" responses (src/ajax/script.js) | Remote response body | No | Auto-execution suppressed for cross-domain responses without an explicit dataType; otherwise the "text script" converter calls jQuery.globalEval. |
JSONP requests (src/ajax/jsonp.js) | Remote response body + callback name | No | Response is executed as script by design; jsonpCallback name is written to window. |
jQuery.fn.load( url, params, callback ) (src/ajax/load.js) | Remote HTML fragment | No | Response is passed to jQuery.parseHTML and injected via .append(...).find( selector ). |
jQuery.fn.attr / prop / css / addClass (src/attributes/*.js, src/css.js) | Attribute / style values | No | No URL-scheme validation — a dynamic href/src value of javascript: or data: is written verbatim. |
jQuery.extend( true, target, src ) (src/core.js) | Object graph (often parsed JSON) | No | Skips __proto__ and self-referential copies (CVE-2019-11358 fix). |
Sizzle selector strings (external/sizzle/dist/sizzle.js) | CSS selector | No | Regex tokenizer with an internal compile cache; unrecognized pseudo-selectors raise a syntax error. |
window.trustedTypes (src/core/support.js, src/manipulation/support.js, sizzle.js) | Browser global / feature flag | Yes (browser-provided) | Presence check only (window.trustedTypes && window.trustedTypes.createPolicy). Determines which of the two behavior branches this fork executes. |
jQuery.ajax calls (xhrFields/withCredentials semantics are decided by the caller).jeenee MainServer / ControllerHandler); jQuery will faithfully issue whatever request the calling code constructs..text() over .html(), and for routing genuinely-HTML content through dompurify / sanitize-html / safevalues.require-trusted-types-for 'script' (Security/SecurityHeadersFramework/SecurityHeaderConstants.cs; Security/SecurityHeaders/SecurityHeaders.cs defaults to TrustedTypesMode.PartialEnforce, flag-gated by ITrustedTypesEnforcementModeFeatureGate, with a report-only variant for rollout). The client-side 'default' policy in Nirvana/Content/src/app/globals/trusted_types.ts is deny-by-default: its createHTML returns a value only for '', '&', and '​' and returns null for everything else, so an unreviewed raw-HTML sink throws rather than executing. Critically, the fork‘s patches only remove innerHTML writes from feature detection; **jQuery’s runtime HTML sinks still assign to innerHTML** and therefore still depend on that default policy for safety. Two important corollaries for scanners: (i) the protection is only as strong as the enforcement flag's rollout state — any user or surface where the gate is off, or where CSP is report-only, has no backstop; and (ii) the default policy is a global, so any code path that broadens it (e.g. the named unsafeCreateHtmlPolicy, 'filepicker-fix', or 'jquery-modal-fix' policies elsewhere in jeenee) re-opens the sinks.JeeneeBrowserAPI.ts, JSONHelp.ts) → jQuery AJAX converters → DOM. A third: third-party origins reachable via dataType: "script" / JSONP → same-origin script execution.| Data Type | Source | Destination | Protection |
|---|---|---|---|
| Customer record data & PII (rows, free-text and Long-Text columns, file names) | AppSheet backend API (JeeneeBrowserAPI.ts, JSONHelp.ts → $.ajax / $.getJSONUnsigned / $.postJSON) | Legacy view controllers → DOM via jQuery | HTTPS transport; server-side authz; rendered predominantly through .text() and React, with Trusted Types as the backstop for any raw-HTML path |
| App-definition metadata (view/column/action labels, format rules) | Customer app author → AppSheet backend | LegacyViewManager.tsx and legacy controllers → DOM | Same-origin rendering; author is a distinct, lower-trust principal from the end user — this is the primary stored-XSS vector into jQuery sinks |
| Session cookies & auth context | Browser cookie jar | Same-origin jQuery.ajax requests (src/ajax/xhr.js) | Ambient same-origin credentials; not read or persisted by jQuery itself |
| CSP nonce | @CspNonce on <script> tags | Copied onto generated <script> elements by DOMEval (preservedScriptAttributes.nonce) | Nonce is propagated verbatim from the reference node — a script-execution laundering surface worth explicit review under 'strict-dynamic' |
Cloud-storage file listings (path, name) | AppSheet server file-listing API via the getTree callback | scripts/_shared/external/jqueryFileTree.js → $( '<li…><a href="#" rel="' + data[i].path + '">' + data[i].name + '</a></li>' ) → .append() | Raw HTML string concatenation, no escaping. Mitigated today only because the sole consumer (components/app/FileTree.tsx) is unreferenced, plus Trusted Types |
Action button markup (buttonHtml) | Would be app-definition-derived | LegacyViewManager.tsx ShowOverlayActionButtons() → .html( actions[i].buttonHtml ) | Unescaped .html() sink. Currently dead code (no callers, property never assigned) but present in the shipped bundle |
| Static third-party map plugin source | Bundled constant MarkerWithLabelRaw | scripts/_shared/lib/GoogleMaps.ts → $.globalEval | Wrapped in safevalues scriptSafeByReview; source is a compile-time constant, not attacker-influenced |
| Action | Location | Guard |
|---|---|---|
| HTML string parsing into DOM nodes | manipulation/buildFragment.js:buildFragment (tmp.innerHTML = wrap[1] + jQuery.htmlPrefilter( elem ) + wrap[2]) | None in-library; relies on the Trusted Types 'default' policy and on callers passing safe values |
Direct innerHTML assignment | manipulation.js:jQuery.fn.html | rnoInnerhtml (/<script|<style|<link/i) gate + try/catch fallback to empty() + append(); no sanitization |
| Inert-document HTML parsing | core/parseHTML.js:jQuery.parseHTML | Uses document.implementation.createHTMLDocument( "" ) when support.createHTMLDocument is truthy; strips <script> unless keepScripts is set |
| Arbitrary script execution | core/DOMEval.js:DOMEval, reached via core.js:jQuery.globalEval, manipulation/_evalUrl.js, ajax/script.js "text script" converter | None. Propagates nonce from the reference node so injected scripts satisfy a nonce-based CSP |
| Deferred/injected script re-execution on DOM insertion | manipulation.js:domManip, manipulation/setGlobalEval.js, manipulation/getAll.js (rscriptType check) | Only executes nodes whose type matches rscriptType; tracks already-evaluated nodes via dataPriv |
| Cross-origin network requests | ajax.js:jQuery.ajax, ajax/xhr.js, ajax/script.js script-tag transport, ajax/jsonp.js | Browser SOP/CORS only; no in-library URL allowlist or scheme validation |
| Global namespace mutation | ajax/jsonp.js (window[ callbackName ]), jqueryInit.js (window.$ = window.jQuery = $) | None |
| Attribute / property / style writes | attributes/attr.js, attributes/prop.js, css.js:jQuery.fn.css | Boolean-attribute and nodeHook normalization only; no URL-scheme validation on href / src / action |
| Deep object merge | core.js:jQuery.extend | Skips __proto__ and self-referential copies (CVE-2019-11358 remediation) |
| Feature-detection branch selection (fork-specific) | core/support.js, manipulation/support.js, external/sizzle/dist/sizzle.js | window.trustedTypes && window.trustedTypes.createPolicy presence check only |
src/core/support.js, src/manipulation/support.js, external/sizzle/dist/sizzle.js) — this is the only Google-authored code in the repository, it is unreviewed by upstream, and it changes support.* flags that gate cloning, wrapMap wrapping, and attribute resolution throughout the library.support.createHTMLDocument function-vs-boolean deviation — the TT branch assigns an uninvoked IIFE where upstream assigns a boolean; it is truthy so jQuery.parseHTML still takes the safe inert-document path today, but any strict === true comparison in a plugin or a future upstream merge would silently downgrade parsing into the live document, executing inline handlers and firing subresource loads.buildFragment/htmlPrefilter, jQuery.fn.html, jQuery.parseHTML, and the HTML branch of jQuery.fn.init; these are the direct stored-DOM-XSS path for app-definition and record data authored by one AppSheet principal and rendered in another's authenticated session.jQuery.globalEval → DOMEval, _evalUrl, the "text script" AJAX converter, and JSONP; the deliberate copying of the nonce attribute onto generated <script> elements is exactly the primitive that defeats a nonce + 'strict-dynamic' policy if an attacker controls the evaluated string.window-exposed SubscribeEmail( id ) in components/account/Settings.tsx), where a string beginning with < is silently reinterpreted as HTML.dist/ provenance — dist/jquery.js/.min.js/.min.map were generated locally (3.6.2-pre, 2023-03-15) rather than taken from an upstream release, and they, not src/, are what webpack bundles and ships to customers; they must be proven to correspond exactly to the reviewed source.package.json dependency will never pick one up automatically.data[i].path / data[i].name concatenation in scripts/_shared/external/jqueryFileTree.js and the .html( actions[i].buttonHtml ) call in LegacyViewManager.tsx; both are presently unreachable but ship in the bundle and would become live XSS the moment a caller is added.Teams can fill out this section with any known filed vulnerability bugs that they've determined should be out of scope from future Fortify bug filing.