Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions java/ql/lib/ext/com.couchbase.client.core.env.model.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["com.couchbase.client.core.env", "CertificateAuthenticator", true, "fromKey", "(PrivateKey,String,List)", "", "Argument[0]", "credentials-key", "manual"]
- ["com.couchbase.client.core.env", "CertificateAuthenticator", true, "fromKey", "(PrivateKey,String,List)", "", "Argument[1]", "credentials-password", "manual"]
- ["com.couchbase.client.core.env", "CertificateAuthenticator", true, "fromKeyStore", "(Path,String,Optional<String>)", "", "Argument[1]", "credentials-password", "manual"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- ["com.couchbase.client.core.env", "CertificateAuthenticator", true, "fromKeyStore", "(Path,String,Optional<String>)", "", "Argument[1]", "credentials-password", "manual"]
- ["com.couchbase.client.core.env", "CertificateAuthenticator", true, "fromKeyStore", "(Path,String,Optional)", "", "Argument[1]", "credentials-password", "manual"]

We just use the erased type. I don't think the model will work as it stands.

Please remove all types in angle brackets in other models as well.

- ["com.couchbase.client.core.env", "CertificateAuthenticator", true, "fromKeyStore", "(KeyStore,String)", "", "Argument[1]", "credentials-password", "manual"]
- ["com.couchbase.client.core.env", "PasswordAuthenticator$Builder", true, "username", "(String)", "", "Argument[0]", "credentials-username", "manual"]
- ["com.couchbase.client.core.env", "PasswordAuthenticator$Builder", true, "username", "(Supplier<String>)", "", "Argument[0]", "credentials-username", "manual"]
- ["com.couchbase.client.core.env", "PasswordAuthenticator$Builder", true, "password", "(String)", "", "Argument[0]", "credentials-password", "manual"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the other overload of password? And also PasswordAuthenticator#builder, PasswordAuthenticator#create and PasswordAuthenticatore#ldapCompatible? (I'm looking at the docs here.)

44 changes: 44 additions & 0 deletions java/ql/lib/ext/com.couchbase.client.java.model.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["com.couchbase.client.java", "ClusterOptions", true, "clusterOptions", "(String,String)", "", "Argument[0]", "credentials-username", "manual"]
- ["com.couchbase.client.java", "ClusterOptions", true, "clusterOptions", "(String,String)", "", "Argument[1]", "credentials-password", "manual"]
- ["com.couchbase.client.java", "Cluster", true, "connect", "(String,String,String)", "", "Argument[1]", "credentials-username", "manual"]
- ["com.couchbase.client.java", "Cluster", true, "connect", "(String,String,String)", "", "Argument[2]", "credentials-password", "manual"]
- ["com.couchbase.client.java", "Cluster", true, "query", "(String)", "", "Argument[0]", "sql-injection", "manual"]
- ["com.couchbase.client.java", "Cluster", true, "query", "(String,QueryOptions)", "", "Argument[0]", "sql-injection", "manual"]
Comment on lines +10 to +11
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be lower down, to keep an alphabetical ordering, so it's easier to find them in future. Actually I think we should keep models with the same kind (e.g. sql-injection) together, with a comment between the different blocks.

- ["com.couchbase.client.java", "Cluster", true, "analysticsQuery", "(String)", "", "Argument[0]", "sql-injection", "manual"]
- ["com.couchbase.client.java", "Cluster", true, "analysticsQuery", "(String,AnalyticsOptions)", "", "Argument[0]", "sql-injection", "manual"]
- ["com.couchbase.client.java", "Cluster", true, "queryStreaming", "(String,Consumer<QueryRow>)", "", "Argument[0]", "sql-injection", "manual"]
- ["com.couchbase.client.java", "Cluster", true, "queryStreaming", "(String,QueryOptions,Consumer<QueryRow>)", "", "Argument[0]", "sql-injection", "manual"]
- ["com.couchbase.client.java", "Cluster", true, "searchQuery", "(String,SearchQuery)", "", "Argument[1]", "sql-injection", "manual"]
- ["com.couchbase.client.java", "Cluster", true, "searchQuery", "(String,SearchQuery,SearchOptions)", "", "Argument[1]", "sql-injection", "manual"]
Comment on lines +16 to +17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While these models are correct, they currently don't have any effect, because we don't have any models for taint to flow into a SearchQuery. Ideally we would also model some methods for creating (subclasses of) SearchQuery. I won't block this PR on this, however.

- ["com.couchbase.client.java", "Collection", true, "upsert", "(String,Object)", "", "Argument[1]", "sql-injection", "manual"]
- ["com.couchbase.client.java", "Collection", true, "upsert", "(String,Object,UpsertOptions)", "", "Argument[1]", "sql-injection", "manual"]
- ["com.couchbase.client.java", "Collection", true, "replace", "(String,Object)", "", "Argument[1]", "sql-injection", "manual"]
- ["com.couchbase.client.java", "Collection", true, "replace", "(String,Object,ReplaceOptions)", "", "Argument[1]", "sql-injection", "manual"]
Comment on lines +18 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These methods don't execute queries, so they shouldn't be sql-injection sinks. They could possibly be sinks with a different sink kind, but it isn't immediately obvious to me what that would be.

Suggested change
- ["com.couchbase.client.java", "Collection", true, "upsert", "(String,Object)", "", "Argument[1]", "sql-injection", "manual"]
- ["com.couchbase.client.java", "Collection", true, "upsert", "(String,Object,UpsertOptions)", "", "Argument[1]", "sql-injection", "manual"]
- ["com.couchbase.client.java", "Collection", true, "replace", "(String,Object)", "", "Argument[1]", "sql-injection", "manual"]
- ["com.couchbase.client.java", "Collection", true, "replace", "(String,Object,ReplaceOptions)", "", "Argument[1]", "sql-injection", "manual"]


- addsTo:
pack: codeql/java-all
extensible: summaryModel
data:
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,Object)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,Object)", "", "Argument[1]", "ReturnValue", "taint", "manual"]
Comment on lines +27 to +28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why you're modelling flow through JsonObject. Do any of the methods modelled above (or already modelled) use JsonObject? I don't remember seeing any. Or is it that JsonObjects are often used but aren't mandated?

