Scanners close a finding when you install the fixed version. For most advisories that's right. For some, the fixed version adds a setting you have to turn on, keeps an open default, or only prints a warning, and the risk stays exactly where it was until someone changes the configuration. Your dashboard goes green either way.
This post is for teams that measure vulnerability work by findings closed, and for anyone who runs MCP servers, AI tooling or web frameworks that ship with permissive defaults. It walks through four 2026 advisories where upgrading wasn't the whole fix, explains why maintainers ship fixes this way, and gives you a script that lists the advisories you're already "fixed" for whose text says there's more to do.
The short answer
An advisory's fixed version is the release that makes a fix possible, not always the one that applies it. In 2026, MCP Toolbox for Databases added host and origin allow-lists that still default to allowing everything, Open WebUI made its token-exchange check opt-in and wrote that upgrading alone is not sufficient, Pipecat kept its unauthenticated development runner by design and added a startup banner, and fastify's fix skipped header schemas shared through an external reference, printing a warning instead. In each case a scanner reports the issue fixed as soon as the version changes. Read the fix section of every advisory you close, and check that the setting it names is in your deployment.
Four fixes that need you to finish them
| Advisory | Severity | Fixed in | What the upgrade does | What you still have to do |
|---|---|---|---|---|
| MCP Toolbox for Databases, CVE-2026-11624 | Critical | 0.25.0 | Adds --allowed-hosts; both allow-lists default to * and log a warning | Set both flags to your real hosts and origins |
| Open WebUI, CVE-2026-70482 | High | 0.11.0 | Adds a trusted-client check for OAuth token exchange, off unless configured | Set OAUTH_TOKEN_EXCHANGE_TRUSTED_CLIENT_IDS, or leave token exchange disabled |
| Pipecat, CVE-2026-102682 | Medium | 1.6.0 | Adds a startup banner and documentation; the runner stays unauthenticated by design | Never expose the development runner; use an authenticated dispatcher in production |
| fastify, CVE-2026-84428 | High | 5.12.2 | Normalizes header names in inline schemas; schemas added with addSchema and referenced by $ref emit an FSTSEC002 warning | Inline those header schemas, or enforce the rule in a hook |
MCP Toolbox: the allow-list ships open
The Model Context Protocol advises servers to validate the Origin header to prevent DNS rebinding, where a web page tricks a browser into talking to a service on your own machine. MCP Toolbox for Databases had no way to restrict hosts before 0.25.0. That release added --allowed-hosts next to the existing --allowed-origins, and per the advisory both default to * so existing setups don't break. If either is *, the server logs a warning.
That default still holds. In the v1.14.0 source, released on 8 October 2026, both flags default to *, and the warning says a wildcard leaves the server open to DNS rebinding in production or local development alike. The server binds to 127.0.0.1 by default, which doesn't help here: DNS rebinding is precisely the attack that reaches services bound to localhost. A team that upgraded to 0.25.0 or later and changed nothing else closed a critical finding and kept the exposure.
Open WebUI: the advisory says it plainly
Open WebUI's token-exchange endpoint accepted OAuth tokens issued to any client, which allowed account takeover. Version 0.11.0 checks which client a token was issued to, using token introspection, against a list in OAUTH_TOKEN_EXCHANGE_TRUSTED_CLIENT_IDS. The advisory, credited to reporter Classic298, is unusually direct: "Upgrading alone is not sufficient." With the list unset, the endpoint behaves as before. It also notes that providers without introspection support, including Google, Microsoft Entra ID and GitHub, can't be restricted this way, and that token exchange should stay disabled on them.
Pipecat: the fix is a banner
Pipecat's development runner exposes endpoints that create bot sessions, and with the Daily transport, paid Daily rooms, without authentication. It binds to localhost, so exploitation needs an operator to expose it, for example with --host 0.0.0.0, a published port or a public tunnel. Version 1.6.0 adds a prominent startup banner and documentation saying the runner must not face untrusted traffic. The advisory, reported by infycore with agent-kira credited as finder, is clear that the unauthenticated behaviour remains by design. Upgrading changes what you see in the terminal, not what the server accepts.
fastify: one schema pattern left out
Fastify lowercases header-schema names because Node.js stores request headers in lowercase, but it missed the dependencies keyword and nested subschemas. A rule such as "the admin header requires the admin token header" was silently skipped. Version 5.12.2 normalizes every position in an inline schema. Header schemas registered with addSchema and pulled in through $ref aren't reached, and now trigger an FSTSEC002 startup warning telling you to inline them. Reporter schecthellraiser606 found it; the fix is thorough for the common case and honest about the remaining one. If your app uses shared header schemas, the upgrade gave you a warning, not protection.
Why maintainers ship fixes this way
It's usually the right engineering call. Changing a default breaks working deployments, and a security release that breaks people slows down everyone's upgrade, including the ones it would have protected. Some behaviour can't be changed at all: a development runner without authentication is a feature for local work. And sometimes the safe configuration depends on things the maintainer can't see, such as which identity provider you use.
What makes it a problem is the bookkeeping downstream. Vulnerability databases record one fixed version per range, and scanners compare your version against it. Neither has a field for "and then set this flag", so the follow-up step lives only in the advisory's prose, which most teams never read once the version is bumped.
Find the advisories you closed too early
This script reads package-lock.json, pinned requirements.txt files and go.mod, asks OSV for every advisory on each package, keeps the ones your version is already fixed for, and prints any whose text mentions a new flag, an open default, a startup warning, an opt-in check or behaviour kept by design. It uses only the Python standard library:
#!/usr/bin/env python3
"""List advisories your pinned versions are already "fixed" for, where the advisory
text says the fix still needs you to act: a new flag, a default left open, a startup
warning, or behaviour kept by design.
Usage: python3 fixed_but_check.py package-lock.json | requirements.txt | go.mod ...
"""
import json, re, sys, urllib.request
OSV = "https://api.osv.dev/v1/query"
SIGNALS = re.compile(
r"\b(defaults? to ['\"`]?\*|by design|startup (?:warning|banner)|new [`'\"]?-{0,2}[\w-]+[`'\"]? (?:flag|option|setting)"
r"|must (?:be )?(?:set|configure|enable|opt)|opt[- ]in|not reached by|still (?:need|require)s?"
r"|documentation (?:has been|was) updated|remains? (?:unchanged|by design|enabled by default))\b[^.\n]*", re.I)
def parse(path):
if path.endswith("package-lock.json"):
for key, meta in json.load(open(path)).get("packages", {}).items():
if key and "node_modules/" in key and meta.get("version"):
yield "npm", key.rsplit("node_modules/", 1)[1], meta["version"]
elif path.endswith("go.mod"):
for m in re.finditer(r"^\s*(?:require\s+)?([\w.\-/]+\.[\w.\-/]+)\s+(v[\w.\-+]+)", open(path).read(), re.M):
yield "Go", m.group(1), m.group(2)
else:
for line in open(path):
m = re.match(r"\s*([A-Za-z0-9._\-]+)(?:\[[^\]]*\])?\s*==\s*([\w.!+\-]+)", line)
if m:
yield "PyPI", m.group(1), m.group(2)
def key(v):
v = v.lstrip("v").split("+")[0]
m = re.match(r"(\d+(?:\.\d+)*)(.*)", v)
if not m:
return ((0,), 0, v)
nums = tuple(int(x) for x in m.group(1).split(".")) + (0, 0, 0)
rest = m.group(2).lstrip(".-")
return (nums[:4], 0 if rest and not rest.startswith("post") else 1, rest)
def query(eco, name):
body = json.dumps({"package": {"name": name, "ecosystem": eco}}).encode()
req = urllib.request.Request(OSV, body, {"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=30) as r:
return json.load(r).get("vulns", [])
def main(paths):
seen, hits = set(), 0
for path in paths:
for eco, name, ver in parse(path):
if (eco, name) in seen:
continue
seen.add((eco, name))
for v in query(eco, name):
fixes = [e["fixed"] for a in v.get("affected", []) if a["package"]["name"] == name
for rg in a.get("ranges", []) for e in rg.get("events", []) if "fixed" in e]
if not fixes or key(ver) < min(key(f) for f in fixes):
continue # not fixed yet: your scanner already reports it
sentences = re.split(r"(?<=[.!?])\s+(?=[A-Z`\-])|\n+", v.get("details", ""))
said = [s.strip(" -") for s in sentences if SIGNALS.search(s)]
if said:
hits += 1
print(f"{eco} {name} {ver}: {v['id']} (fixed in {min(fixes, key=key)})")
for s in said[:2]:
print(f" \"{s[:200]}\"")
print(f"\n{len(seen)} packages checked, {hits} fixed advisories that may still need configuration")
if __name__ == "__main__":
main(sys.argv[1:])
On a test project with three of the four packages above at their fixed or later versions, plus three packages with no such advisories:
$ python3 fixed_but_check.py go.mod requirements.txt package-lock.json
Go github.com/googleapis/mcp-toolbox v1.14.0: GHSA-76g7-m3xw-x9gr (fixed in 0.25.0)
"In v0.25.0, a new "--allowed-hosts" flag was introduced alongside the existing "--allowed-origins" flag, enabling users to specify permitted hosts at server sta"
"If either flag is set to "*", the server will output a startup warning about potential vulnerabilities."
PyPI pipecat-ai 1.6.0: GHSA-hqm2-cfx2-2vgh (fixed in 1.6.0)
"The development runner displays a prominent startup banner identifying it as a development tool."
"The unauthenticated development behavior remains by design."
npm fastify 5.12.2: GHSA-9q9j-q6p8-xq58 (fixed in 5.12.2)
"Header schemas referenced through an external shared `$ref` (registered with `addSchema`) are not reached by this normalization and now emit an `FSTSEC002` star"
6 packages checked, 3 fixed advisories that may still need configuration
Open WebUI isn't in the test project, but its advisory is caught by the same rules. Expect noise on a real project. Across the 6,988 GitHub-reviewed 2026 advisories for Go, npm and PyPI with a fixed version, 335 contain one of the script's phrases. In a random sample of 20 of those, one was a real "upgrade isn't enough" case and one more was ambiguous. The rest used the phrases to describe the bug, the impact or a safe new default. So treat the output as a short reading list, not a set of findings.
Planning upgrades is the first half of this work, and checking what each upgrade actually changed is the second. Here's Safeguard's interactive walkthrough of the first half, finding the fixes available today:
What to do
- Read the fix section before closing a finding, at least for critical and high advisories. Look for flags, environment variables, defaults and the words "opt-in" or "by design".
- Check the setting, not the version. For the four advisories above: MCP Toolbox's
--allowed-hostsand--allowed-originsaren't*, Open WebUI's trusted client list is set or token exchange is off, no Pipecat development runner is reachable from outside, and no fastify header schema relies on$ref. - Treat startup warnings as findings.
FSTSEC002and the MCP Toolbox wildcard warning are the software telling you the fix isn't in effect. Alert on them in your logs. - Record the configuration step with the fix, in the ticket or a VEX statement, so the next audit can see why the finding is really closed.
- Prefer software with secure defaults when you have the choice. Our post on insecure default configurations covers what to look for.
The fair view
All four maintainers did the responsible thing: they shipped a fix or a guard, documented exactly what it does and doesn't cover, and in two cases warned at startup when the safe setting isn't in use. Open WebUI's advisory is a model of clarity. None of this is hidden.
The gap is that the information arrives as prose, and the tools most teams rely on read only version numbers. Until advisories carry a machine-readable "configuration required" field, the step after the upgrade is a human job. The cost is a few minutes per advisory, and for a critical one like an open allow-list on a server with database access, those minutes are the whole fix.
Check yourself
You upgraded MCP Toolbox for Databases past 0.25.0 and your scanner shows the finding closed. Are you protected against DNS rebinding?
Only if you set --allowed-hosts and --allowed-origins to specific values. Both default to a wildcard, and binding to localhost doesn't stop DNS rebinding, which targets exactly those services. The server logs a warning when a wildcard is in use.
Why didn't the maintainers just change the defaults?
Because a security release that breaks working setups slows upgrades for everyone, and in some cases the safe value depends on your environment, such as your allowed hosts or which OAuth clients you trust. They chose a safe option plus a warning, and documented it.
Your scanner reads only version numbers. What's the cheapest way to catch these cases?
Read the fix section of each critical and high advisory before closing it, alert on startup security warnings in your logs, and run a script like the one above to list closed advisories whose text mentions flags, defaults or opt-in checks.