Add Fortify scanner THREAT_MODEL.md to third_party/jquery repo

Bug: b/548455274
Change-Id: Iede575191dd3ac6ad7b3cc3e8dff0853be1757b7
Reviewed-on: https://gnocchi-internal-review.git.corp.google.com/c/third_party/jquery/+/316628
Reviewed-by: Adam Stone <stoneadam@google.com>
diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md
new file mode 100644
index 0000000..8b3f46d
--- /dev/null
+++ b/THREAT_MODEL.md
@@ -0,0 +1,328 @@
+# Security Threat Model: jQuery (AppSheet Trusted-Types Fork)
+
+## Asset Definition & Scope
+
+-   **Component:** jQuery — client-side JavaScript DOM manipulation, traversal,
+    event, effects, and AJAX library.
+-   **Repository:** Git-on-Borg
+    (`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.
+-   **Upstream baseline:** jQuery **3.6.2** (upstream release 2022-12-13),
+    including the bundled **Sizzle 2.3.8** selector engine
+    (`external/sizzle/dist/sizzle.js`). Declared in `METADATA` as
+    `version: "3.6.2"`, `last_upgrade_date: 2023-03-01`.
+-   **Fork delta:** This is a **Trusted-Types-patched** build of jQuery. Relative
+    to the pristine upstream 3.6.2 tarball, only four source files differ, all of
+    them to remove `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&lt;8 / IE&lt;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.
+    -   Additionally the repo commits a locally produced `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.
+-   **Explicitly NOT changed:** no CVE backports, no security hardening, and no
+    modification to any runtime HTML sink. `jQuery.fn.html`, `buildFragment`,
+    `jQuery.parseHTML`, `jQuery.htmlPrefilter`, `jQuery.globalEval`, `DOMEval`,
+    and the Sizzle selector parser are byte-identical to upstream 3.6.2.
+-   **Scope:** The full library source (`src/`), the vendored selector engine
+    (`external/sizzle/`), and the committed prebuilt bundles (`dist/`) that are
+    the artifacts actually consumed by AppSheet.
+
+### Consumption by AppSheet
+
+-   Pinned by exact commit in
+    `jeenee/Nirvana/Content/package.json`:
+    `"jquery": "git+https://appsheet-third-party.googlesource.com/jquery#1d60e5afef1b0287e855686a4d524d8cf3aa61ee"`
+    (with `@types/jquery` 3.5.14).
+-   A single ES import in
+    `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`.
+-   Server-rendered Razor views additionally ship a pre-minified copy via
+    `<script nonce="@CspNonce" src="/Scripts/jquery-3.6.2.min.js">`
+    (`V3/MainServer/Views/Shared/_LegacyContentLayout.cshtml` and friends).
+-   Bundled jQuery plugins that extend the same `$` object:
+    `_shared/external/jqueryFileTree`, `jquery.exif`, `jquery.canvasresize`.
+
+## Prioritization Signals
+
+-   **1P OSS:** No (third-party open-source library maintained as an internal
+    customized fork for Google AppSheet; upstream is
+    `https://github.com/jquery/jquery`, MIT).
+-   **1P Proprietary Shipped Software:** Yes. Although the code itself is
+    third-party OSS, this fork's `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.
+-   **High-Risk Code Surface:** Yes. jQuery is fundamentally a collection of
+    DOM-injection sinks: string-to-DOM HTML parsing
+    (`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.
+-   **Perimeter Exposure:** Yes. AppSheet is a 1P Google Cloud service exposed to
+    the public Internet; this library is downloaded and executed by every
+    unauthenticated and authenticated visitor of AppSheet app pages, the app
+    editor, the site/marketing pages, and the app gallery.
+-   **Data Sensitivity:** High. jQuery-driven legacy view controllers render
+    customer business records, PII, file/attachment metadata, account and
+    billing surfaces, and app-definition metadata directly into the DOM. Because
+    it runs in the AppSheet origin, a compromise yields access to session
+    cookies, `localStorage`/`localforage` caches of record data, and the ability
+    to issue authenticated first-party API calls on the victim's behalf.
+-   **Untrusted Input Handling:** Yes. Strings that reach jQuery APIs originate
+    from (a) **AppSheet app definitions** authored by customers — column names,
+    view names, action labels, format rules, expressions; (b) **end-user record
+    data** from customer spreadsheets/databases, including free-text and
+    Long-Text columns and uploaded file names; (c) **first-party API responses**
+    (`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.
+-   **Business Value:** jQuery is load-bearing for AppSheet's entire legacy view
+    layer and the app editor shell; it cannot be trivially removed. It is also
+    the specific reason this fork exists — the patches were required so AppSheet
+    could roll out `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.
+
+## Scanning Harness Prompts
+
+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.
+
+1.  **Audit the Trusted Types patch delta first.** Review the four TT-gated
+    branches in `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.
+2.  **Flag the `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.
+3.  **Trace all string→DOM parsing sinks for XSS.** Focus on
+    `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.
+4.  **Trace all dynamic script-execution sinks.** `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.
+5.  **Analyze the Sizzle selector parser for injection and ReDoS.**
+    `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`.
+6.  **Check `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`.
+7.  **Verify `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.
+8.  **Report upstream version drift.** Baseline 3.6.2 is materially behind
+    current upstream jQuery (3.7.x). Enumerate upstream security-relevant fixes
+    and advisories landed after 3.6.2 that are absent here.
+
+## Entry Points and Untrusted Inputs
+
+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. |
+
+## Trust Boundaries and Auth Assumptions
+
+-   **Authentication**: None at the library level. jQuery executes in the
+    browser with whatever ambient authority the AppSheet origin already has —
+    session cookies are attached automatically to same-origin `jQuery.ajax`
+    calls (`xhrFields`/`withCredentials` semantics are decided by the caller).
+-   **Authorization**: None at the library level. Access control is enforced
+    server-side by AppSheet (`jeenee` MainServer / ControllerHandler); jQuery
+    will faithfully issue whatever request the calling code constructs.
+-   **Implicit trust**: The library implicitly trusts every string handed to its
+    HTML and script sinks. It provides **no sanitizer** and makes no attempt to
+    distinguish app-author content from end-user content. AppSheet's frontend
+    is responsible for choosing `.text()` over `.html()`, and for routing
+    genuinely-HTML content through `dompurify` / `sanitize-html` / `safevalues`.
+-   **Trusted Types as the compensating control**: This fork exists precisely
+    because AppSheet enforces
+    `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 `'&#8203;'` 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.
+-   **Boundary crossings**: AppSheet app author (customer) authors an app
+    definition → AppSheet backend stores/serves it → end user (a different,
+    often external principal) loads the app in a browser → app-definition
+    strings and record data cross into the **same-origin DOM** through jQuery →
+    rendered alongside the victim's authenticated session. A second crossing:
+    first-party API responses (`JeeneeBrowserAPI.ts`, `JSONHelp.ts`) → jQuery
+    AJAX converters → DOM. A third: third-party origins reachable via
+    `dataType: "script"` / JSONP → same-origin script execution.
+
+## Sensitive Data Paths
+
+| 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 |
+
+## Privileged Actions
+
+| 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 |
+
+## Priority Review Areas
+
+1.  **The Trusted Types patch delta itself** (`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.
+2.  **The `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.
+3.  **HTML-string sinks reachable from customer content** —
+    `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.
+4.  **Script-execution sinks and CSP-nonce laundering** — `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.
+5.  **Selector injection and ReDoS in Sizzle** — a hand-rolled regex tokenizer
+    that AppSheet feeds with dynamically constructed selectors (e.g. the
+    `window`-exposed `SubscribeEmail( id )` in `components/account/Settings.tsx`),
+    where a string beginning with `<` is silently reinterpreted as HTML.
+6.  **Prebuilt `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.
+7.  **Upstream version drift and absent CVE backports** — the fork is frozen at
+    3.6.2 (Dec 2022) with zero security patches applied on top, so every
+    post-3.6.2 upstream security fix is missing and the pinned-by-SHA
+    `package.json` dependency will never pick one up automatically.
+8.  **Known unescaped call sites in AppSheet's own jQuery usage** — the
+    `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.
+
+## Out of Scope
+
+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.