Jan 23, 2026·6 min read·100 visits
If an attacker can modify your `logback.xml`, they can trick the Joran engine into treating a non-existent appender reference as a fully qualified class name. Logback will then helpfully instantiate that class via reflection. While the CVSS is low due to the prerequisite of file write access, it serves as a powerful persistence or privilege escalation vector.
A logic flaw in the Joran configuration engine within Logback-core allows attackers with write access to configuration files to instantiate arbitrary classes via reflection, leading to code execution.
Let's be honest: Java logging libraries are the gift that keeps on giving. Just when you thought the trauma of Log4Shell had faded into a dull ache, Logback—the 'safe' alternative—decided to hold our beer.
CVE-2026-1225 isn't a network-facing nuke like its predecessors. It’s quieter, more subtle, and frankly, a bit more embarrassing. It lives in Joran, Logback's internal configuration engine. Joran is responsible for parsing those sprawling logback.xml files that everyone copy-pastes from StackOverflow and turning them into live Java objects.
The problem? Joran is too helpful. It loves instantiation. It sees a string in an XML tag and thinks, 'I wonder if this is a class I can load?' In this specific case, the mechanism used to reference Appenders (the things that actually write logs to files or consoles) had a fallback logic so loose it might as well have been a try { eval() } catch { ignore }.
If you have write access to the config file, you don't just control the logs; you control the runtime. This vulnerability is a reminder that in the world of Java, 'configuration' is often just a euphemism for 'uncompiled code'.
To understand the bug, you have to look at how Logback handles dependencies. When you define a logger in XML, you attach appenders to it using the <appender-ref> tag.
Typically, it looks like this:
<root level="info">
<appender-ref ref="CONSOLE" />
</root>Joran sees ref="CONSOLE" and looks up an appender named CONSOLE in its internal map. Simple, right? But what happens if Joran can't find an appender named CONSOLE?
In versions prior to 1.5.25, Joran’s DefaultProcessor and AppenderRefModelHandler got creative. Instead of strictly failing, the logic allowed for a fallback where the string provided in the ref attribute could be interpreted as a Fully Qualified Class Name (FQCN).
Why? Presumably for some dynamic dependency resolution feature lost to time. But practically, it meant that if I put <appender-ref ref="com.example.MyEvilClass" />, and an appender named com.example.MyEvilClass didn't exist, Joran would shrug and say, 'Well, maybe it's a class?' and attempt to instantiate it via reflection using the default constructor.
This is a classic 'Desirability vs. Security' trade-off failure. The engine prioritized making things work (resolving dependencies dynamically) over ensuring that only explicitly defined components were loaded.
The fix, landed in commit 1f97ae1844b1be8486e4e9cade98d7123d3eded5 by Ceki Gülcü, introduces a concept that should have probably been there from day one: Declaration Analysis.
The patch introduces a new component, AppenderDeclarationAnalyser. Before Joran tries to link anything up, this analyzer creates a strict allowlist (DECLARED_APPENDER_NAME_SET) of all appenders that are explicitly defined in the XML.
Here is a conceptual view of the change in AppenderRefModelHandler.java.
The Vulnerable Logic (Conceptual):
// Old, loose logic
String refName = attributes.getValue("ref");
Appender appender = appenderBag.get(refName);
if (appender == null) {
// DANGER ZONE: The code might drift into attempting
// to resolve 'refName' as a class later in the chain.
dependencyQueue.add(refName);
}The Fixed Logic:
// New, strict logic
String refName = attributes.getValue("ref");
// The Guard Clause
if (!isAppenderDeclared(mic, refName)) {
addWarn("Appender named [" + refName + "] not declared. Skipping.");
return;
}
// Proceed only if it's a known, declared appenderBy enforcing this check, the DefaultProcessor is prevented from ever reaching the fallback code paths that attempt reflection on arbitrary strings. If you didn't define it with an <appender> tag, you can't reference it. Game over.
Let's construct an attack. We are assuming you have achieved file write access—maybe via a directory traversal bug in a different service, or perhaps you're an insider threat with access to the deployment repo.
Target: An application utilizing logback-core < 1.5.25.
Goal: Execute code during application startup/reload.
First, we need a Gadget. Since this isn't a deserialization bug, we don't need a complex chain like CommonsCollections. We just need a class that does something interesting in its Constructor or Static Initializer.
Let's assume the classpath contains a utility class with a static block that registers a service or performs a lookup.
The Malicious logback.xml:
<configuration>
<!-- Standard Setup -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder><pattern>%msg%n</pattern></encoder>
</appender>
<root level="debug">
<!-- Valid reference -->
<appender-ref ref="STDOUT" />
<!-- THE TRIGGER -->
<!-- Joran looks for appender named 'com.evil.Gadget'. Fails. -->
<!-- Joran tries Class.forName('com.evil.Gadget').newInstance() -->
<appender-ref ref="com.evil.Gadget" />
</root>
</configuration>When the application restarts or reloads the configuration (Logback supports scan="true" for hot-reloading!), Joran parses the tree. It hits the malicious ref. It fails to find the appender. It falls back to reflection. The class com.evil.Gadget is instantiated.
If com.evil.Gadget puts a shell connection in its constructor, you now have a shell running as the application user.
You might look at the CVSS score of 1.8 and laugh. 'Low severity? Why are we even talking about this?'
Context is king. The score is low because the Attack Vector is local (AV:L) and requires high privileges (PR:H - write access to config). But in the real world, vulnerabilities are rarely exploited in isolation. They are chained.
Imagine a scenario where you have a limited Arbitrary File Write (AFW) vulnerability. Usually, turning a file write into Code Execution (RCE) requires overwriting a binary, a web shell in a specific directory, or a cron job—all of which might be blocked by OS permissions or read-only filesystems.
However, logback.xml is often writable by the application user to allow for log level adjustments. This CVE turns a simple text file modification into full code execution. It is a persistence gadget and a privilege escalation helper.
If an attacker is on your box and modifies your logging config, they aren't just messing with your audit trails; they are embedding a logic bomb that detonates the next time your app restarts.
The remediation is straightforward: Update to Logback-core 1.5.25.
If you cannot update immediately, you must treat your configuration files as executable code.
logback.xml is read-only for the application user.<configuration scan="true">, turn it off. Hot-reloading configs gives an attacker an instant trigger mechanism.Appender named [...] could not be found. If you see this in your logs, especially referencing strange class names, investigate immediately.Don't let your logging library be the reason you get paged at 3 AM.
CVSS:4.0/AV:L/AC:H/AT:P/PR:H/UI:N/VC:L/VI:L/VA:L/SC:L/SI:L/SA:L/S:N/AU:N/RE:M/U:Green| Product | Affected Versions | Fixed Version |
|---|---|---|
Logback-core QOS.CH | < 1.5.25 | 1.5.25 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-470 |
| Attack Vector | Local (File Write) |
| CVSS v4.0 | 1.8 (Low) |
| Impact | Arbitrary Code Execution |
| Privileges Required | High (Write Access) |
| Exploit Status | Poc / Theoretical |
Use of Externally-Controlled Input to Select Classes or Code ('Unsafe Reflection')
CVE-2022-0492 is a high-severity missing authorization vulnerability in the Linux kernel's Control Groups (cgroups) v1 implementation. The flaw resides within the cgroup_release_agent_write function in kernel/cgroup/cgroup-v1.c, where the kernel fails to validate if the process writing to the release_agent file possesses administrative capabilities in the initial user namespace. This allows a local attacker inside a container with root privileges (UID 0) to abuse user namespaces, mount a cgroups v1 directory, modify the release_agent parameter, and execute arbitrary commands on the host system as host root, effectively achieving a complete container escape.
NocoDB is subject to an insufficient session expiration vulnerability where OAuth access and refresh tokens are not invalidated or revoked during security-sensitive actions such as password changes, forgot-password requests, or password resets. This allows an attacker possessing an active OAuth token to maintain unauthorized persistence.
A vulnerability in the vantage6 federated learning framework allows unauthenticated remote attackers to gain administrative control of the server via hardcoded default credentials (root/root) when deployed under default configurations in versions 4.2.3 and below.
An improper access control vulnerability in the vantage6 node component allows concurrently running algorithm containers to read and modify sensitive input and output files of other tasks. The lack of strict workspace directory isolation exposes a significant attack surface in multi-tenant or federated environments where untrusted algorithms are executed.
TinyMCE versions 6.8.0 through 7.0.1 contain a high-severity Cross-Site Scripting (XSS) vulnerability. The flaw exists in the custom HTML parser and sanitizer module, which incorrectly manages SVG namespace scopes when parsing nested elements. A low-privileged or unauthenticated attacker can submit a crafted HTML payload containing nested SVG structures to bypass sanitization filters, leading to arbitrary JavaScript execution in the context of the victim's browser session.
CVE-2026-47759 is a critical stored Cross-Site Scripting (XSS) vulnerability affecting multiple active branches of the TinyMCE rich text editor. The flaw resides in the editor's handling of user-controlled, prefixed internal attributes, such as data-mce-href, data-mce-src, and data-mce-style. When processing raw HTML inputs, TinyMCE's internal validation schema neglects to inspect these custom prefixed attributes. During HTML serialization, the editor's engine extracts these unsanitized values and copies them back into standard executable attributes, overwriting any previously sanitized standard values and leading to execution of arbitrary code.