Apache Polaris accepts literal `*` characters in namespace and table names. When it
later builds temporary S3 access policies for delegated table access, those
same characters appear to be reused unescaped in S3 IAM resource patterns
and
`s3:prefix` conditions.
In S3 IAM policy matching, `*` is treated as a wildcard rather than as
ordinary text. That means temporary credentials issued for one crafted table
can match the storage path of a different table.
In private testing against Polaris 1.4.0 using Polaris' AWS S3 temporary-
credential path on both MinIO and real AWS S3, credentials returned for
crafted tables such as `f*.t1`, `f*.*`, `*.*`, and `foo.*` could reach other
tables' S3 locations.
The confirmed behavior includes:
- reading another table's metadata control file ([Iceberg metadata JSON]);
- listing another table's exact S3 table prefix ([table prefix]);
- and, when write delegation was returned for the crafted table, creating
and
deleting an object under another table's exact S3 table prefix.
A control case using ordinary different names did not allow the same
cross-table access.
A least-privilege AWS S3 variant was also confirmed in which the attacker
principal had no Polaris permissions on the victim table and only the
minimal permissions required to create and use a crafted wildcard table
(namespace-scoped `TABLE_CREATE` and `TABLE_WRITE_DATA` on `*`). In that
setup, direct Polaris access to `foo.t1` remained forbidden, but the
attacker
could still create and load `*.*`, receive delegated S3 credentials, and use
those credentials to list, read, create, and delete objects under `foo.t1`.
In Iceberg, the metadata JSON file is a control file: it tells readers which
data files belong to the table, which snapshots exist, and which table
version
to read. So unauthorized access to it is already a meaningful
confidentiality
problem. The confirmed write-capable variant means the issue is not limited
to
disclosure.
In plain terms, Apache Polaris is supposed to issue short-lived GCS credentials
that
only work for one table's files, but a crafted namespace or table name can
cause those credentials to work across the configured bucket instead.
Apache Polaris builds Google Cloud Storage downscoped credentials by creating a
Credential Access Boundary (CAB) with CEL conditions that are intended to
restrict access to the requested table's storage path.
The relevant CEL string is built from the bucket name and the table path.
That
table path is derived from namespace and table identifiers. In current code,
that path appears to be inserted into the CEL expression without escaping.
As a result, a namespace or table identifier containing a single quote and
other URI-safe CEL fragments can break out of the intended quoted string and
change the meaning of the CEL condition.
In private testing against Polaris 1.4.0 on real Google Cloud Storage, it was confirmed that Polaris accepted a crafted identifier and returned delegated
GCS
credentials whose CEL path restriction had effectively collapsed.
Those delegated credentials could then:
- list another table's object prefix;
- read another table's metadata control file (Iceberg metadata JSON);
- create and delete an object under another table's object prefix;
- and also list, read, create, and delete objects under an unrelated
external
prefix in the same bucket that was not part of any table path.
That last point is important. The issue is not limited to "another table".
In
the confirmed setup, once Apache Polaris returned credentials for the crafted
table,
the path restriction inside the configured bucket was effectively gone.
The practical effect is that temporary credentials for one crafted table
can be
broader than the table Polaris was asked to authorize, and can become
effectively bucket-wide within the configured bucket.
The current GCS testing used a Polaris principal with broad catalog
privileges for setup. A separate least-privilege Polaris RBAC variant
has not yet been tested on GCS. However, the storage-credential
broadening behavior itself has been confirmed on GCS.
In Apache Iceberg, the table's metadata files are control files: they tell readers
which data files belong to the table and which table version to read.
`write.metadata.path` is an optional table property that tells Polaris
where to
write those metadata files.
For a table already registered in a
Polaris-managed
catalog, changing only that property through an `ALTER TABLE`-style settings
change (not a row-level `INSERT`, `SELECT`, `UPDATE`, or `DELETE`) bypasses
the commit-time branch that is supposed to revalidate storage locations.
The full persisted / credential-vending variant requires the affected
catalog
to have `polaris.config.allow.unstructured.table.location=true`, with
`allowedLocations` broad enough to include the attacker-chosen target.
`allowedLocations` is the admin-configured allowlist of storage paths that
the
catalog is allowed to use. Public project materials suggest that this flag
is a
real supported compatibility / layout mode, not just a contrived lab-only
prerequisite.
In that configuration, a user who can change table settings can cause Apache Polaris
itself to write new table metadata to an attacker-chosen reachable storage
location before the intended location-validation branch runs.
If the later concrete-path validation also accepts that location, Polaris
persists the resulting metadata path into stored table state. Later
table-load
and credential APIs can then return temporary cloud-storage credentials for
the
same location without revalidating it. In plain terms, Polaris can later
hand
out temporary storage access for the same attacker-chosen area.
That attacker-chosen area does not need to be limited to the poisoned
table's
own files. If it is a broader storage prefix, another table's prefix, or,
depending on configuration or provider behavior, even a bucket/container
root,
the resulting disclosure or corruption scope can extend to any data and
metadata Polaris can reach there.
The practical consequences are therefore similar to the staged-create
credential-vending issue already discussed: data and metadata reachable in
that
storage scope can be exposed and, if write-capable credentials are later
issued, modified, corrupted, or removed. Even before that later credential
step, Polaris itself performs the metadata write to the unchecked location.
So the core issue is not only later credential vending.
The primary defect
is
that Polaris skips its intended location checks before performing a
security-
sensitive metadata write when only `write.metadata.path` changes.
When `polaris.config.allow.unstructured.table.location=false`, current code
review suggests the later `updateTableLike(...)` validation usually rejects
out-of-tree metadata locations before the unsafe path is persisted. That may
reduce the persisted / credential-vending variant, but it does not prevent
the
underlying defect: Polaris still skips the intended pre-write location check
when only `write.metadata.path` changes.
Notesnook is a note-taking app focused on user privacy & ease of use. Prior to Notesnook Web/Desktop version 3.3.15 and prior to Notesnook iOS/Android version 3.3.20, a stored XSS vulnerability in the note export flow can be escalated to remote code execution in the desktop app. The root cause is that exported note fields such as title, headline, and content are inserted into the generated HTML template without HTML escaping. When the note is later exported to PDF, Notesnook renders that HTML into a same-origin, unsandboxed iframe using iframe.srcdoc = .... Injected script executes in the Notesnook origin. In the desktop app, this becomes RCE because Electron is configured with nodeIntegration: true and contextIsolation: false. This issue has been patched in Notesnook Web/Desktop version 3.3.15 and Notesnook iOS/Android version 3.3.20.
D-Link DIR-605L Hardware Revision A1 (End-of-Life, EOL) contains a hardcoded telnet backdoor. The device starts a telnet daemon at boot via /bin/telnetd.sh with the username "Alphanetworks" and the static password "wrgn35_dlwbr_dir605l" read from /etc/alpha_config/image_sign. The custom telnetd binary accepts a -u user:password flag, and the custom login binary uses strcmp() to validate credentials. Successful authentication grants an unauthenticated attacker on the local network a root shell with full administrative control. The device has reached End-of-Life (EOL) and will not receive patches.
D-Link DIR-605L Hardware Revision B2 (End-of-Life, EOL) contains a hardcoded telnet backdoor. The device starts a telnet daemon at boot via /bin/telnetd.sh with the username "Alphanetworks" and the static password "wrgn76_dlwbr_dir605L" read from /etc/alpha_config/image_sign. The custom telnetd binary accepts a -u user:password flag, and the custom login binary uses strcmp() to validate credentials. Successful authentication grants an unauthenticated attacker on the local network a root shell with full administrative control. The device has reached End-of-Life (EOL) and will not receive patches.
D-Link DIR-600L Hardware Revision B1 (End-of-Life) contains a hardcoded telnet backdoor. The device starts a telnet daemon at boot via /bin/telnetd.sh with the username "Alphanetworks" and the static password "wrgn61_dlwbr_dir600L" read from /etc/alpha_config/image_sign. The custom telnetd binary accepts a -u user:password flag, and the custom login binary uses strcmp() to validate credentials. Successful authentication grants an unauthenticated attacker on the local network a root shell with full administrative control. The device has reached End-of-Life (EOL) and will not receive patches.
D-Link DIR-600L Hardware Revision A1 (End-of-Life) contains a hardcoded telnet backdoor. The device starts a telnet daemon at boot via /bin/telnetd.sh with the username "Alphanetworks" and the static password "wrgn35_dlwbr_dir600l" read from /etc/alpha_config/image_sign. The custom telnetd binary accepts a -u user:password flag, and the custom login binary uses strcmp() to validate credentials. Successful authentication grants an unauthenticated attacker on the local network a root shell with full administrative control. The device has reached End-of-Life (EOL) and will not receive patches.
Arbitrary Class Instantiation via Model Manifest in Apache OpenNLP ExtensionLoader
Versions Affected: before 2.5.9, before 3.0.0-M3
Description:
The ExtensionLoader.instantiateExtension(Class, String) method loads a class by its fully-qualified name via Class.forName() and invokes its no-arg constructor, with the class name sourced from the manifest.properties entry of a model archive. The existing isAssignableFrom check correctly rejects classes that are not subtypes of the expected extension interface (BaseToolFactory for factory=, ArtifactSerializer for serializer-class-*), but the check runs after Class.forName() has already loaded and initialized the named class.
Class.forName() with default initialization semantics executes the target class's static initializer before returning, so an attacker who can supply a crafted model archive can cause the static initializer of any class on the classpath to run during model loading, regardless of whether that class passes the subsequent type check.
Exploitation requires a class with attacker-useful side effects in its static initializer (for example, JNDI lookup, outbound network I/O, or filesystem access) to be present on the classpath, so this is not a drop-in remote code execution; however, the attack surface grows as third-party model distribution becomes more common (community model repositories, Hugging Face-style sharing), where users routinely load model files from origins they do not control. A secondary, narrower vector affects deployments that ship legitimate BaseToolFactory or ArtifactSerializer subclasses with side-effecting no-arg constructors: a malicious manifest can name such a class and force its constructor to run during model load.
Mitigation:
* 2.x users should upgrade to 2.5.9.
* 3.x users should upgrade to 3.0.0-M3.
Note: The fix introduces a package-prefix allowlist that is consulted before Class.forName() is invoked, so the static initializer of a disallowed class is never executed. Classes under the opennlp. prefix remain permitted by default. Deployments that load models referencing factories or serializers outside opennlp.* must opt those packages in, either programmatically via ExtensionLoader.registerAllowedPackage(String) before the first model load, or by setting the OPENNLP_EXT_ALLOWED_PACKAGES system property to a comma-separated list of allowed package prefixes.
Users who cannot upgrade immediately should ensure that all model files are sourced from trusted origins and should audit their classpath for classes with side-effecting static initializers or constructors, particularly any that perform JNDI lookups, network requests, or filesystem operations during class initialization.
An out-of-bounds read in the ParseIP6Extended function (/bgp/bgp.go) of gobgp v4.3.0 allows attackers to cause a Denial of Service (DoS) via supplying a crafted BGP UPDATE message.