Jul 23, 2026·6 min read·75 visits
c3p0 versions prior to 0.14.0 contain a deserialization gadget where JavaBean introspectors trigger getConnection() or getPooledConnection() on deserialized DataSources, leading to RCE via malicious JDBC URLs or JNDI lookups.
An untrusted deserialization vulnerability exists in the c3p0 JDBC connection pooling library before version 0.14.0. Standard JDBC getter methods conform to the JavaBean property getter pattern, allowing introspection libraries like Apache Commons BeanUtils to evaluate connection properties dynamically during deserialization, leading to arbitrary code execution when chained with a vulnerable database driver or JNDI sink.
The open-source library c3p0 serves as a JDBC connection pooling manager in enterprise Java applications. By automating the creation, reuse, and disposal of database connections, it optimizes application performance and database interaction. The library exposes public classes that implement the standard JDBC javax.sql.DataSource and javax.sql.ConnectionPoolDataSource interfaces to allow seamless integration into enterprise frameworks.\n\nBecause c3p0 functions within complex enterprise application containers, its classes are frequently instantiated, configured, and serialized. To facilitate runtime properties management, modern frameworks heavily depend on dynamic serialization and JavaBean introspection. This architecture relies on the implicit trust of underlying property names and getter methods, exposing a wide attack surface if untrusted inputs influence object configuration.\n\nIn environments where c3p0 is present on the application classpath alongside an introspection-driven deserialization library, this architectural design introduces a critical weakness. An attacker who is able to submit crafted serialized Java objects can exploit the trust relationship between dynamic reflection and connection configuration. This vulnerability allows an attacker to control the target database URI and trigger connection attempts, leading to remote code execution under specific circumstances.
The root cause of this vulnerability lies in the conflict between the standard JavaBean design conventions and the JDBC specification. Under standard JavaBean rules, any public parameterless method starting with get followed by an uppercase letter is interpreted as a getter for a readable property. When JavaBean helper libraries like Apache Commons BeanUtils scan a class, they translate these getter methods into readable and writable properties.\n\nIn the JDBC specification, the javax.sql.DataSource interface defines the getConnection() method to obtain a database connection, while the javax.sql.ConnectionPoolDataSource interface defines getPooledConnection(). Because these methods match the standard getter signature, standard JDK java.beans.Introspector registers connection and pooledConnection as readable properties. Consequently, utility methods that dynamically query properties will implicitly execute the database connection process.\n\nDuring standard deserialization of dynamic objects, libraries like Apache Commons BeanUtils utilize a BeanComparator to evaluate and compare properties across objects. When a deserialized payload triggers a comparison, the comparator invokes the configured property getter via reflection. If the compared target is a c3p0 DataSource, resolving the connection property forces a call to getConnection(), triggering an active TCP connection to an attacker-controlled endpoint.
The developer addressed the vulnerability in version 0.14.0 by introducing a custom BeanInfo code generation mechanism to modify the exposed metadata of c3p0 classes. In Java, providing an explicit BeanInfo implementation in the same package as the target bean class overrides the automatic reflective discovery performed by the JDK Introspector. The class C3P0BeanInfoGen generates these descriptor files during the project's build phase.\n\njava\npackage com.mchange.v2.c3p0.beaninfo;\n\nimport java.io.*;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\nimport com.mchange.v2.codegen.bean.BeanInfoGen;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\npublic final class C3P0BeanInfoGen\n{\n final static Set excludedPropertyNames;\n final static Set excludedPropertyTypes;\n\n static\n { \n // Explicitly blacklists the dangerous property names to hide them\n Set tmp0 = new HashSet();\n tmp0.add(\"connection\");\n tmp0.add(\"pooledConnection\");\n excludedPropertyNames = Collections.unmodifiableSet(tmp0);\n\n // Explicitly blacklists return types that trigger database interactions\n Set tmp1 = new HashSet();\n tmp1.add( java.sql.Connection.class );\n tmp1.add( javax.sql.PooledConnection.class );\n excludedPropertyTypes = Collections.unmodifiableSet(tmp1);\n }\n // ... (rest of code generation logic follows)\n}\n\n\nBy generating explicit BeanInfo descriptors that exclude the connection and pooledConnection properties, standard JavaBean reflection libraries can no longer find these properties. Consequently, attempts to dynamically resolve the \"connection\" property result in a standard property-not-found exception rather than executing the underlying database connection method. This mechanism cleanly severs the link between JavaBean introspection and JDBC execution, neutralizing the deserialization gadget path.
Exploitation of this vulnerability requires the presence of specific dependencies on the target application's classpath. The primary prerequisite is an active deserialization vector that parses attacker-supplied object streams. Additionally, an introspection-based deserialization carrier such as Apache Commons BeanUtils must be present to bridge the gap between deserialization and getter invocation.\n\nmermaid\ngraph LR\n A[\"Serialized Payload\"] --> B[\"PriorityQueue.readObject()\"]\n B --> C[\"BeanComparator.compare()\"]\n C --> D[\"PropertyUtils.getProperty()\"]\n D --> E[\"ComboPooledDataSource.getConnection()\"]\n E --> F[\"Remote Exploit Execution\"]\n\n\nThe attack sequence begins when the target system deserializes a crafted payload containing a PriorityQueue configured with a BeanComparator. During queue rebuilding, the comparator executes dynamic property resolution on the elements. This action triggers getConnection() on the deserialized c3p0 DataSource, forcing the library to establish a connection to the configured JDBC URL. The attacker controls this URL, pointing it to a rogue database (e.g., an H2 instance executing custom SQL command scripts) or an external JNDI service to load malicious byte code.\n\nBecause the exploit relies on third-party drivers or JNDI sinks to execute commands, the payload composition varies based on the classpath of the target. For instance, if the H2 database driver is present, the connection URL triggers SQL script evaluation, executing commands via a user-defined alias. Alternatively, a JNDI-backed DataSource configuration allows loading arbitrary class files via LDAP or RMI lookups.
The immediate impact of successful exploitation is remote code execution in the context of the running Java Virtual Machine. An attacker who successfully delivers a weaponized payload can run arbitrary system commands, potentially leading to a complete compromise of the underlying application server and hosting infrastructure.\n\nWhile the CVSS Base Score is calculated at 6.3, this reflects the moderate rating of c3p0 itself since the connection pooling library functions as an intermediate gadget rather than the final execution context. However, in practice, the technical severity depends on the classpath environment. If a vulnerable database driver or unmitigated JNDI sink is available, the impact escalates directly to a critical system compromise.\n\nFurthermore, the confidentiality, integrity, and availability of database assets connected to the application are severely threatened. Once code execution is achieved, the attacker can extract application database credentials, modify operational data, or disrupt business services by executing denial-of-service commands on host systems.
To resolve the vulnerability, developers must upgrade the c3p0 connection pooling library to version 0.14.0 or newer. Upgrading ensures that the built-in BeanInfo files are present on the classpath, blocking reflective utilities from locating the connection-triggering properties.\n\nIf upgrading is not immediately possible, temporary workarounds should be applied to restrict the deserialization attack surface. The application should be configured to reject Java serialized objects from untrusted sources, transitioning to secure serialization alternatives like JSON or Protocol Buffers. Additionally, deploying look-ahead deserialization firewalls or custom ObjectInputStream filters can prevent the instantiation of dangerous classes like BeanComparator or c3p0 DataSources.\n\nEgress filtering must also be implemented on target servers to block unexpected outbound TCP connections. Restricting outbound connections to authorized database ports prevents the target from connecting to rogue external servers or fetching remote payloads via JNDI or HTTP channels.
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
c3p0 Steve Waldman | < 0.14.0 | 0.14.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-502 / CWE-915 |
| Attack Vector | Network |
| CVSS v4.0 Score | 6.3 |
| EPSS Score | 0.00284 |
| Exploit Status | Proof-of-Concept |
| KEV Status | Not Listed |
The application deserializes untrusted serialization streams without validating that the incoming objects are safe.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.
Contao Open Source CMS versions 4.0.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 contain a Cross-Site Request Forgery (CSRF) vulnerability in backend parameter handling. The `RequestTokenListener` component validates anti-CSRF tokens solely for HTTP POST requests, while GET-based declarative guards run only when an `act` parameter is present in the query string. Consequently, custom backend actions dispatched via alternative parameters such as `key=` can execute without CSRF token verification when triggered by an authenticated user.
Contao CMS versions 4.1.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 fail to validate form submission tokens and enforce rate limiting when processing activation email resend requests via HTTP POST, enabling resource exhaustion and account state enumeration.
An information disclosure vulnerability in Contao CMS allows unauthenticated site visitors to view protected page titles, URLs, and text excerpts through search queries when protected page indexing is disabled after previously being enabled.
In Vikunja prior to version 2.6.0, relation creation via the CalDAV endpoint fails to invoke the TaskRelation.CanCreate authorization check. This missing access control allows an authenticated user to establish unauthorized relationships and perform write operations against any task, provided its unique identifier (UID) is known.
A cross-project information disclosure vulnerability in Vikunja allows authenticated users with read access to one project to view private task details from unauthorized projects via subtask expansion parameters.