Like calling a third-party number and blindly trusting whoever picks up
The finding behind tenable:106657 maps to jQuery’s old habit of auto-executing text/javascript returned from a cross-domain Ajax request when developers used $.ajax() / $.get() without an explicit dataType. Tenable flags jQuery 1.x before 1.12.0 and 2.x before 2.2.0, because the jQuery 1.12.0 / 2.2.0 releases added a mitigation for this behavior. The broader CVE record, CVE-2015-9251, was later scoped as affecting jQuery before 3.0.0, which is why this plugin often under-describes the real version story.
Vendor MEDIUM is fair in a lab, but still a bit generous for enterprise patch triage. The bug is only reachable when the application actually makes a vulnerable cross-origin Ajax call to an attacker-controlled or compromised endpoint, and most sites simply do not do that in a way an external attacker can steer on demand. This is real, but it is heavily conditional, highly application-specific, and a terrible candidate for emergency patching across 10,000 hosts.
4 steps from start to impact.
Find a jQuery page that makes cross-origin Ajax calls
$.ajax() / $.get() to a third-party origin without an explicit dataType. The library version alone is not enough; the application has to exercise the bad pattern. The relevant behavior is documented in jQuery issue #2432 and the later mitigation commit f60729f.- Victim browses an application that ships vulnerable jQuery
- The application makes a cross-domain Ajax request
- The request omits an explicit
dataType
- Many apps never make cross-origin jQuery Ajax calls at all
- Modern apps often use
fetch, back-end proxies, or explicit JSON APIs instead - Static library detection does not prove the dangerous code path exists
$.ajax(, $.get(, and cross-domain URLs is better for applicability.Gain control of the remote response
Content-Type. The original report demonstrates a malicious endpoint returning text/javascript, which jQuery then treated as executable content.- Attacker controls or can tamper with the cross-origin endpoint
- Browser can reach that endpoint from the victim context
- This usually requires compromise of a partner API, CDN-like endpoint, or app configuration weakness
- TLS, pinned destinations, and allowlisted domains make this much less reachable in mature environments
- If the third-party endpoint is stable and trusted, the attacker has no path
Trigger jQuery script auto-execution
jQuery.globalEval() even when the caller did not request script execution. The mitigation commit explicitly added a prefilter to disable auto-execution for crossDomain requests unless dataType: "script" is set.- Returned response is treated as script-capable content
- The request remains cross-domain in jQuery’s logic
- The exact behavior depends on request options and response headers
- Applications already using
dataTypesafely or sanitizing flows are not meaningfully exposed
Abuse the victim session in-browser
- Victim must load the affected page and trigger the request
- The application session has something worth stealing or abusing
- Impact stays inside the browser session unless chained further
- HttpOnly cookies, strong CSP, and short-lived tokens can reduce practical payoff
The supporting signals.
| Mapped issue | CVE-2015-9251; Tenable plugin 106657 specifically keys on the 1.12.0 / 2.2.0 mitigation milestone rather than the broader CVE scope. |
|---|---|
| In-the-wild status | No CISA KEV listing and I found no authoritative evidence of active exploitation campaigns tied to this CVE in the sources reviewed. |
| PoC / weaponization | A public demo exists in jQuery issue #2432 and Packet Storm/RetireJS references are attached from NVD. That makes reproduction easy for testers, but not the same as broad offensive use. |
| EPSS | Current public telemetry is elevated for a medium bug: Bitsight shows 18.01% probability over 30 days at the 95th percentile. Tenable’s CVE page also shows FIRST EPSS on the record, which confirms this CVE stays visible in exploit-likelihood feeds. |
| KEV status | Not present in CISA’s Known Exploited Vulnerabilities Catalog. No due date exists because it is not KEV-listed. |
| CVSS and meaning | NVD scores it 6.1 / MEDIUM with CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N: network reachable, but user interaction is required and impact is browser-session level. |
| Affected versions | Authoritative CVE language says jQuery before 3.0.0. The Tenable plugin title is narrower: 1.x < 1.12.0 / 2.x < 2.2.0. |
| Fixed versions | Upstream mitigation appears in 1.12.0 and 2.2.0 release notes, but Debian notes only 3.0 was fixed upstream for the full CVE because backporting was considered too invasive. Treat 3.0.0+ as the clean answer. |
| Exposure data | Bitsight Groma currently shows about 2,023,513 observations tied to this CVE over the prior 30 days, with 39.02% of observations in the US. That says the library is common, not that each instance is exploitable. |
| Timeline / attribution | The dangerous behavior was publicly discussed in jQuery issue #2432 on 2015-06-26; the mitigation shipped in the 2016-01-08 jQuery 1.12.0 / 2.2.0 release; NVD published the CVE on 2018-01-18. The GitHub issue was opened by homakov. |
noisgate verdict.
The decisive downgrade factor is attacker reachability: this is not a generic 'load page, get popped' library bug. An attacker needs a very specific application behavior—unsafe cross-origin jQuery Ajax to an attacker-influenced endpoint—which sharply narrows the exposed population even though vulnerable jQuery versions are widespread.
Why this verdict
- Downgrade for prerequisite chain: the attacker does not get value from the library version alone; they need a live cross-origin
$.ajax()/$.get()call with no explicitdataType. - Downgrade for attacker position: requiring control of a third-party response path implies either compromise of an external service, misrouting, or application-specific endpoint abuse. That is much narrower than unauthenticated direct exploitation.
- Downgrade for blast radius: successful exploitation lands in the victim browser session, not as direct server-side code execution or broad host compromise.
- Slight upward pressure: public demos exist and EPSS is higher than many medium-severity bugs, so this is not noise-only.
Why not higher?
There is no direct pre-auth server compromise path here. The exploit chain depends on a fragile combination of front-end coding pattern, cross-origin request behavior, and attacker control of the response source; that is too much real-world friction for MEDIUM-or-higher patch urgency across a large fleet.
Why not lower?
This is still a real client-side execution issue with public repro steps, and some legacy apps absolutely do make unsafe jQuery cross-domain calls. If one of your internet-facing portals relies on this pattern, the result can still be credential theft or session abuse for active users.
What to do — in priority order.
- Inventory the code path — Within backlog hygiene timing for a LOW issue, confirm whether the app actually performs cross-origin jQuery Ajax without explicit
dataType. This is the single fastest way to separate real exposure from scanner noise. - Eliminate browser-to-third-party Ajax where possible — Move third-party API calls server-side or through a same-origin proxy so the browser is not executing trust decisions on remote content. For this LOW verdict, fold this into normal engineering backlog rather than emergency change windows.
- Set explicit
dataTypeon legacy jQuery requests — Where legacy code must stay, forcedataType: 'json'or another expected type so script auto-execution is not inferred from response headers. Do this during the next planned maintenance cycle. - Harden CSP — Use a stricter
script-srcand eliminate unnecessary execution allowances to reduce the payoff of browser-side script injection. CSP is not a perfect fix here, but it can reduce downstream abuse while you clean up old front-end code.
- A WAF does not reliably help because the bad decision happens inside legitimate browser-side JavaScript after the page loads.
- Blindly trusting the library version finding does not prove exploitability; this CVE is highly dependent on application behavior.
- EDR on user endpoints usually has poor visibility into a browser executing allowed JavaScript from an application origin.
Crowdsourced verification payload.
Run this on the target web server, build artifact directory, or unpacked static-content repo that actually hosts front-end assets. Invoke it as python3 verify_jquery_106657.py /var/www/html or point it at your CI artifact root; no admin rights are required beyond read access to the files.
#!/usr/bin/env python3
# verify_jquery_106657.py
# Purpose: validate whether local jQuery assets match Tenable plugin 106657 conditions.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN/usage error
import os
import re
import sys
from typing import Optional, Tuple
VERSION_RE = re.compile(r"jQuery v?(\d+)\.(\d+)\.(\d+)", re.I)
FILENAME_RE = re.compile(r"jquery(?:[-.]min)?[-.]?(\d+)\.(\d+)\.(\d+)", re.I)
JS_EXT = (".js", ".jsp", ".html", ".htm", ".cshtml", ".php", ".twig")
def parse_version(text: str) -> Optional[Tuple[int, int, int]]:
m = VERSION_RE.search(text)
if m:
return tuple(map(int, m.groups()))
m = FILENAME_RE.search(text)
if m:
return tuple(map(int, m.groups()))
return None
def classify(ver: Tuple[int, int, int]) -> str:
major, minor, patch = ver
# Tenable plugin 106657 logic
if major == 1 and ver < (1, 12, 0):
return "VULNERABLE"
if major == 2 and ver < (2, 2, 0):
return "VULNERABLE"
# Important nuance: broader CVE-2015-9251 language says < 3.0.0.
# Versions 1.12.x and 2.2.x contain the mitigation Tenable is looking for,
# but may still be treated as affected by broader CVE records.
if major in (1, 2) and ver >= ((1, 12, 0) if major == 1 else (2, 2, 0)):
return "UNKNOWN"
if major >= 3:
return "PATCHED"
return "UNKNOWN"
def inspect_file(path: str) -> Optional[Tuple[Tuple[int, int, int], str]]:
# First try filename
ver = parse_version(os.path.basename(path))
if ver:
return ver, classify(ver)
# Then read a small chunk from the file body for the jQuery banner
try:
with open(path, "r", encoding="utf-8", errors="ignore") as f:
chunk = f.read(65536)
ver = parse_version(chunk)
if ver:
return ver, classify(ver)
except Exception:
return None
return None
def main() -> int:
if len(sys.argv) != 2:
print("UNKNOWN - usage: python3 verify_jquery_106657.py <webroot-or-artifact-dir>")
return 2
root = sys.argv[1]
if not os.path.exists(root):
print(f"UNKNOWN - path does not exist: {root}")
return 2
findings = []
for base, _, files in os.walk(root):
for name in files:
if not name.lower().endswith(JS_EXT):
continue
path = os.path.join(base, name)
result = inspect_file(path)
if result:
ver, state = result
findings.append((path, ver, state))
if not findings:
print("UNKNOWN - no identifiable jQuery assets found")
return 2
vulnerable = [f for f in findings if f[2] == "VULNERABLE"]
unknown = [f for f in findings if f[2] == "UNKNOWN"]
patched = [f for f in findings if f[2] == "PATCHED"]
if vulnerable:
path, ver, _ = vulnerable[0]
print(f"VULNERABLE - found jQuery {ver[0]}.{ver[1]}.{ver[2]} at {path}")
return 1
if unknown:
sample = unknown[0]
path, ver, _ = sample
print(f"UNKNOWN - found jQuery {ver[0]}.{ver[1]}.{ver[2]} at {path}; Tenable plugin condition may be mitigated, but broader CVE-2015-9251 scope should be reviewed")
return 2
path, ver, _ = patched[0]
print(f"PATCHED - found jQuery {ver[0]}.{ver[1]}.{ver[2]} at {path}")
return 0
if __name__ == "__main__":
sys.exit(main())
If you remember one thing.
dataType; for a LOW verdict there is no noisgate mitigation SLA and no noisgate remediation SLA—treat it as backlog hygiene. If the unsafe pattern exists on a sensitive external app, fix the code path and move the jQuery upgrade into the next normal release train; if it is only a library-version hit with no reachable pattern, document the exception and move on.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.