fix(teams): skip the 1.0.0.0 placeholder, keep Teams Panel/Phone off Teams
Field case: an Intune host lists "MSTeams 1.0.0.0" (CN=Microsoft
Corporation). It drew CVE-2023-4863, -29328, -29330, CVE-2022-21965 and
CVE-2025-53783, plus the Teams classic EOL.
1.0.0.0 names no build. It is the new client's MSIX package (Intune's
"MSTeams", Wazuh's WindowsApps\MSTeams_1.0.0.0_...) with no version read;
no desktop Teams shipped as 1.0.0.0 and classic was never MSIX. Four parts
under 100, so it passed the scheme check and sat below every classic and
Android bound. teams_placeholder_version (1.0.0.0, 1.0, 1, 0.0.0.0) is now
skipped by the cvelistV5 and NVD scans and by _teams_classic. 0a73eafb had
read it as classic; "MSTeams" now counts as the new client for EOL, like
"Microsoft Teams". Real classic builds (1.5.00.31168) keep both.
CVE-2025-53783 came through teams_panels: the NVD filter matched the
vendor:product token as a substring, so microsoft:teams also took
teams_panels and teams_phones (1.0.9x device builds), and Teams for
Android (1.0.0.2025...) got their CVE and the Panel fix 1.0.97.2025102203.
Teams now takes its CPE exactly. Other products keep the prefix match;
Adobe relies on it (acrobat_dc). NVD cache prefix v5.
This commit is contained in:
@@ -1440,6 +1440,18 @@ entry, else the first listed. Windows hosts were told the macOS build
|
||||
is skipped: "Teams for Mac" is not paired, so it held only the desktop's
|
||||
ranges; NVD's macOS entries cover the Mac.
|
||||
|
||||
Version 1.0.0.0 (also 1.0, 1, 0.0.0.0) is a placeholder, not a build:
|
||||
Intune's "MSTeams 1.0.0.0" and Wazuh's WindowsApps\MSTeams_1.0.0.0_… are the
|
||||
new client's MSIX package with no build read. No desktop Teams shipped as
|
||||
1.0.0.0, and classic was never MSIX. Read as a build it sat below every
|
||||
classic and Android bound (CVE-2023-29328/-29330/-4863, CVE-2022-21965) and
|
||||
drew the classic EOL. Both CVE paths and `_teams_classic` skip it
|
||||
(`teams_placeholder_version`); "MSTeams" otherwise counts as the new client
|
||||
for EOL, like "Microsoft Teams". On NVD the Teams lookup takes
|
||||
`microsoft:teams` exactly: `teams_panels` and `teams_phones` (1.0.9x builds)
|
||||
gave Teams for Android their CVE-2025-53783 fix. Prefix matching stays for
|
||||
everything else, Adobe relies on it (`acrobat_dc`).
|
||||
|
||||
**Oracle Java SE, JRE and JDK** (key `oracle-java` on cvelistV5; NVD rows
|
||||
`oracle:jdk` and `oracle:jre`, each with its `sun:` twin for the Sun-era
|
||||
records, 6-8 only; a JDK also asks for the JRE's CVEs). Version from the
|
||||
|
||||
@@ -1092,6 +1092,21 @@ def _same_version_scheme(installed: str, bound: str) -> bool:
|
||||
return (a[0] >= 100) == (b[0] >= 100)
|
||||
|
||||
|
||||
def teams_placeholder_version(version: str) -> bool:
|
||||
"""A Teams version that names no build: 1.0.0.0, 1.0, 1, 0.0.0.0.
|
||||
|
||||
Intune lists the new client's MSIX package as "MSTeams 1.0.0.0", and
|
||||
Wazuh reads the same from WindowsApps\\MSTeams_1.0.0.0_…. No Teams desktop
|
||||
client ever shipped as 1.0.0.0 (classic is 1.N.00.NNNNN, the machine-wide
|
||||
installer 1.N.0.NNNNN, new Teams 2xxxx.x.x.x). Read as a build, it sits
|
||||
below every classic and Android bound of the same shape: CVE-2023-29328,
|
||||
-29330, -4863, CVE-2022-21965 and the Teams classic EOL all landed on it.
|
||||
The CVE scanners and the EOL check skip it; the version is unknown, not
|
||||
old.
|
||||
"""
|
||||
return bool(re.fullmatch(r"[01](?:\.0+)*", (version or "").strip()))
|
||||
|
||||
|
||||
def dotnet_sdk_version(v) -> bool:
|
||||
"""A modern .NET version whose patch is 100+ is an SDK, not a runtime.
|
||||
|
||||
@@ -1274,6 +1289,12 @@ def _query_nvd_cpe(cpe: str, version: str, sap_pl: Optional[int] = None,
|
||||
if prod_token not in crit and not (
|
||||
loadmaster and ":progress:multi-tenant_" in crit):
|
||||
continue # Multi Tenant: its 7.1.35 line, see loadmaster_fix
|
||||
if prod_token == "microsoft:teams" and ":microsoft:teams:" not in crit:
|
||||
# teams_panels / teams_phones: own devices, own 1.0.9x
|
||||
# builds. Teams for Android (1.0.0.2025…) sat below
|
||||
# them and took their CVEs and fix (CVE-2025-53783).
|
||||
# Teams only: Adobe needs the prefix (acrobat_dc).
|
||||
continue
|
||||
if not m.get("vulnerable", True):
|
||||
continue
|
||||
if skip_editions and (crit.split(":") + [""] * 10)[9].lower() \
|
||||
@@ -1412,9 +1433,10 @@ def _cache_put(db: Session, product_key: str, version: str, cves: List[dict]) ->
|
||||
db.commit()
|
||||
|
||||
|
||||
# v5: Teams Panel / Phone CPEs no longer answer for Teams.
|
||||
# v4: Teams bounds scheme-checked, fixes kept per platform. Also drops answers
|
||||
# cached before every NVD page was read.
|
||||
CACHE_PREFIX = "v4:"
|
||||
CACHE_PREFIX = "v5:"
|
||||
|
||||
|
||||
def lookup_cves(db: Session, entry: dict, version: str,
|
||||
@@ -1823,6 +1845,8 @@ def scan_asset_packages(db: Session, asset, packages: list, new_ids: Optional[li
|
||||
entry = resolve_product(name)
|
||||
if not entry:
|
||||
continue
|
||||
if entry["key"] == "cpe:microsoft:teams" and teams_placeholder_version(version):
|
||||
continue
|
||||
java_upd = None
|
||||
if entry.get("java"):
|
||||
# Asked as the release (1.6.0) and decided by the update; shown
|
||||
|
||||
@@ -3817,6 +3817,8 @@ def scan_asset(db: Session, asset, packages: list, index: dict,
|
||||
# at 1.6.00.17554 (its own fix) sat below the desktop's 18681.
|
||||
# NVD carries the macOS entries.
|
||||
continue
|
||||
if key == "teams" and cpe.teams_placeholder_version(version):
|
||||
continue # "MSTeams 1.0.0.0" names no build
|
||||
strict = key in _STRICT_SCHEME_KEYS
|
||||
for entry in index[key]:
|
||||
if not _affected(cver, entry.get("start"), entry.get("lt"),
|
||||
|
||||
@@ -34,6 +34,7 @@ import httpx
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models.setting import Setting
|
||||
from app.services.app_cve_scanner_service import teams_placeholder_version
|
||||
from app.services.eol_service import EOLStatus, EOL_SOON_DAYS, _days_until
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -130,6 +131,10 @@ def _teams_classic(name: str, version: str) -> bool:
|
||||
every shipping new-Teams build is 2xxxx.x.x.x, never 1.x.
|
||||
Intune detectedApps lists the same package by its AppX name "MSTeams".
|
||||
|
||||
1.0.0.0 is none of them: it is what Intune and Wazuh read off the new
|
||||
client's MSIX package (WindowsApps\\MSTeams_1.0.0.0_…) when they get no
|
||||
build. Classic was never an MSIX package; see teams_placeholder_version.
|
||||
|
||||
The version test must not widen past an exact "teams" name — "Microsoft
|
||||
Teams Meeting Add-in for Microsoft Office" is a live product at 1.24.x.
|
||||
"""
|
||||
@@ -139,8 +144,10 @@ def _teams_classic(name: str, version: str) -> bool:
|
||||
if "teams classic" in low or "classic teams" in low:
|
||||
return True
|
||||
ver = (version or "").strip()
|
||||
if teams_placeholder_version(ver):
|
||||
return False
|
||||
if _normalise(name) in ("teams", "msteams"):
|
||||
return ver == "1" or ver.startswith("1.")
|
||||
return ver.startswith("1.")
|
||||
return "machine-wide installer" in low and ver.startswith("1.")
|
||||
|
||||
|
||||
@@ -405,7 +412,7 @@ def resolve_ms_lifecycle_eol(
|
||||
# plain "Microsoft Teams", which is exactly the export's listing name for
|
||||
# BOTH releases — the day Microsoft fills a retirement date on the classic
|
||||
# row, a current Teams would read as CRITICAL EOL.
|
||||
if _normalise(pname) == "teams":
|
||||
if _normalise(pname) in ("teams", "msteams"):
|
||||
return None
|
||||
|
||||
# 1) hardcoded exotics (Silverlight, old VC++ redists)
|
||||
|
||||
@@ -9,12 +9,16 @@ nothing at all. Fixed date instead, matched on name+version.
|
||||
Three inventory entries are that product:
|
||||
Teams Machine-Wide Installer 1.5.0.31168
|
||||
Microsoft Teams classic 1.8.00.18356
|
||||
Microsoft Teams 1.0.0.0
|
||||
Microsoft Teams 1.8.00.18356
|
||||
The third is what Wazuh syscollector reports on a host where the client was
|
||||
never renamed — same name the CURRENT client uses (26198.304.4946.9672), and
|
||||
so does a machine-wide installer belonging to it. Hence the version, not the
|
||||
name, decides: every shipping new-Teams build is 2xxxx.x.x.x, never 1.x.
|
||||
|
||||
1.0.0.0 is not classic. It is what Intune ("MSTeams") and Wazuh
|
||||
(WindowsApps\\MSTeams_1.0.0.0_…) read off the new client's MSIX package when
|
||||
they get no build; no Teams desktop client shipped as 1.0.0.0.
|
||||
|
||||
The version test is pinned to an exact "Microsoft Teams" name, because
|
||||
"Microsoft Teams Meeting Add-in for Microsoft Office" is a live product
|
||||
sitting at 1.24.x and must stay clean.
|
||||
@@ -45,11 +49,7 @@ def test_classic_is_eol():
|
||||
for name, version in (
|
||||
("Microsoft Teams classic", "1.8.00.18356"),
|
||||
("Teams Machine-Wide Installer", "1.5.0.31168"),
|
||||
# Wazuh syscollector, WindowsApps MSTeams_1.0.0.0_x64__8wekyb3d8bbwe
|
||||
("Microsoft Teams", "1.0.0.0"),
|
||||
("Microsoft Teams", "1.8.00.18356"),
|
||||
# Intune detectedApps lists the same package by its AppX name
|
||||
("MSTeams", "1.0.0.0"),
|
||||
):
|
||||
st = _resolve(name, version)
|
||||
assert st is not None, f"{name}: no EOL finding"
|
||||
@@ -65,6 +65,13 @@ def test_current_teams_is_not_eol():
|
||||
assert _resolve("Teams Machine-Wide Installer", "26198.304.4946.9672") is None
|
||||
|
||||
|
||||
def test_placeholder_version_is_not_classic():
|
||||
"""Intune: "MSTeams 1.0.0.0"; Wazuh: WindowsApps\\MSTeams_1.0.0.0_…."""
|
||||
for name in ("MSTeams", "Microsoft Teams", "Teams", "Teams Machine-Wide Installer"):
|
||||
for version in ("1.0.0.0", "1.0", "1"):
|
||||
assert _resolve(name, version) is None, (name, version)
|
||||
|
||||
|
||||
def test_meeting_addin_is_not_teams():
|
||||
"""Live product at 1.24.x — the 1.x rule must not reach it."""
|
||||
assert _resolve(
|
||||
@@ -75,5 +82,6 @@ def test_meeting_addin_is_not_teams():
|
||||
if __name__ == "__main__":
|
||||
test_classic_is_eol()
|
||||
test_current_teams_is_not_eol()
|
||||
test_placeholder_version_is_not_classic()
|
||||
test_meeting_addin_is_not_teams()
|
||||
print("OK — Teams classic EOL 2024-07-01, current Teams + add-in clean")
|
||||
|
||||
@@ -69,7 +69,13 @@ NVD = {"vulnerabilities": [
|
||||
_m("*", "1.6.00.26474", edition="desktop")]),
|
||||
("CVE-2025-53783", [_m("android", "1.0.0.2025102802"), _m("iphone_os", "7.10.1"),
|
||||
_m("macos", "25122.1207.3700.1444"),
|
||||
_m("*", "25122.1415.3698.6812", edition="desktop")]),
|
||||
_m("*", "25122.1415.3698.6812", edition="desktop"),
|
||||
{"vulnerable": True, "versionEndExcluding": "1.0.97.2025102203",
|
||||
"criteria": "cpe:2.3:a:microsoft:teams_panels:*:*:*:*:*:*:*:*"},
|
||||
{"vulnerable": True, "versionEndExcluding": "1.0.94.2025168802",
|
||||
"criteria": "cpe:2.3:a:microsoft:teams_phones:*:*:*:*:*:*:*:*"}]),
|
||||
# No platform on the bounded entry: Android / Rooms numbering.
|
||||
("CVE-2022-21965", [_m("*", "1.0.94.20000")]),
|
||||
)]}
|
||||
|
||||
|
||||
@@ -208,6 +214,27 @@ def demo():
|
||||
assert mac["CVE-2023-4863"] == "1.6.00.26463", mac
|
||||
assert mac["CVE-2023-29328"] == "1.6.00.17554", mac
|
||||
|
||||
# --- placeholder ------------------------------------------------------------
|
||||
# Intune: "MSTeams 1.0.0.0" — the new client's MSIX package without a
|
||||
# build. Four parts and below every classic / Android bound, so it drew
|
||||
# CVE-2023-29328/-29330 (cvelistV5 + NVD), -4863, CVE-2022-21965 and,
|
||||
# via teams_panels' 1.0.97.x, CVE-2025-53783.
|
||||
for version in ("1.0.0.0", "1.0.0", "1", "0.0.0.0"):
|
||||
for name in ("MSTeams", "Microsoft Teams", "Teams"):
|
||||
assert _scan5(index, name, version) == [], (name, version)
|
||||
assert _scan_nvd("Windows 11 Enterprise", version) == [], version
|
||||
# …while a real classic build still gets them, and the old bound's
|
||||
# Android numbering (1.0.94.x) is not a placeholder.
|
||||
assert _scan_nvd("Windows 11 Enterprise", "1.5.00.31168") == _nvd("1.5.00.31168")
|
||||
assert not cpe.teams_placeholder_version("1.0.94.19999")
|
||||
|
||||
# --- Teams Panel / Phone --------------------------------------------------
|
||||
# Their own CPEs (teams_panels, teams_phones), not Teams. Teams for
|
||||
# Android (1.0.0.2025…) sits below their 1.0.9x bounds and picked them up,
|
||||
# fix included. It gets the Android entry only.
|
||||
c = next(c for c in _query("1.0.0.2025102801") if c["cve"] == "CVE-2025-53783")
|
||||
assert c["fixes"] == {"android": "1.0.0.2025102802"}, c
|
||||
|
||||
print("ok classic Teams 1.5.00.31168 gets CVE-2023-29328/-29330 from both paths "
|
||||
"with the desktop fix, CVE-2023-24881 (2.x only) stays off it")
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ def test_other_families_and_arp_entries_untouched():
|
||||
_msix("Microsoft Teams", "MSTeams", "26225.1806.5074.1452"),
|
||||
_msix("Company Portal", "Microsoft.CompanyPortal", "11.2.1.0"),
|
||||
# Same name, classic ARP install, no WindowsApps folder — a different
|
||||
# product line and must survive (EOL scan flags it).
|
||||
# product line and must survive.
|
||||
{"name": "Microsoft Teams", "version": "1.0.0.0", "location": ""},
|
||||
{"name": "Mozilla Firefox", "version": "141.0"},
|
||||
]
|
||||
|
||||
@@ -117,7 +117,7 @@ def _index():
|
||||
return _INDEX_SETTING
|
||||
|
||||
|
||||
@check("NVD result cache prefix", "v4:")
|
||||
@check("NVD result cache prefix", "v5:")
|
||||
def _cache():
|
||||
from app.services.app_cve_scanner_service import CACHE_PREFIX
|
||||
return CACHE_PREFIX
|
||||
|
||||
Reference in New Issue
Block a user