The models are fine, so there is no need to remove them. I only bring it up in case it makes it clear that there's a gap in the modelling somewhere.

JsonObject is basically a Map, so we could use the MapKey and MapValue access paths so that we can distinguish them.

Suggested change
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,Object)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,Object)", "", "Argument[1]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,Object)", "", "Argument[0]", "ReturnValue.MapKey", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,Object)", "", "Argument[1]", "ReturnValue.MapValue", "taint", "manual"]

This should also be done for all the below models... except I'm actually going to suggest that your replace all of the models for put with these two:

      - ["com.couchbase.client.java.json", "JsonObject", true, "put", "", "", "Argument[0]", "ReturnValue.MapKey", "taint", "manual"]
      - ["com.couchbase.client.java.json", "JsonObject", true, "put", "", "", "Argument[1]", "ReturnValue.MapValue", "taint", "manual"]

(When no signature is specified, the model applies to all methods with that name.)

- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,String)", "", "Argument[1]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,int)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,long)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,number)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,double)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,boolean)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,JsonObject)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,JsonObject)", "", "Argument[1]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,Map)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,Map)", "", "Argument[1]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,JsonArray)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,JsonArray)", "", "Argument[1]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,List)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "put", "(String,List)", "", "Argument[1]", "ReturnValue", "taint", "manual"]
- ["com.couchbase.client.java.json", "JsonObject", true, "putNull", "(String)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
4 changes: 4 additions & 0 deletions java/ql/src/change-notes/2025-12-24-couchbase-sinks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added sink models for `com.couchbase` supporting SQL Injection and Hardcoded Cretentials queries.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would love it if these tests could exercise more (or most? or even all?) of the models you've added. That is the only way of checking that the models work - and in this case it would have caught the issues with angle brackets.

(I would also love it if the tests were converted to inline expectations. But there is no need for you to do that.)

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example;

import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.Cluster;
import com.couchbase.client.java.Collection;
import com.couchbase.client.java.json.JsonObject;

public class CouchBase {
public static void main(String[] args) {
Cluster cluster = Cluster.connect("192.168.0.158", "Administrator", "Administrator");
Bucket bucket = cluster.bucket("travel-sample");
cluster.query(args[1]);

Collection collection = bucket.defaultCollection();
collection.replace("airbnb_1", JsonObject.create().putNull(System.getenv("ITEM_CATEGORY")));
collection.upsert("airbnb_1", JsonObject.create().put("country", args[1]));
}
}
Loading