From 49d826f6674d9ce8dea47af920888028dd6e715c Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Mon, 25 Sep 2023 11:48:27 +0100
Subject: [PATCH 001/497] Ruby: Add a query for CSRF protection not enabled
Specifically in Rails apps, we look for root ActionController classes
without a call to `protect_from_forgery`.
---
.../ruby/frameworks/ActionController.qll | 80 +++++++++++--------
.../cwe-352/CSRFProtectionNotEnabled.qhelp | 65 +++++++++++++++
.../cwe-352/CSRFProtectionNotEnabled.ql | 23 ++++++
.../examples/ProtectFromForgeryGood.rb | 4 +
.../cwe-352/CSRFProtectionNotEnabled.expected | 1 +
.../cwe-352/CSRFProtectionNotEnabled.qlref | 1 +
.../alternative_root_controller.rb | 3 +
7 files changed, 144 insertions(+), 33 deletions(-)
create mode 100644 ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.qhelp
create mode 100644 ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
create mode 100644 ruby/ql/src/queries/security/cwe-352/examples/ProtectFromForgeryGood.rb
create mode 100644 ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.expected
create mode 100644 ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.qlref
create mode 100644 ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/alternative_root_controller.rb
diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
index be1df5066e1..5500eca0607 100644
--- a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
+++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
@@ -21,6 +21,35 @@ private import codeql.ruby.dataflow.internal.DataFlowDispatch
module ActionController {
// TODO: move the rest of this file inside this module.
import codeql.ruby.frameworks.actioncontroller.Filters
+
+ /**
+ * An ActionController class which sits at the top of the class hierarchy.
+ * In other words, it does not subclass any other class in source code.
+ */
+ class RootController extends ActionControllerClass {
+ RootController() {
+ not exists(ActionControllerClass parent | this != parent and this = parent.getADescendent())
+ }
+ }
+
+ /**
+ * A call to `protect_from_forgery`.
+ */
+ class ProtectFromForgeryCall extends CsrfProtectionSetting::Range, DataFlow::CallNode {
+ ProtectFromForgeryCall() {
+ this = actionControllerInstance().getAMethodCall("protect_from_forgery")
+ }
+
+ private string getWithValueText() {
+ result = this.getKeywordArgument("with").getConstantValue().getSymbol()
+ }
+
+ // Calls without `with: :exception` can allow for bypassing CSRF protection
+ // in some scenarios.
+ override boolean getVerificationSetting() {
+ if this.getWithValueText() = "exception" then result = true else result = false
+ }
+ }
}
/**
@@ -38,18 +67,10 @@ module ActionController {
*/
class ActionControllerClass extends DataFlow::ClassNode {
ActionControllerClass() {
- this =
- [
- DataFlow::getConstant("ActionController").getConstant("Base"),
- // In Rails applications `ApplicationController` typically extends `ActionController::Base`, but we
- // treat it separately in case the `ApplicationController` definition is not in the database.
- DataFlow::getConstant("ApplicationController"),
- // ActionController::Metal technically doesn't contain all of the
- // methods available in Base, such as those for rendering views.
- // However we prefer to be over-sensitive in this case in order to find
- // more results.
- DataFlow::getConstant("ActionController").getConstant("Metal")
- ].getADescendentModule()
+ this = DataFlow::getConstant("ApplicationController").getADescendentModule()
+ or
+ this = actionControllerBaseClass().getADescendentModule() and
+ not exists(DataFlow::ModuleNode m | m = actionControllerBaseClass().asModule() | this = m)
}
/**
@@ -73,6 +94,20 @@ class ActionControllerClass extends DataFlow::ClassNode {
}
}
+private DataFlow::ConstRef actionControllerBaseClass() {
+ result =
+ [
+ // In Rails applications `ApplicationController` typically extends `ActionController::Base`, but we
+ // treat it separately in case the `ApplicationController` definition is not in the database.
+ DataFlow::getConstant("ActionController").getConstant("Base"),
+ // ActionController::Metal technically doesn't contain all of the
+ // methods available in Base, such as those for rendering views.
+ // However we prefer to be over-sensitive in this case in order to find
+ // more results.
+ DataFlow::getConstant("ActionController").getConstant("Metal")
+ ]
+}
+
private API::Node actionControllerInstance() {
result = any(ActionControllerClass cls).getSelf().track()
}
@@ -406,27 +441,6 @@ class ActionControllerSkipForgeryProtectionCall extends CsrfProtectionSetting::R
override boolean getVerificationSetting() { result = false }
}
-/**
- * A call to `protect_from_forgery`.
- */
-private class ActionControllerProtectFromForgeryCall extends CsrfProtectionSetting::Range,
- DataFlow::CallNode
-{
- ActionControllerProtectFromForgeryCall() {
- this = actionControllerInstance().getAMethodCall("protect_from_forgery")
- }
-
- private string getWithValueText() {
- result = this.getKeywordArgument("with").getConstantValue().getSymbol()
- }
-
- // Calls without `with: :exception` can allow for bypassing CSRF protection
- // in some scenarios.
- override boolean getVerificationSetting() {
- if this.getWithValueText() = "exception" then result = true else result = false
- }
-}
-
/**
* A call to `send_file`, which sends the file at the given path to the client.
*/
diff --git a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.qhelp b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.qhelp
new file mode 100644
index 00000000000..9b8944b1d65
--- /dev/null
+++ b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.qhelp
@@ -0,0 +1,65 @@
+
+
+
+
+
+ Cross-site request forgery (CSRF) is a type of vulnerability in which an
+ attacker is able to force a user to carry out an action that the user did
+ not intend.
+
+
+
+ The attacker tricks an authenticated user into submitting a request to the
+ web application. Typically this request will result in a state change on
+ the server, such as changing the user's password. The request can be
+ initiated when the user visits a site controlled by the attacker. If the
+ web application relies only on cookies for authentication, or on other
+ credentials that are automatically included in the request, then this
+ request will appear as legitimate to the server.
+
+
+
+ A common countermeasure for CSRF is to generate a unique token to be
+ included in the HTML sent from the server to a user. This token can be
+ used as a hidden field to be sent back with requests to the server, where
+ the server can then check that the token is valid and associated with the
+ relevant user session.
+
+
+
+
+
+ In the Rails web framework, CSRF protection is enabled by the adding a call to
+ the protect_from_forgery method inside an
+ ActionController class. Typically this is done in the
+ ApplicationController class, or an equivalent class from which
+ other controller classes are subclassed.
+
+ The default behaviour of this method is to null the session when an invalid
+ CSRF token is provided. This may not be sufficient to avoid a CSRF
+ vulnerability - for example if parts of the session are memoized. Calling
+ protect_from_forgery with: :exception can help to avoid this
+ by raising an exception on an invalid CSRF token instead.
+
+
+
+
+
+ The following example shows a case where CSRF protection is enabled with
+ a secure request handling strategy of :exception.
+
+
+
+
diff --git a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
new file mode 100644
index 00000000000..4210d798863
--- /dev/null
+++ b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
@@ -0,0 +1,23 @@
+/**
+ * @name CSRF protection not enabled
+ * @description Not enabling CSRF protection may make the application
+ * vulnerable to a Cross-Site Request Forgery (CSRF) attack.
+ * @kind problem
+ * @problem.severity warning
+ * @security-severity 8.8
+ * @precision high
+ * @id rb/csrf-protection-not-enabled
+ * @tags security
+ * external/cwe/cwe-352
+ */
+
+import codeql.ruby.AST
+import codeql.ruby.Concepts
+import codeql.ruby.frameworks.ActionController
+
+from ActionController::RootController c
+where
+ not exists(ActionController::ProtectFromForgeryCall call |
+ c.getSelf().flowsTo(call.getReceiver())
+ )
+select c, "Potential CSRF vulnerability due to forgery protection not being enabled"
diff --git a/ruby/ql/src/queries/security/cwe-352/examples/ProtectFromForgeryGood.rb b/ruby/ql/src/queries/security/cwe-352/examples/ProtectFromForgeryGood.rb
new file mode 100644
index 00000000000..ecab2c8ea45
--- /dev/null
+++ b/ruby/ql/src/queries/security/cwe-352/examples/ProtectFromForgeryGood.rb
@@ -0,0 +1,4 @@
+class ApplicationController < ActionController::Base
+ protect_from_forgery with: :exception
+end
+
\ No newline at end of file
diff --git a/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.expected b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.expected
new file mode 100644
index 00000000000..7fe8b3490a9
--- /dev/null
+++ b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.expected
@@ -0,0 +1 @@
+| railsapp/app/controllers/alternative_root_controller.rb:1:1:3:3 | AlternativeRootController | Potential CSRF vulnerability due to forgery protection not being enabled |
diff --git a/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.qlref b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.qlref
new file mode 100644
index 00000000000..8e9e894fe51
--- /dev/null
+++ b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.qlref
@@ -0,0 +1 @@
+queries/security/cwe-352/CSRFProtectionNotEnabled.ql
\ No newline at end of file
diff --git a/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/alternative_root_controller.rb b/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/alternative_root_controller.rb
new file mode 100644
index 00000000000..8cbf31529c1
--- /dev/null
+++ b/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/alternative_root_controller.rb
@@ -0,0 +1,3 @@
+class AlternativeRootController < ActionController::Base
+ # BAD: no protect_from_forgery call
+end
\ No newline at end of file
From 6d6f8ba512b4bdba57a09b6815aed8228a9425c4 Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Mon, 25 Sep 2023 13:46:50 +0100
Subject: [PATCH 002/497] Ruby: Make CSRF query more sensitive
Generate an alert for every controller class that doesn't have or
inherity a `protect_from_forgery` setting.
---
.../cwe-352/CSRFProtectionNotEnabled.ql | 20 +++++++++++++------
.../cwe-352/CSRFProtectionNotEnabled.expected | 3 ++-
.../controllers/subscriptions_controller.rb | 3 +++
.../app/controllers/tags_controller.rb | 2 ++
4 files changed, 21 insertions(+), 7 deletions(-)
create mode 100644 ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/subscriptions_controller.rb
create mode 100644 ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/tags_controller.rb
diff --git a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
index 4210d798863..235798e66d4 100644
--- a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
+++ b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
@@ -15,9 +15,17 @@ import codeql.ruby.AST
import codeql.ruby.Concepts
import codeql.ruby.frameworks.ActionController
-from ActionController::RootController c
-where
- not exists(ActionController::ProtectFromForgeryCall call |
- c.getSelf().flowsTo(call.getReceiver())
- )
-select c, "Potential CSRF vulnerability due to forgery protection not being enabled"
+/**
+ * Holds if a call to `protect_from_forgery` is made in the controller class `definedIn`,
+ * which is inherited by the controller class `child`.
+ */
+private predicate protectFromForgeryCall(
+ ActionControllerClass definedIn, ActionControllerClass child,
+ ActionController::ProtectFromForgeryCall call
+) {
+ definedIn.getSelf().flowsTo(call.getReceiver()) and child = definedIn.getADescendent()
+}
+
+from ActionControllerClass c
+where not protectFromForgeryCall(_, c, _)
+select c, "Potential CSRF vulnerability due to forgery protection not being enabled."
diff --git a/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.expected b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.expected
index 7fe8b3490a9..52e2b1aaa4b 100644
--- a/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.expected
+++ b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.expected
@@ -1 +1,2 @@
-| railsapp/app/controllers/alternative_root_controller.rb:1:1:3:3 | AlternativeRootController | Potential CSRF vulnerability due to forgery protection not being enabled |
+| railsapp/app/controllers/alternative_root_controller.rb:1:1:3:3 | AlternativeRootController | Potential CSRF vulnerability due to forgery protection not being enabled. |
+| railsapp/app/controllers/tags_controller.rb:1:1:2:3 | TagsController | Potential CSRF vulnerability due to forgery protection not being enabled. |
diff --git a/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/subscriptions_controller.rb b/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/subscriptions_controller.rb
new file mode 100644
index 00000000000..9e1cfcf9a1e
--- /dev/null
+++ b/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/subscriptions_controller.rb
@@ -0,0 +1,3 @@
+class SubscriptionsController < AlternativeRootController
+ protect_from_forgery with: :exception
+end
\ No newline at end of file
diff --git a/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/tags_controller.rb b/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/tags_controller.rb
new file mode 100644
index 00000000000..4c3f586b9fe
--- /dev/null
+++ b/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/tags_controller.rb
@@ -0,0 +1,2 @@
+class TagsController < AlternativeRootController
+end
\ No newline at end of file
From 581072721cac3d8e4e2ff42cbf0005af58b2f06d Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Mon, 25 Sep 2023 13:57:30 +0100
Subject: [PATCH 003/497] Ruby: Add change note
---
.../change-notes/2023-09-25-csrf-protection-not-enabled.md | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 ruby/ql/src/change-notes/2023-09-25-csrf-protection-not-enabled.md
diff --git a/ruby/ql/src/change-notes/2023-09-25-csrf-protection-not-enabled.md b/ruby/ql/src/change-notes/2023-09-25-csrf-protection-not-enabled.md
new file mode 100644
index 00000000000..e8e7ac54e38
--- /dev/null
+++ b/ruby/ql/src/change-notes/2023-09-25-csrf-protection-not-enabled.md
@@ -0,0 +1,4 @@
+---
+category: newQuery
+---
+* Added a new experimental query, `rb/csrf-protection-not-enabled`, to detect cases where Cross-Site Request Forgery protection is not enabled in Ruby on Rails controllers.
From 3c69ab10f25d91107f78f5c6fa31c741fd1b70c8 Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Fri, 29 Sep 2023 15:35:16 +0100
Subject: [PATCH 004/497] Ruby: Restrict rb/csrf-protection-not-enabled
This query only applies to codebases using Ruby on Rails < 5.2, or where
there is no call to `csrf_meta_tags` in the base ERb template.
---
.../ql/lib/codeql/ruby/frameworks/Gemfile.qll | 243 ++++++++++++++++++
.../cwe-352/CSRFProtectionNotEnabled.ql | 20 +-
2 files changed, 262 insertions(+), 1 deletion(-)
create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll
diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll b/ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll
new file mode 100644
index 00000000000..526e8cea736
--- /dev/null
+++ b/ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll
@@ -0,0 +1,243 @@
+private import codeql.ruby.AST
+
+/**
+ * Provides classes and predicates for Gemfiles, including version constraint logic.
+ */
+module Gemfile {
+ private File getGemfile() { result.getBaseName() = "Gemfile" }
+
+ /**
+ * A call to `gem` inside a gemfile. This defines a dependency. For example:
+ *
+ * ```rb
+ * gem "actionpack", "~> 7.0.0"
+ * ```
+ *
+ * This call defines a dependency on the `actionpack` gem, with version constraint `~> 7.0.0`.
+ * For detail on version constraints, see the `VersionConstraint` class.
+ */
+ class Gem extends MethodCall {
+ Gem() { this.getMethodName() = "gem" and this.getFile() = getGemfile() }
+
+ string getName() { result = this.getArgument(0).getConstantValue().getStringlikeValue() }
+
+ /**
+ * Gets the `i`th version string for this gem. A single `gem` call may have multiple version constraints, for example:
+ *
+ * ```rb
+ * gem "json", "3.4.0", ">= 3.0"
+ * ```
+ */
+ string getVersionString(int i) {
+ result = this.getArgument(i + 1).getConstantValue().getStringlikeValue()
+ }
+
+ /**
+ * Gets a version constraint defined by this call.
+ */
+ VersionConstraint getAVersionConstraint() { result = this.getVersionString(_) }
+ }
+
+ private newtype TComparator =
+ TEq() or
+ TNeq() or
+ TGt() or
+ TLt() or
+ TGeq() or
+ TLeq() or
+ TPGeq()
+
+ /**
+ * A comparison operator in a version constraint.
+ */
+ private class Comparator extends TComparator {
+ string toString() { result = this.toSourceString() }
+
+ /**
+ * The representation of the comparator in source code.
+ * This is defined separately so that we can change the `toString` implementation without breaking `parseConstraint`.
+ */
+ string toSourceString() {
+ this = TEq() and result = "="
+ or
+ this = TNeq() and result = "!="
+ or
+ this = TGt() and result = ">"
+ or
+ this = TLt() and result = "<"
+ or
+ this = TGeq() and result = ">="
+ or
+ this = TLeq() and result = "<="
+ or
+ this = TPGeq() and result = "~>"
+ }
+ }
+
+ bindingset[s]
+ private predicate parseExactVersion(string s, string version) {
+ version = s.regexpCapture("\\s*(\\d+\\.\\d+\\.\\d+)\\s*", 1)
+ }
+
+ bindingset[s]
+ private predicate parseConstraint(string s, Comparator c, string version) {
+ exists(string pattern | pattern = "(=|!=|>=?|<=?|~>)\\s+(.+)" |
+ c.toSourceString() = s.regexpCapture(pattern, 1) and version = s.regexpCapture(pattern, 2)
+ )
+ }
+
+ class VersionConstraint extends string {
+ Comparator comp;
+ string versionString;
+
+ VersionConstraint() {
+ this = any(Gem g).getVersionString(_) and
+ (
+ parseConstraint(this, comp, versionString)
+ or
+ parseExactVersion(this, versionString) and comp = TEq()
+ )
+ }
+
+ /**
+ * Gets the string defining the version number used in this constraint.
+ */
+ string getVersionString() { result = versionString }
+
+ /**
+ * Gets the `Version` used in this constraint.
+ */
+ Version getVersion() { result = this.getVersionString() }
+
+ /**
+ * Holds if `other` is a version which is strictly greater than the range described by this version constraint.
+ */
+ bindingset[other]
+ predicate before(string other) {
+ comp = TEq() and this.getVersion().before(other)
+ or
+ comp = TLt() and
+ (this.getVersion().before(other) or this.getVersion().equal(other))
+ or
+ comp = TLeq() and this.getVersion().before(other)
+ or
+ // ~> x.y.z <=> >= x.y.z && < x.(y+1).0
+ // ~> x.y <=> >= x.y && < (x+1).0
+ comp = TPGeq() and
+ exists(int thisMajor, int thisMinor, int otherMajor, int otherMinor |
+ thisMajor = this.getVersion().getMajor() and
+ thisMinor = this.getVersion().getMinor() and
+ exists(string maj, string mi | normalizeSemver(other, _, maj, mi, _) |
+ otherMajor = maj.toInt() and otherMinor = mi.toInt()
+ )
+ |
+ exists(this.getVersion().getPatch()) and
+ (
+ thisMajor < otherMajor
+ or
+ thisMajor = otherMajor and
+ thisMinor < otherMinor
+ )
+ or
+ not exists(this.getVersion().getPatch()) and
+ thisMajor < otherMajor
+ )
+ // if the comparator is > or >=, it has no upper bound and therefore isn't guaranteed to be before any other version.
+ }
+ }
+
+ /**
+ * A version number in a version constraint. For example, in the following code
+ *
+ * ```rb
+ * gem "json", ">= 3.4.5"
+ * ```
+ *
+ * The version is `3.4.5`.
+ */
+ private class Version extends string {
+ string normalized;
+
+ Version() {
+ this = any(Gem c).getAVersionConstraint().getVersionString() and
+ normalized = normalizeSemver(this)
+ }
+
+ /**
+ * Holds if this version is strictly before the version defined by `other`.
+ */
+ bindingset[other]
+ predicate before(string other) { normalized < normalizeSemver(other) }
+
+ /**
+ * Holds if this versino is equal to the version defined by `other`.
+ */
+ bindingset[other]
+ predicate equal(string other) { normalized = normalizeSemver(other) }
+
+ /**
+ * Holds if this version is strictly after the version defined by `other`.
+ */
+ bindingset[other]
+ predicate after(string other) { normalized > normalizeSemver(other) }
+
+ /**
+ * Holds if this version defines a patch number.
+ */
+ predicate hasPatch() { exists(getPatch(this)) }
+
+ /**
+ * Gets the major number of this version.
+ */
+ int getMajor() { result = getMajor(normalized).toInt() }
+
+ /**
+ * Gets the minor number of this version, if it exists.
+ */
+ int getMinor() { result = getMinor(normalized).toInt() }
+
+ /**
+ * Gets the patch number of this version, if it exists.
+ */
+ int getPatch() { result = getPatch(normalized).toInt() }
+ }
+
+ /**
+ * Normalizes a SemVer string such that the lexicographical ordering
+ * of two normalized strings is consistent with the SemVer ordering.
+ *
+ * Pre-release information and build metadata is not supported.
+ */
+ bindingset[orig]
+ private predicate normalizeSemver(
+ string orig, string normalized, string major, string minor, string patch
+ ) {
+ major = getMajor(orig) and
+ (
+ minor = getMinor(orig)
+ or
+ not exists(getMinor(orig)) and minor = "0"
+ ) and
+ (
+ patch = getPatch(orig)
+ or
+ not exists(getPatch(orig)) and patch = "0"
+ ) and
+ normalized = leftPad(major) + "." + leftPad(minor) + "." + leftPad(patch)
+ }
+
+ bindingset[orig]
+ private string normalizeSemver(string orig) { normalizeSemver(orig, result, _, _, _) }
+
+ bindingset[s]
+ private string getMajor(string s) { result = s.regexpCapture("(\\d+).*", 1) }
+
+ bindingset[s]
+ private string getMinor(string s) { result = s.regexpCapture("(\\d+)\\.(\\d+).*", 2) }
+
+ bindingset[s]
+ private string getPatch(string s) { result = s.regexpCapture("(\\d+)\\.(\\d+)\\.(\\d+).*", 3) }
+
+ bindingset[str]
+ private string leftPad(string str) { result = ("000" + str).suffix(str.length()) }
+}
diff --git a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
index 235798e66d4..8bbb8d79116 100644
--- a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
+++ b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
@@ -14,6 +14,7 @@
import codeql.ruby.AST
import codeql.ruby.Concepts
import codeql.ruby.frameworks.ActionController
+import codeql.ruby.frameworks.Gemfile
/**
* Holds if a call to `protect_from_forgery` is made in the controller class `definedIn`,
@@ -26,6 +27,23 @@ private predicate protectFromForgeryCall(
definedIn.getSelf().flowsTo(call.getReceiver()) and child = definedIn.getADescendent()
}
+/**
+ * Holds if the Gemfile for this application specifies a version of "rails" < 3.0.0.
+ * Rails versions from 3.0.0 onwards enable CSRF protection by default.
+ */
+private predicate railsPreVersion3() {
+ exists(Gemfile::Gem g | g.getName() = "rails" and g.getAVersionConstraint().before("5.2"))
+}
+
from ActionControllerClass c
-where not protectFromForgeryCall(_, c, _)
+where
+ not protectFromForgeryCall(_, c, _) and
+ // Rails versions prior to 3.0.0 require CSRF protection to be explicitly enabled.
+ // For later versions, there must exist a call to `csrf_meta_tags` in every HTML response.
+ // We currently just check for a call to this method anywhere in the codebase.
+ (
+ railsPreVersion3()
+ or
+ not any(MethodCall m).getMethodName() = "csrf_meta_tags"
+ )
select c, "Potential CSRF vulnerability due to forgery protection not being enabled."
From f19a5a9837a87085be8b26680541fe6dddddd9ad Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Tue, 10 Oct 2023 12:06:51 +0100
Subject: [PATCH 005/497] Ruby: Add tests for Gemfile modeling
---
.../library-tests/frameworks/gemfile/Gemfile | 9 +++++++++
.../frameworks/gemfile/Gemfile.expected | 8 ++++++++
.../library-tests/frameworks/gemfile/Gemfile.ql | 17 +++++++++++++++++
.../frameworks/gemfile/not_gemfile.rb | 1 +
4 files changed, 35 insertions(+)
create mode 100644 ruby/ql/test/library-tests/frameworks/gemfile/Gemfile
create mode 100644 ruby/ql/test/library-tests/frameworks/gemfile/Gemfile.expected
create mode 100644 ruby/ql/test/library-tests/frameworks/gemfile/Gemfile.ql
create mode 100644 ruby/ql/test/library-tests/frameworks/gemfile/not_gemfile.rb
diff --git a/ruby/ql/test/library-tests/frameworks/gemfile/Gemfile b/ruby/ql/test/library-tests/frameworks/gemfile/Gemfile
new file mode 100644
index 00000000000..2e3f2313bfb
--- /dev/null
+++ b/ruby/ql/test/library-tests/frameworks/gemfile/Gemfile
@@ -0,0 +1,9 @@
+source "https://rubygems.org"
+
+gem "rails", "7.0.0"
+gem "json", "~> 2.6.0"
+gem "jwt"
+
+gem "loofah", ">= 2"
+
+gem "invalid-version", "abc"
diff --git a/ruby/ql/test/library-tests/frameworks/gemfile/Gemfile.expected b/ruby/ql/test/library-tests/frameworks/gemfile/Gemfile.expected
new file mode 100644
index 00000000000..9d87e77087e
--- /dev/null
+++ b/ruby/ql/test/library-tests/frameworks/gemfile/Gemfile.expected
@@ -0,0 +1,8 @@
+gemCalls
+| Gemfile:3:1:3:20 | call to gem | rails | 7.0.0 | 7.0.0 |
+| Gemfile:4:1:4:22 | call to gem | json | ~> 2.6.0 | 2.6.0 |
+| Gemfile:7:1:7:20 | call to gem | loofah | >= 2 | 2 |
+versionBefore
+| 2 | 2.6.0 |
+| 2 | 7.0.0 |
+| 2.6.0 | 7.0.0 |
diff --git a/ruby/ql/test/library-tests/frameworks/gemfile/Gemfile.ql b/ruby/ql/test/library-tests/frameworks/gemfile/Gemfile.ql
new file mode 100644
index 00000000000..487d224777b
--- /dev/null
+++ b/ruby/ql/test/library-tests/frameworks/gemfile/Gemfile.ql
@@ -0,0 +1,17 @@
+import codeql.ruby.frameworks.Gemfile
+
+query predicate gemCalls(
+ Gemfile::Gem gem, string name, Gemfile::VersionConstraint constraint, string version
+) {
+ name = gem.getName() and
+ constraint = gem.getAVersionConstraint() and
+ version = constraint.getVersion()
+}
+
+query predicate versionBefore(string before, string after) {
+ exists(Gemfile::VersionConstraint c1, Gemfile::VersionConstraint c2 |
+ c1.getVersion() = before and c2.getVersion() = after
+ |
+ c1.getVersion().before(after)
+ )
+}
diff --git a/ruby/ql/test/library-tests/frameworks/gemfile/not_gemfile.rb b/ruby/ql/test/library-tests/frameworks/gemfile/not_gemfile.rb
new file mode 100644
index 00000000000..a526277026c
--- /dev/null
+++ b/ruby/ql/test/library-tests/frameworks/gemfile/not_gemfile.rb
@@ -0,0 +1 @@
+gem "this-gem-not-in-gemfile", "1.2"
From 0597b2ed1b3b77bcb266a957d074bdcfce82e24b Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Tue, 10 Oct 2023 12:13:59 +0100
Subject: [PATCH 006/497] Ruby: recognise csrf_meta_tag
csrf_meta_tag is an alias for csrf_meta_tags, retained for backwards
compatibility.
---
.../ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
index 8bbb8d79116..cd7961d2f9a 100644
--- a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
+++ b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
@@ -44,6 +44,6 @@ where
(
railsPreVersion3()
or
- not any(MethodCall m).getMethodName() = "csrf_meta_tags"
+ not any(MethodCall m).getMethodName() = ["csrf_meta_tags", "csrf_meta_tag"]
)
select c, "Potential CSRF vulnerability due to forgery protection not being enabled."
From 3499d169f9173223fa3be5f7e7227baa423e0473 Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Tue, 10 Oct 2023 12:20:23 +0100
Subject: [PATCH 007/497] Ruby: Add missing QLDoc
---
ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll b/ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll
index 526e8cea736..c71a783387f 100644
--- a/ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll
+++ b/ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll
@@ -1,3 +1,7 @@
+/**
+ * Provides classes and predicates for Gemfiles, including version constraint logic.
+ */
+
private import codeql.ruby.AST
/**
@@ -19,6 +23,9 @@ module Gemfile {
class Gem extends MethodCall {
Gem() { this.getMethodName() = "gem" and this.getFile() = getGemfile() }
+ /**
+ * Gets the name of the gem in this version constraint.
+ */
string getName() { result = this.getArgument(0).getConstantValue().getStringlikeValue() }
/**
@@ -86,6 +93,10 @@ module Gemfile {
)
}
+ /**
+ * A version constraint in a `gem` call. This consists of a version number and an optional comparator, for example
+ * `>= 1.2.3`.
+ */
class VersionConstraint extends string {
Comparator comp;
string versionString;
From 1fbf177b546a1bb73178be73757e2eb352566c08 Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Tue, 10 Oct 2023 12:21:34 +0100
Subject: [PATCH 008/497] Ruby: QLDoc fix
---
ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll b/ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll
index c71a783387f..83ebc27100a 100644
--- a/ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll
+++ b/ruby/ql/lib/codeql/ruby/frameworks/Gemfile.qll
@@ -61,7 +61,7 @@ module Gemfile {
string toString() { result = this.toSourceString() }
/**
- * The representation of the comparator in source code.
+ * Gets the representation of the comparator in source code.
* This is defined separately so that we can change the `toString` implementation without breaking `parseConstraint`.
*/
string toSourceString() {
From 32b775fdc36c2cf39daf3737fe5fadc74f3cf5eb Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Tue, 10 Oct 2023 15:37:32 +0100
Subject: [PATCH 009/497] Ruby: reduce duplicate alerts for csrf query
Only generate an alert on the top-most vulnerable Rails controller in
the controller tree.
---
.../queries/security/cwe-352/CSRFProtectionNotEnabled.ql | 6 ++++--
.../security/cwe-352/CSRFProtectionNotEnabled.expected | 1 -
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
index cd7961d2f9a..f3631eb4556 100644
--- a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
+++ b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
@@ -18,7 +18,7 @@ import codeql.ruby.frameworks.Gemfile
/**
* Holds if a call to `protect_from_forgery` is made in the controller class `definedIn`,
- * which is inherited by the controller class `child`.
+ * which is inherited by the controller class `child`. These classes may be the same.
*/
private predicate protectFromForgeryCall(
ActionControllerClass definedIn, ActionControllerClass child,
@@ -45,5 +45,7 @@ where
railsPreVersion3()
or
not any(MethodCall m).getMethodName() = ["csrf_meta_tags", "csrf_meta_tag"]
- )
+ ) and
+ // Only generate alerts for the topmost controller in the tree.
+ not exists(ActionControllerClass parent | c = parent.getAnImmediateDescendent())
select c, "Potential CSRF vulnerability due to forgery protection not being enabled."
diff --git a/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.expected b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.expected
index 52e2b1aaa4b..50da7dc0766 100644
--- a/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.expected
+++ b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.expected
@@ -1,2 +1 @@
| railsapp/app/controllers/alternative_root_controller.rb:1:1:3:3 | AlternativeRootController | Potential CSRF vulnerability due to forgery protection not being enabled. |
-| railsapp/app/controllers/tags_controller.rb:1:1:2:3 | TagsController | Potential CSRF vulnerability due to forgery protection not being enabled. |
From 3ee425cc477d70382634dd6aedab98dd0dee3351 Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Fri, 13 Oct 2023 11:52:39 +0100
Subject: [PATCH 010/497] Ruby: Identify ActionController::API
`ActionController::API < ActionController::Base` is a base controller
class, so we should recognise it as such.
---
ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
index 5500eca0607..adeaf79fe17 100644
--- a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
+++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
@@ -100,11 +100,11 @@ private DataFlow::ConstRef actionControllerBaseClass() {
// In Rails applications `ApplicationController` typically extends `ActionController::Base`, but we
// treat it separately in case the `ApplicationController` definition is not in the database.
DataFlow::getConstant("ActionController").getConstant("Base"),
- // ActionController::Metal technically doesn't contain all of the
+ // ActionController::Metal and ActionController::API technically don't contain all of the
// methods available in Base, such as those for rendering views.
- // However we prefer to be over-sensitive in this case in order to find
- // more results.
- DataFlow::getConstant("ActionController").getConstant("Metal")
+ // However we prefer to be over-sensitive in this case in order to find more results.
+ DataFlow::getConstant("ActionController").getConstant("Metal"),
+ DataFlow::getConstant("ActionController").getConstant("API")
]
}
From 081c1201edd177cbfa7d049e99db823210fc8784 Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Tue, 17 Oct 2023 12:36:28 +0100
Subject: [PATCH 011/497] Ruby: Make csrf query more specific
CSRF protection only needs to be explicitly enabled on Rails
applications < 5.2 _or_ those that don't include a `load_defaults` call
with a version >= 5.2.
---
.../cwe-352/CSRFProtectionNotEnabled.ql | 35 ++++++++++++++-----
1 file changed, 26 insertions(+), 9 deletions(-)
diff --git a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
index f3631eb4556..bef764a6104 100644
--- a/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
+++ b/ruby/ql/src/queries/security/cwe-352/CSRFProtectionNotEnabled.ql
@@ -15,6 +15,7 @@ import codeql.ruby.AST
import codeql.ruby.Concepts
import codeql.ruby.frameworks.ActionController
import codeql.ruby.frameworks.Gemfile
+import codeql.ruby.DataFlow
/**
* Holds if a call to `protect_from_forgery` is made in the controller class `definedIn`,
@@ -28,23 +29,39 @@ private predicate protectFromForgeryCall(
}
/**
- * Holds if the Gemfile for this application specifies a version of "rails" < 3.0.0.
- * Rails versions from 3.0.0 onwards enable CSRF protection by default.
+ * Holds if the Gemfile for this application specifies a version of "rails" or "actionpack" < 5.2.
+ * Rails versions prior to 5.2 do not enable CSRF protection by default.
*/
-private predicate railsPreVersion3() {
- exists(Gemfile::Gem g | g.getName() = "rails" and g.getAVersionConstraint().before("5.2"))
+private predicate railsPreVersion5_2() {
+ exists(Gemfile::Gem g |
+ g.getName() = ["rails", "actionpack"] and g.getAVersionConstraint().before("5.2")
+ )
+}
+
+private float getRailsConfigDefaultVersion() {
+ exists(DataFlow::CallNode config, DataFlow::CallNode loadDefaultsCall |
+ DataFlow::getConstant("Rails")
+ .getConstant("Application")
+ .getADescendentModule()
+ .getAnImmediateReference()
+ .flowsTo(config.getReceiver()) and
+ config.getMethodName() = "config" and
+ loadDefaultsCall.getReceiver() = config and
+ loadDefaultsCall.getMethodName() = "load_defaults" and
+ result = loadDefaultsCall.getArgument(0).getConstantValue().getFloat()
+ )
}
from ActionControllerClass c
where
not protectFromForgeryCall(_, c, _) and
- // Rails versions prior to 3.0.0 require CSRF protection to be explicitly enabled.
- // For later versions, there must exist a call to `csrf_meta_tags` in every HTML response.
- // We currently just check for a call to this method anywhere in the codebase.
(
- railsPreVersion3()
+ // Rails versions prior to 5.2 require CSRF protection to be explicitly enabled.
+ railsPreVersion5_2()
or
- not any(MethodCall m).getMethodName() = ["csrf_meta_tags", "csrf_meta_tag"]
+ // For Rails >= 5.2, CSRF protection is enabled by default if there is a `load_defaults` call in the root application class
+ // which specifies a version >= 5.2.
+ not getRailsConfigDefaultVersion() >= 5.2
) and
// Only generate alerts for the topmost controller in the tree.
not exists(ActionControllerClass parent | c = parent.getAnImmediateDescendent())
From 7b3f1a098204388cc7915f7ed35d13fbecbbf804 Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Fri, 23 Feb 2024 11:14:52 +0000
Subject: [PATCH 012/497] Ruby: fix comment
---
ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
index adeaf79fe17..6fde1705018 100644
--- a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
+++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
@@ -67,6 +67,8 @@ module ActionController {
*/
class ActionControllerClass extends DataFlow::ClassNode {
ActionControllerClass() {
+ // In Rails applications `ApplicationController` typically extends `ActionController::Base`, but we
+ // treat it separately in case the `ApplicationController` definition is not in the database.
this = DataFlow::getConstant("ApplicationController").getADescendentModule()
or
this = actionControllerBaseClass().getADescendentModule() and
@@ -97,8 +99,6 @@ class ActionControllerClass extends DataFlow::ClassNode {
private DataFlow::ConstRef actionControllerBaseClass() {
result =
[
- // In Rails applications `ApplicationController` typically extends `ActionController::Base`, but we
- // treat it separately in case the `ApplicationController` definition is not in the database.
DataFlow::getConstant("ActionController").getConstant("Base"),
// ActionController::Metal and ActionController::API technically don't contain all of the
// methods available in Base, such as those for rendering views.
From f5be4079896f13f3b370734ed41cf1a91ce76564 Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Fri, 23 Feb 2024 11:26:53 +0000
Subject: [PATCH 013/497] Ruby: deprecate old ProtectFromForgeryCall class
---
ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
index 6fde1705018..c8667b2b2f2 100644
--- a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
+++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
@@ -441,6 +441,11 @@ class ActionControllerSkipForgeryProtectionCall extends CsrfProtectionSetting::R
override boolean getVerificationSetting() { result = false }
}
+/**
+ * DEPRECATED: Use `ActionController::ProtectFromForgeryCall` instead.
+ */
+deprecated class ActionControllerProtectFromForgeryCall = ActionController::ProtectFromForgeryCall;
+
/**
* A call to `send_file`, which sends the file at the given path to the client.
*/
From dd092fd18f2778645896b5c2a557ccfbdd884601 Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Mon, 26 Feb 2024 10:02:56 +0000
Subject: [PATCH 014/497] Ruby: Fix CSRF test
---
.../security/cwe-352/CSRFProtectionDisabled.expected | 2 +-
.../security/cwe-352/railsapp/config/application.rb | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionDisabled.expected b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionDisabled.expected
index d80c52afc66..be0df7c9da7 100644
--- a/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionDisabled.expected
+++ b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionDisabled.expected
@@ -1,5 +1,5 @@
| railsapp/app/controllers/application_controller.rb:5:3:5:22 | call to protect_from_forgery | Potential CSRF vulnerability due to forgery protection being disabled or weakened. |
| railsapp/app/controllers/users_controller.rb:4:3:4:47 | call to skip_before_action | Potential CSRF vulnerability due to forgery protection being disabled or weakened. |
-| railsapp/config/application.rb:15:5:15:53 | call to allow_forgery_protection= | Potential CSRF vulnerability due to forgery protection being disabled or weakened. |
+| railsapp/config/application.rb:16:5:16:53 | call to allow_forgery_protection= | Potential CSRF vulnerability due to forgery protection being disabled or weakened. |
| railsapp/config/environments/development.rb:5:3:5:51 | call to allow_forgery_protection= | Potential CSRF vulnerability due to forgery protection being disabled or weakened. |
| railsapp/config/environments/production.rb:5:3:5:51 | call to allow_forgery_protection= | Potential CSRF vulnerability due to forgery protection being disabled or weakened. |
diff --git a/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/application.rb b/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/application.rb
index 49ccf578c5e..02b349a1630 100644
--- a/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/application.rb
+++ b/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/application.rb
@@ -9,7 +9,8 @@ Bundler.require(*Rails.groups)
module Railsapp
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
- config.load_defaults 6.0
+ # This defaults version does NOT enable CSRF protection by default.
+ config.load_defaults 5.1
# BAD: Disabling forgery protection may open the application to CSRF attacks
config.action_controller.allow_forgery_protection = false
From 9ec17e6338c23a8189334c9082a6f9882f7c7027 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Mon, 26 Feb 2024 12:40:40 +0000
Subject: [PATCH 015/497] Shared: Pull out the shared parts of Java's type flow
library into a shared module.
---
shared/typeflow/codeql/typeflow/TypeFlow.qll | 118 +++++
.../codeql/typeflow/internal/TypeFlowImpl.qll | 445 ++++++++++++++++++
shared/typeflow/qlpack.yml | 7 +
3 files changed, 570 insertions(+)
create mode 100644 shared/typeflow/codeql/typeflow/TypeFlow.qll
create mode 100644 shared/typeflow/codeql/typeflow/internal/TypeFlowImpl.qll
create mode 100644 shared/typeflow/qlpack.yml
diff --git a/shared/typeflow/codeql/typeflow/TypeFlow.qll b/shared/typeflow/codeql/typeflow/TypeFlow.qll
new file mode 100644
index 00000000000..5df8e53a914
--- /dev/null
+++ b/shared/typeflow/codeql/typeflow/TypeFlow.qll
@@ -0,0 +1,118 @@
+/**
+ * Provides predicates for giving improved type bounds on expressions.
+ *
+ * An inferred bound on the runtime type of an expression can be either exact
+ * or merely an upper bound. Bounds are only reported if they are likely to be
+ * better than the static bound, which can happen either if an inferred exact
+ * type has a subtype or if an inferred upper bound passed through at least one
+ * explicit or implicit cast that lost type information.
+ */
+
+/** Provides the input specification. */
+signature module TypeFlowInput {
+ /**
+ * A node for which type information is available. For example, expressions
+ * and method declarations.
+ */
+ class TypeFlowNode {
+ /** Gets a textual representation of this node. */
+ string toString();
+
+ /** Gets the type of this node. */
+ Type getType();
+
+ /**
+ * Holds if this element is at the specified location.
+ * The location spans column `startcolumn` of line `startline` to
+ * column `endcolumn` of line `endline` in file `filepath`.
+ * For more information, see
+ * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
+ */
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ );
+ }
+
+ /**
+ * Holds if data can flow from `n1` to `n2` in one step, and `n1` is not
+ * necessarily functionally determined by `n2`.
+ */
+ predicate joinStep0(TypeFlowNode n1, TypeFlowNode n2);
+
+ /**
+ * Holds if data can flow from `n1` to `n2` in one step, and `n1` is
+ * functionally determined by `n2`.
+ */
+ predicate step(TypeFlowNode n1, TypeFlowNode n2);
+
+ /**
+ * Holds if `null` is the only value that flows to `n`.
+ */
+ predicate isNull(TypeFlowNode n);
+
+ /** A type. */
+ class Type {
+ /** Gets a textual representation of this type. */
+ string toString();
+
+ /** Gets a direct super type of this type. */
+ Type getASupertype();
+ }
+
+ /**
+ * Gets the source declaration of this type, or `t` if `t` is already a
+ * source declaration.
+ */
+ default Type getSourceDeclaration(Type t) { result = t }
+
+ /**
+ * Gets the erased version of this type. The erasure of a erasure of a
+ * parameterized type is its generic counterpart, or `t` if `t` is already
+ * fully erased.
+ */
+ default Type getErasure(Type t) { result = t }
+
+ /** Gets a direct or indirect supertype of this type, including itself. */
+ default Type getAnAncestor(Type sub) {
+ result = sub
+ or
+ exists(Type mid | result = mid.getASupertype() and sub = getAnAncestor(mid))
+ }
+
+ /**
+ * Holds if `t` is the most precise type of `n`, if any.
+ */
+ predicate exactTypeBase(TypeFlowNode n, Type t);
+
+ /**
+ * Holds if `n` has type `t` and this information is discarded, such that `t`
+ * might be a better type bound for nodes where `n` flows to. This might include
+ * multiple bounds for a single node.
+ */
+ predicate typeFlowBaseCand(TypeFlowNode n, Type t);
+
+ /**
+ * Holds if `n` is a value that is guarded by a disjunction of a dynamic type
+ * check that checks if `n` is an instance of type `t_i` where `t` is one of
+ * those `t_i`.
+ */
+ default predicate instanceofDisjunctionGuarded(TypeFlowNode n, Type t) { none() }
+
+ /**
+ * Holds if `t` is a raw type or parameterised type with unrestricted type
+ * arguments.
+ *
+ * By default, no types are unbound.
+ */
+ default predicate unbound(Type t) { none() }
+}
+
+private import internal.TypeFlowImpl as Impl
+
+/**
+ * Provides an implementation of type-flow using input `I`.
+ */
+cached
+module Make {
+ import Impl::TypeFlow
+}
diff --git a/shared/typeflow/codeql/typeflow/internal/TypeFlowImpl.qll b/shared/typeflow/codeql/typeflow/internal/TypeFlowImpl.qll
new file mode 100644
index 00000000000..121bc605dbc
--- /dev/null
+++ b/shared/typeflow/codeql/typeflow/internal/TypeFlowImpl.qll
@@ -0,0 +1,445 @@
+private import codeql.typeflow.TypeFlow
+private import codeql.util.Unit
+
+module TypeFlow {
+ private import I
+
+ /**
+ * Holds if data can flow from `n1` to `n2` in one step, `n1` is not necessarily
+ * functionally determined by `n2`, and `n1` might take a non-null value.
+ */
+ predicate joinStep(TypeFlowNode n1, TypeFlowNode n2) { joinStep0(n1, n2) and not isNull(n1) }
+
+ private predicate anyStep(TypeFlowNode n1, TypeFlowNode n2) { joinStep(n1, n2) or step(n1, n2) }
+
+ private predicate sccEdge(TypeFlowNode n1, TypeFlowNode n2) {
+ anyStep(n1, n2) and anyStep+(n2, n1)
+ }
+
+ private module Scc = QlBuiltins::EquivalenceRelation;
+
+ private class TypeFlowScc = Scc::EquivalenceClass;
+
+ /** Holds if `n` is part of an SCC of size 2 or more represented by `scc`. */
+ private predicate sccRepr(TypeFlowNode n, TypeFlowScc scc) { scc = Scc::getEquivalenceClass(n) }
+
+ private predicate sccJoinStep(TypeFlowNode n, TypeFlowScc scc) {
+ exists(TypeFlowNode mid |
+ joinStep(n, mid) and
+ sccRepr(mid, scc) and
+ not sccRepr(n, scc)
+ )
+ }
+
+ private signature class NodeSig;
+
+ private signature module Edge {
+ class Node;
+
+ predicate edge(TypeFlowNode n1, Node n2);
+ }
+
+ private signature module RankedEdge {
+ predicate edgeRank(int r, TypeFlowNode n1, Node n2);
+
+ int lastRank(Node n);
+ }
+
+ private module RankEdge implements RankedEdge {
+ private import E
+
+ /**
+ * Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. The used
+ * ordering is not necessarily total, so the ranking may have gaps.
+ */
+ private predicate edgeRank1(int r, TypeFlowNode n1, Node n2) {
+ n1 =
+ rank[r](TypeFlowNode n, int startline, int startcolumn |
+ edge(n, n2) and
+ n.hasLocationInfo(_, startline, startcolumn, _, _)
+ |
+ n order by startline, startcolumn
+ )
+ }
+
+ /**
+ * Holds if `r2` is a ranking of the ranks from `edgeRank1`. This removes the
+ * gaps from the ranking.
+ */
+ private predicate edgeRank2(int r2, int r1, Node n) {
+ r1 = rank[r2](int r | edgeRank1(r, _, n) | r)
+ }
+
+ /** Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. */
+ predicate edgeRank(int r, TypeFlowNode n1, Node n2) {
+ exists(int r1 |
+ edgeRank1(r1, n1, n2) and
+ edgeRank2(r, r1, n2)
+ )
+ }
+
+ int lastRank(Node n) { result = max(int r | edgeRank(r, _, n)) }
+ }
+
+ private signature module TypePropagation {
+ class Typ;
+
+ predicate candType(TypeFlowNode n, Typ t);
+
+ bindingset[t]
+ predicate supportsType(TypeFlowNode n, Typ t);
+ }
+
+ /** Implements recursion through `forall` by way of edge ranking. */
+ private module ForAll E, TypePropagation T> {
+ /**
+ * Holds if `t` is a bound that holds on one of the incoming edges to `n` and
+ * thus is a candidate bound for `n`.
+ */
+ pragma[nomagic]
+ private predicate candJoinType(Node n, T::Typ t) {
+ exists(TypeFlowNode mid |
+ T::candType(mid, t) and
+ E::edgeRank(_, mid, n)
+ )
+ }
+
+ /**
+ * Holds if `t` is a candidate bound for `n` that is also valid for data coming
+ * through the edges into `n` ranked from `1` to `r`.
+ */
+ private predicate flowJoin(int r, Node n, T::Typ t) {
+ (
+ r = 1 and candJoinType(n, t)
+ or
+ flowJoin(r - 1, n, t) and E::edgeRank(r, _, n)
+ ) and
+ forall(TypeFlowNode mid | E::edgeRank(r, mid, n) | T::supportsType(mid, t))
+ }
+
+ /**
+ * Holds if `t` is a candidate bound for `n` that is also valid for data
+ * coming through all the incoming edges, and therefore is a valid bound for
+ * `n`.
+ */
+ predicate flowJoin(Node n, T::Typ t) { flowJoin(E::lastRank(n), n, t) }
+ }
+
+ private module JoinStep implements Edge {
+ class Node = TypeFlowNode;
+
+ predicate edge = joinStep/2;
+ }
+
+ private module SccJoinStep implements Edge {
+ class Node = TypeFlowScc;
+
+ predicate edge = sccJoinStep/2;
+ }
+
+ private module RankedJoinStep = RankEdge;
+
+ private module RankedSccJoinStep = RankEdge;
+
+ private module ExactTypePropagation implements TypePropagation {
+ class Typ = Type;
+
+ predicate candType = exactType/2;
+
+ predicate supportsType = exactType/2;
+ }
+
+ /**
+ * Holds if the runtime type of `n` is exactly `t` and if this bound is a
+ * non-trivial lower bound, that is, `t` has a subtype.
+ */
+ private predicate exactType(TypeFlowNode n, Type t) {
+ exactTypeBase(n, t)
+ or
+ exists(TypeFlowNode mid | exactType(mid, t) and step(mid, n))
+ or
+ // The following is an optimized version of
+ // `forex(TypeFlowNode mid | joinStep(mid, n) | exactType(mid, t))`
+ ForAll::flowJoin(n, t)
+ or
+ exists(TypeFlowScc scc |
+ sccRepr(n, scc) and
+ // Optimized version of
+ // `forex(TypeFlowNode mid | sccJoinStep(mid, scc) | exactType(mid, t))`
+ ForAll::flowJoin(scc, t)
+ )
+ }
+
+ /**
+ * Gets the source declaration of a direct supertype of this type, excluding itself.
+ */
+ private Type getASourceSupertype(Type t) {
+ result = getSourceDeclaration(t.getASupertype()) and
+ result != t
+ }
+
+ /**
+ * Holds if `n` has type `t` and this information is discarded, such that `t`
+ * might be a better type bound for nodes where `n` flows to. This only includes
+ * the best such bound for each node.
+ */
+ private predicate typeFlowBase(TypeFlowNode n, Type t) {
+ exists(Type te |
+ typeFlowBaseCand(n, t) and
+ te = getErasure(t) and
+ not exists(Type better |
+ typeFlowBaseCand(n, better) and
+ better != t and
+ not t.getASupertype+() = better
+ |
+ better.getASupertype+() = t or
+ getASourceSupertype+(getErasure(better)) = te
+ )
+ )
+ }
+
+ private module TypeFlowPropagation implements TypePropagation {
+ class Typ = Type;
+
+ predicate candType = typeFlow/2;
+
+ bindingset[t]
+ predicate supportsType(TypeFlowNode mid, Type t) {
+ exists(Type midtyp | exactType(mid, midtyp) or typeFlow(mid, midtyp) |
+ getAnAncestor(pragma[only_bind_out](midtyp)) = t
+ )
+ }
+ }
+
+ /**
+ * Holds if the runtime type of `n` is bounded by `t` and if this bound is
+ * likely to be better than the static type of `n`.
+ */
+ private predicate typeFlow(TypeFlowNode n, Type t) {
+ typeFlowBase(n, t)
+ or
+ exists(TypeFlowNode mid | typeFlow(mid, t) and step(mid, n))
+ or
+ ForAll::flowJoin(n, t)
+ or
+ exists(TypeFlowScc scc |
+ sccRepr(n, scc) and
+ ForAll::flowJoin(scc, t)
+ )
+ }
+
+ pragma[nomagic]
+ private predicate erasedTypeBound(Type t) {
+ exists(Type t0 | typeFlow(_, t0) and t = getErasure(t0))
+ }
+
+ pragma[nomagic]
+ private predicate typeBound(Type t) { typeFlow(_, t) }
+
+ /**
+ * Gets a direct or indirect supertype of this type.
+ * This does not include itself, unless this type is part of a cycle
+ * in the type hierarchy.
+ */
+ Type getAStrictAncestor(Type sub) { result = getAnAncestor(sub.getASupertype()) }
+
+ /**
+ * Holds if we have a bound for `n` that is better than `t`.
+ */
+ pragma[nomagic]
+ private predicate irrelevantBound(TypeFlowNode n, Type t) {
+ exists(Type bound |
+ typeFlow(n, bound) and
+ t = getAStrictAncestor(bound) and
+ typeBound(t) and
+ typeFlow(n, pragma[only_bind_into](t)) and
+ not getAnAncestor(t) = bound
+ or
+ n.getType() = pragma[only_bind_into](bound) and
+ typeFlow(n, t) and
+ t = getAnAncestor(bound)
+ )
+ }
+
+ /**
+ * Holds if we have a bound for `n` that is better than `t`, taking only erased
+ * types into account.
+ */
+ pragma[nomagic]
+ private predicate irrelevantErasedBound(TypeFlowNode n, Type t) {
+ exists(Type bound |
+ typeFlow(n, bound)
+ or
+ n.getType() = bound and typeFlow(n, _)
+ |
+ t = getASourceSupertype+(getErasure(bound)) and
+ erasedTypeBound(t)
+ )
+ }
+
+ /**
+ * Holds if the runtime type of `n` is bounded by `t`, if this bound is likely
+ * to be better than the static type of `n`, and if this the best such bound.
+ */
+ private predicate bestTypeFlow(TypeFlowNode n, Type t) {
+ typeFlow(n, t) and
+ not irrelevantErasedBound(n, getErasure(t)) and
+ not irrelevantBound(n, t)
+ }
+
+ predicate bestTypeFlow(TypeFlowNode n, Type t, boolean exact) {
+ exactType(n, t) and exact = true
+ or
+ not exactType(n, _) and bestTypeFlow(n, t) and exact = false
+ }
+
+ private predicate bestTypeFlowOrTypeFlowBase(TypeFlowNode n, Type t, boolean exact) {
+ bestTypeFlow(n, t, exact)
+ or
+ typeFlowBase(n, t) and
+ exact = false and
+ not bestTypeFlow(n, _, _)
+ }
+
+ /**
+ * Holds if `n` has type `t` and this information is not propagated as a
+ * universal bound to a subsequent node, such that `t` might form the basis for
+ * a union type bound for that node.
+ */
+ private predicate unionTypeFlowBaseCand(TypeFlowNode n, Type t, boolean exact) {
+ exists(TypeFlowNode next |
+ joinStep(n, next) and
+ bestTypeFlowOrTypeFlowBase(n, t, exact) and
+ not bestTypeFlowOrTypeFlowBase(next, t, exact) and
+ not exactType(next, _)
+ )
+ }
+
+ private module HasUnionTypePropagation implements TypePropagation {
+ class Typ = Unit;
+
+ predicate candType(TypeFlowNode mid, Unit unit) {
+ exists(unit) and
+ (unionTypeFlowBaseCand(mid, _, _) or hasUnionTypeFlow(mid))
+ }
+
+ predicate supportsType = candType/2;
+ }
+
+ /**
+ * Holds if all incoming type flow can be traced back to a
+ * `unionTypeFlowBaseCand`, such that we can compute a union type bound for `n`.
+ * Disregards nodes for which we have an exact bound.
+ */
+ private predicate hasUnionTypeFlow(TypeFlowNode n) {
+ not exactType(n, _) and
+ (
+ // Optimized version of
+ // `forex(TypeFlowNode mid | joinStep(mid, n) | unionTypeFlowBaseCand(mid, _, _) or hasUnionTypeFlow(mid))`
+ ForAll::flowJoin(n, _)
+ or
+ exists(TypeFlowScc scc |
+ sccRepr(n, scc) and
+ // Optimized version of
+ // `forex(TypeFlowNode mid | sccJoinStep(mid, scc) | unionTypeFlowBaseCand(mid, _, _) or hasUnionTypeFlow(mid))`
+ ForAll::flowJoin(scc, _)
+ )
+ or
+ exists(TypeFlowNode mid | step(mid, n) and hasUnionTypeFlow(mid))
+ or
+ instanceofDisjunctionGuarded(n, _)
+ )
+ }
+
+ pragma[nomagic]
+ private Type getTypeBound(TypeFlowNode n) {
+ bestTypeFlow(n, result)
+ or
+ not bestTypeFlow(n, _) and result = n.getType()
+ }
+
+ pragma[nomagic]
+ private predicate unionTypeFlow0(TypeFlowNode n, Type t, boolean exact) {
+ hasUnionTypeFlow(n) and
+ (
+ exists(TypeFlowNode mid | anyStep(mid, n) |
+ unionTypeFlowBaseCand(mid, t, exact) or unionTypeFlow(mid, t, exact)
+ )
+ or
+ instanceofDisjunctionGuarded(n, t) and exact = false
+ )
+ }
+
+ /**
+ * Holds if there is a common (reflexive, transitive) subtype of the erased
+ * types `t1` and `t2`.
+ */
+ private predicate erasedHaveIntersection(Type t1, Type t2) {
+ exists(Type commonSub | commonSub = getSourceDeclaration(commonSub) |
+ getASourceSupertype*(commonSub) = t1 and
+ getASourceSupertype*(commonSub) = t2
+ ) and
+ t1 = getErasure(_) and
+ t2 = getErasure(_)
+ }
+
+ /** Holds if we have a union type bound for `n` and `t` is one of its parts. */
+ private predicate unionTypeFlow(TypeFlowNode n, Type t, boolean exact) {
+ unionTypeFlow0(n, t, exact) and
+ // filter impossible union parts:
+ exists(Type tErased, Type boundErased |
+ pragma[only_bind_into](tErased) = getErasure(t) and
+ pragma[only_bind_into](boundErased) = getErasure(getTypeBound(n))
+ |
+ if exact = true
+ then getASourceSupertype*(tErased) = boundErased
+ else erasedHaveIntersection(tErased, boundErased)
+ )
+ }
+
+ /**
+ * Holds if the inferred union type bound for `n` contains the best universal
+ * bound and thus is irrelevant.
+ */
+ private predicate irrelevantUnionType(TypeFlowNode n) {
+ exists(Type t, Type nt, Type te, Type nte |
+ unionTypeFlow(n, t, false) and
+ nt = getTypeBound(n) and
+ te = getErasure(t) and
+ nte = getErasure(nt)
+ |
+ nt.getASupertype*() = t
+ or
+ getASourceSupertype+(nte) = te
+ or
+ nte = te and unbound(t)
+ )
+ }
+
+ /**
+ * Holds if `t` is an irrelevant part of the union type bound for `n` due to
+ * being contained in another part of the union type bound.
+ */
+ private predicate irrelevantUnionTypePart(TypeFlowNode n, Type t, boolean exact) {
+ unionTypeFlow(n, t, exact) and
+ not irrelevantUnionType(n) and
+ exists(Type weaker |
+ unionTypeFlow(n, weaker, false) and
+ t.getASupertype*() = weaker
+ |
+ exact = true or not weaker.getASupertype*() = t
+ )
+ }
+
+ /**
+ * Holds if the runtime type of `n` is bounded by a union type and if this
+ * bound is likely to be better than the static type of `n`. The union type is
+ * made up of the types `t` related to `n` by this predicate, and the flag
+ * `exact` indicates whether `t` is an exact bound or merely an upper bound.
+ */
+ predicate bestUnionType(TypeFlowNode n, Type t, boolean exact) {
+ unionTypeFlow(n, t, exact) and
+ not irrelevantUnionType(n) and
+ not irrelevantUnionTypePart(n, t, exact)
+ }
+}
diff --git a/shared/typeflow/qlpack.yml b/shared/typeflow/qlpack.yml
new file mode 100644
index 00000000000..6bc23bcd4fc
--- /dev/null
+++ b/shared/typeflow/qlpack.yml
@@ -0,0 +1,7 @@
+name: codeql/typeflow
+version: 0.0.1-dev
+groups: shared
+library: true
+dependencies:
+ codeql/util: ${workspace}
+warnOnImplicitThis: true
\ No newline at end of file
From 1d4c889ab87d4a1094b1c912e4e865d6805e089d Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Mon, 26 Feb 2024 12:40:56 +0000
Subject: [PATCH 016/497] Java: Use the shared type-flow library.
---
java/ql/lib/qlpack.yml | 1 +
.../semmle/code/java/dataflow/TypeFlow.qll | 1003 +++++------------
2 files changed, 307 insertions(+), 697 deletions(-)
diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml
index 15b4982d41e..82701ce6066 100644
--- a/java/ql/lib/qlpack.yml
+++ b/java/ql/lib/qlpack.yml
@@ -13,6 +13,7 @@ dependencies:
codeql/threat-models: ${workspace}
codeql/tutorial: ${workspace}
codeql/typetracking: ${workspace}
+ codeql/typeflow: ${workspace}
codeql/util: ${workspace}
dataExtensions:
- ext/*.model.yml
diff --git a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll
index ea0df55d60f..9a29809f15c 100644
--- a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll
@@ -8,747 +8,356 @@
* explicit or implicit cast that lost type information.
*/
-import java
+import java as J
private import semmle.code.java.dispatch.VirtualDispatch
private import semmle.code.java.dataflow.internal.BaseSSA
private import semmle.code.java.controlflow.Guards
+private import codeql.typeflow.TypeFlow
-private newtype TTypeFlowNode =
- TField(Field f) { not f.getType() instanceof PrimitiveType } or
- TSsa(BaseSsaVariable ssa) { not ssa.getSourceVariable().getType() instanceof PrimitiveType } or
- TExpr(Expr e) or
- TMethod(Method m) { not m.getReturnType() instanceof PrimitiveType }
+private module Input implements TypeFlowInput {
+ private newtype TTypeFlowNode =
+ TField(Field f) { not f.getType() instanceof PrimitiveType } or
+ TSsa(BaseSsaVariable ssa) { not ssa.getSourceVariable().getType() instanceof PrimitiveType } or
+ TExpr(Expr e) or
+ TMethod(Method m) { not m.getReturnType() instanceof PrimitiveType }
-/**
- * A `Field`, `BaseSsaVariable`, `Expr`, or `Method`.
- */
-private class TypeFlowNode extends TTypeFlowNode {
- string toString() {
- result = this.asField().toString() or
- result = this.asSsa().toString() or
- result = this.asExpr().toString() or
- result = this.asMethod().toString()
- }
-
- Location getLocation() {
- result = this.asField().getLocation() or
- result = this.asSsa().getLocation() or
- result = this.asExpr().getLocation() or
- result = this.asMethod().getLocation()
- }
-
- Field asField() { this = TField(result) }
-
- BaseSsaVariable asSsa() { this = TSsa(result) }
-
- Expr asExpr() { this = TExpr(result) }
-
- Method asMethod() { this = TMethod(result) }
-
- RefType getType() {
- result = this.asField().getType() or
- result = this.asSsa().getSourceVariable().getType() or
- result = boxIfNeeded(this.asExpr().getType()) or
- result = this.asMethod().getReturnType()
- }
-}
-
-/** Gets `t` if it is a `RefType` or the boxed type if `t` is a primitive type. */
-private RefType boxIfNeeded(Type t) {
- t.(PrimitiveType).getBoxedType() = result or
- result = t
-}
-
-/**
- * Holds if `arg` is an argument for the parameter `p` in a private callable.
- */
-private predicate privateParamArg(Parameter p, Argument arg) {
- p.getAnArgument() = arg and
- p.getCallable().isPrivate()
-}
-
-/**
- * Holds if data can flow from `n1` to `n2` in one step, and `n1` is not
- * necessarily functionally determined by `n2`.
- */
-private predicate joinStep0(TypeFlowNode n1, TypeFlowNode n2) {
- n2.asExpr().(ChooseExpr).getAResultExpr() = n1.asExpr()
- or
- exists(Field f, Expr e |
- f = n2.asField() and
- f.getAnAssignedValue() = e and
- e = n1.asExpr() and
- not e.(FieldAccess).getField() = f
- )
- or
- n2.asSsa().(BaseSsaPhiNode).getAnUltimateLocalDefinition() = n1.asSsa()
- or
- exists(ReturnStmt ret |
- n2.asMethod() = ret.getEnclosingCallable() and ret.getResult() = n1.asExpr()
- )
- or
- viableImpl_v1(n2.asExpr()) = n1.asMethod()
- or
- exists(Argument arg, Parameter p |
- privateParamArg(p, arg) and
- n1.asExpr() = arg and
- n2.asSsa().(BaseSsaImplicitInit).isParameterDefinition(p) and
- // skip trivial recursion
- not arg = n2.asSsa().getAUse()
- )
-}
-
-/**
- * Holds if data can flow from `n1` to `n2` in one step, and `n1` is
- * functionally determined by `n2`.
- */
-private predicate step(TypeFlowNode n1, TypeFlowNode n2) {
- n2.asExpr() = n1.asField().getAnAccess()
- or
- n2.asExpr() = n1.asSsa().getAUse()
- or
- n2.asExpr().(CastingExpr).getExpr() = n1.asExpr() and
- not n2.asExpr().getType() instanceof PrimitiveType
- or
- n2.asExpr().(AssignExpr).getSource() = n1.asExpr() and
- not n2.asExpr().getType() instanceof PrimitiveType
- or
- n2.asSsa().(BaseSsaUpdate).getDefiningExpr().(VariableAssign).getSource() = n1.asExpr()
- or
- n2.asSsa().(BaseSsaImplicitInit).captures(n1.asSsa())
-}
-
-/**
- * Holds if `null` is the only value that flows to `n`.
- */
-private predicate isNull(TypeFlowNode n) {
- n.asExpr() instanceof NullLiteral
- or
- exists(LocalVariableDeclExpr decl |
- n.asSsa().(BaseSsaUpdate).getDefiningExpr() = decl and
- not decl.hasImplicitInit() and
- not exists(decl.getInit())
- )
- or
- exists(TypeFlowNode mid | isNull(mid) and step(mid, n))
- or
- forex(TypeFlowNode mid | joinStep0(mid, n) | isNull(mid)) and
- // Fields that are never assigned a non-null value are probably set by
- // reflection and are thus not always null.
- not exists(n.asField())
-}
-
-/**
- * Holds if data can flow from `n1` to `n2` in one step, `n1` is not necessarily
- * functionally determined by `n2`, and `n1` might take a non-null value.
- */
-private predicate joinStep(TypeFlowNode n1, TypeFlowNode n2) {
- joinStep0(n1, n2) and not isNull(n1)
-}
-
-private predicate anyStep(TypeFlowNode n1, TypeFlowNode n2) { joinStep(n1, n2) or step(n1, n2) }
-
-private predicate sccEdge(TypeFlowNode n1, TypeFlowNode n2) { anyStep(n1, n2) and anyStep+(n2, n1) }
-
-private module Scc = QlBuiltins::EquivalenceRelation;
-
-private class TypeFlowScc = Scc::EquivalenceClass;
-
-/** Holds if `n` is part of an SCC of size 2 or more represented by `scc`. */
-private predicate sccRepr(TypeFlowNode n, TypeFlowScc scc) { scc = Scc::getEquivalenceClass(n) }
-
-private predicate sccJoinStep(TypeFlowNode n, TypeFlowScc scc) {
- exists(TypeFlowNode mid |
- joinStep(n, mid) and
- sccRepr(mid, scc) and
- not sccRepr(n, scc)
- )
-}
-
-private signature class NodeSig;
-
-private signature module Edge {
- class Node;
-
- predicate edge(TypeFlowNode n1, Node n2);
-}
-
-private signature module RankedEdge {
- predicate edgeRank(int r, TypeFlowNode n1, Node n2);
-
- int lastRank(Node n);
-}
-
-private module RankEdge implements RankedEdge {
- private import E
-
- /**
- * Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. The used
- * ordering is not necessarily total, so the ranking may have gaps.
- */
- private predicate edgeRank1(int r, TypeFlowNode n1, Node n2) {
- n1 =
- rank[r](TypeFlowNode n |
- edge(n, n2)
- |
- n order by n.getLocation().getStartLine(), n.getLocation().getStartColumn()
- )
+ /** Gets `t` if it is a `RefType` or the boxed type if `t` is a primitive type. */
+ private RefType boxIfNeeded(J::Type t) {
+ t.(J::PrimitiveType).getBoxedType() = result or
+ result = t
}
/**
- * Holds if `r2` is a ranking of the ranks from `edgeRank1`. This removes the
- * gaps from the ranking.
+ * A `Field`, `BaseSsaVariable`, `Expr`, or `Method`.
*/
- private predicate edgeRank2(int r2, int r1, Node n) {
- r1 = rank[r2](int r | edgeRank1(r, _, n) | r)
+ class TypeFlowNode extends TTypeFlowNode {
+ string toString() {
+ result = this.asField().toString() or
+ result = this.asSsa().toString() or
+ result = this.asExpr().toString() or
+ result = this.asMethod().toString()
+ }
+
+ predicate hasLocationInfo(
+ string filepath, int startline, int startcolumn, int endline, int endcolumn
+ ) {
+ this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
+ }
+
+ Location getLocation() {
+ result = this.asField().getLocation() or
+ result = this.asSsa().getLocation() or
+ result = this.asExpr().getLocation() or
+ result = this.asMethod().getLocation()
+ }
+
+ Field asField() { this = TField(result) }
+
+ BaseSsaVariable asSsa() { this = TSsa(result) }
+
+ Expr asExpr() { this = TExpr(result) }
+
+ Method asMethod() { this = TMethod(result) }
+
+ RefType getType() {
+ result = this.asField().getType() or
+ result = this.asSsa().getSourceVariable().getType() or
+ result = boxIfNeeded(this.asExpr().getType()) or
+ result = this.asMethod().getReturnType()
+ }
}
- /** Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. */
- predicate edgeRank(int r, TypeFlowNode n1, Node n2) {
- exists(int r1 |
- edgeRank1(r1, n1, n2) and
- edgeRank2(r, r1, n2)
+ class Type = J::RefType;
+
+ /**
+ * Holds if `arg` is an argument for the parameter `p` in a private callable.
+ */
+ private predicate privateParamArg(Parameter p, Argument arg) {
+ p.getAnArgument() = arg and
+ p.getCallable().isPrivate()
+ }
+
+ /**
+ * Holds if data can flow from `n1` to `n2` in one step, and `n1` is not
+ * necessarily functionally determined by `n2`.
+ */
+ predicate joinStep0(TypeFlowNode n1, TypeFlowNode n2) {
+ n2.asExpr().(ChooseExpr).getAResultExpr() = n1.asExpr()
+ or
+ exists(Field f, Expr e |
+ f = n2.asField() and
+ f.getAnAssignedValue() = e and
+ e = n1.asExpr() and
+ not e.(FieldAccess).getField() = f
+ )
+ or
+ n2.asSsa().(BaseSsaPhiNode).getAnUltimateLocalDefinition() = n1.asSsa()
+ or
+ exists(ReturnStmt ret |
+ n2.asMethod() = ret.getEnclosingCallable() and ret.getResult() = n1.asExpr()
+ )
+ or
+ viableImpl_v1(n2.asExpr()) = n1.asMethod()
+ or
+ exists(Argument arg, Parameter p |
+ privateParamArg(p, arg) and
+ n1.asExpr() = arg and
+ n2.asSsa().(BaseSsaImplicitInit).isParameterDefinition(p) and
+ // skip trivial recursion
+ not arg = n2.asSsa().getAUse()
)
}
- int lastRank(Node n) { result = max(int r | edgeRank(r, _, n)) }
-}
-
-private signature module TypePropagation {
- class Typ;
-
- predicate candType(TypeFlowNode n, Typ t);
-
- bindingset[t]
- predicate supportsType(TypeFlowNode n, Typ t);
-}
-
-/** Implements recursion through `forall` by way of edge ranking. */
-private module ForAll E, TypePropagation T> {
/**
- * Holds if `t` is a bound that holds on one of the incoming edges to `n` and
- * thus is a candidate bound for `n`.
+ * Holds if data can flow from `n1` to `n2` in one step, and `n1` is
+ * functionally determined by `n2`.
+ */
+ predicate step(TypeFlowNode n1, TypeFlowNode n2) {
+ n2.asExpr() = n1.asField().getAnAccess()
+ or
+ n2.asExpr() = n1.asSsa().getAUse()
+ or
+ n2.asExpr().(CastingExpr).getExpr() = n1.asExpr() and
+ not n2.asExpr().getType() instanceof PrimitiveType
+ or
+ n2.asExpr().(AssignExpr).getSource() = n1.asExpr() and
+ not n2.asExpr().getType() instanceof PrimitiveType
+ or
+ n2.asSsa().(BaseSsaUpdate).getDefiningExpr().(VariableAssign).getSource() = n1.asExpr()
+ or
+ n2.asSsa().(BaseSsaImplicitInit).captures(n1.asSsa())
+ }
+
+ /**
+ * Holds if `null` is the only value that flows to `n`.
+ */
+ predicate isNull(TypeFlowNode n) {
+ n.asExpr() instanceof NullLiteral
+ or
+ exists(LocalVariableDeclExpr decl |
+ n.asSsa().(BaseSsaUpdate).getDefiningExpr() = decl and
+ not decl.hasImplicitInit() and
+ not exists(decl.getInit())
+ )
+ or
+ exists(TypeFlowNode mid | isNull(mid) and step(mid, n))
+ or
+ forex(TypeFlowNode mid | joinStep0(mid, n) | isNull(mid)) and
+ // Fields that are never assigned a non-null value are probably set by
+ // reflection and are thus not always null.
+ not exists(n.asField())
+ }
+
+ predicate exactTypeBase(TypeFlowNode n, RefType t) {
+ exists(J::ClassInstanceExpr e |
+ n.asExpr() = e and
+ e.getType() = t and
+ not e instanceof FunctionalExpr and
+ exists(SrcRefType sub | sub.getASourceSupertype() = t.getSourceDeclaration())
+ )
+ }
+
+ /**
+ * Holds if `n` occurs in a position where type information might be discarded;
+ * `t1` is the type of `n`, `t1e` is the erasure of `t1`, `t2` is the type of
+ * the implicit or explicit cast, and `t2e` is the erasure of `t2`.
*/
pragma[nomagic]
- private predicate candJoinType(Node n, T::Typ t) {
- exists(TypeFlowNode mid |
- T::candType(mid, t) and
- E::edgeRank(_, mid, n)
+ private predicate upcastCand(TypeFlowNode n, RefType t1, RefType t1e, RefType t2, RefType t2e) {
+ exists(TypeFlowNode next | step(n, next) or Make::joinStep(n, next) |
+ n.getType() = t1 and
+ next.getType() = t2 and
+ t1.getErasure() = t1e and
+ t2.getErasure() = t2e and
+ t1 != t2
)
}
- /**
- * Holds if `t` is a candidate bound for `n` that is also valid for data coming
- * through the edges into `n` ranked from `1` to `r`.
- */
- private predicate flowJoin(int r, Node n, T::Typ t) {
- (
- r = 1 and candJoinType(n, t)
+ /** Holds if `n` occurs in a position where type information is discarded. */
+ private predicate upcast(TypeFlowNode n, RefType t1) {
+ exists(RefType t1e, RefType t2, RefType t2e | upcastCand(n, t1, t1e, t2, t2e) |
+ t1e.getASourceSupertype+() = t2e
or
- flowJoin(r - 1, n, t) and E::edgeRank(r, _, n)
- ) and
- forall(TypeFlowNode mid | E::edgeRank(r, mid, n) | T::supportsType(mid, t))
+ t1e = t2e and
+ unbound(t2) and
+ not unbound(t1)
+ )
+ }
+
+ /** Gets the element type of an array or subtype of `Iterable`. */
+ private J::Type elementType(RefType t) {
+ result = t.(Array).getComponentType()
+ or
+ exists(ParameterizedType it |
+ it.getSourceDeclaration().hasQualifiedName("java.lang", "Iterable") and
+ result = it.getATypeArgument() and
+ t.extendsOrImplements*(it)
+ )
+ }
+
+ private predicate upcastEnhancedForStmtAux(BaseSsaUpdate v, RefType t, RefType t1, RefType t2) {
+ exists(EnhancedForStmt for |
+ for.getVariable() = v.getDefiningExpr() and
+ v.getSourceVariable().getType().getErasure() = t2 and
+ t = boxIfNeeded(elementType(for.getExpr().getType())) and
+ t.getErasure() = t1
+ )
}
/**
- * Holds if `t` is a candidate bound for `n` that is also valid for data
- * coming through all the incoming edges, and therefore is a valid bound for
- * `n`.
+ * Holds if `v` is the iteration variable of an enhanced for statement, `t` is
+ * the type of the elements being iterated over, and this type is more precise
+ * than the type of `v`.
*/
- predicate flowJoin(Node n, T::Typ t) { flowJoin(E::lastRank(n), n, t) }
-}
+ private predicate upcastEnhancedForStmt(BaseSsaUpdate v, RefType t) {
+ exists(RefType t1, RefType t2 |
+ upcastEnhancedForStmtAux(v, t, t1, t2) and
+ t1.getASourceSupertype+() = t2
+ )
+ }
-private module JoinStep implements Edge {
- class Node = TypeFlowNode;
+ private predicate downcastSuccessorAux(
+ CastingExpr cast, BaseSsaVariable v, RefType t, RefType t1, RefType t2
+ ) {
+ cast.getExpr() = v.getAUse() and
+ t = cast.getType() and
+ t1 = t.getErasure() and
+ t2 = v.getSourceVariable().getType().getErasure()
+ }
- predicate edge = joinStep/2;
-}
+ /**
+ * Holds if `va` is an access to a value that has previously been downcast to `t`.
+ */
+ private predicate downcastSuccessor(VarAccess va, RefType t) {
+ exists(CastingExpr cast, BaseSsaVariable v, RefType t1, RefType t2 |
+ downcastSuccessorAux(pragma[only_bind_into](cast), v, t, t1, t2) and
+ t1.getASourceSupertype+() = t2 and
+ va = v.getAUse() and
+ dominates(cast, va) and
+ dominates(cast.(ControlFlowNode).getANormalSuccessor(), va)
+ )
+ }
-private module SccJoinStep implements Edge {
- class Node = TypeFlowScc;
+ /**
+ * Holds if `va` is an access to a value that is guarded by `instanceof t` or `case e t`.
+ */
+ private predicate typeTestGuarded(VarAccess va, RefType t) {
+ exists(Guard typeTest, BaseSsaVariable v |
+ typeTest.appliesTypeTest(v.getAUse(), t, _) and
+ va = v.getAUse() and
+ guardControls_v1(typeTest, va.getBasicBlock(), true)
+ )
+ }
- predicate edge = sccJoinStep/2;
-}
+ /**
+ * Holds if `aa` is an access to a value that is guarded by `instanceof t` or `case e t`.
+ */
+ private predicate arrayTypeTestGuarded(ArrayAccess aa, RefType t) {
+ exists(Guard typeTest, BaseSsaVariable v1, BaseSsaVariable v2, ArrayAccess aa1 |
+ typeTest.appliesTypeTest(aa1, t, _) and
+ aa1.getArray() = v1.getAUse() and
+ aa1.getIndexExpr() = v2.getAUse() and
+ aa.getArray() = v1.getAUse() and
+ aa.getIndexExpr() = v2.getAUse() and
+ guardControls_v1(typeTest, aa.getBasicBlock(), true)
+ )
+ }
-private module RankedJoinStep = RankEdge;
-
-private module RankedSccJoinStep = RankEdge;
-
-private predicate exactTypeBase(TypeFlowNode n, RefType t) {
- exists(ClassInstanceExpr e |
- n.asExpr() = e and
- e.getType() = t and
- not e instanceof FunctionalExpr and
- exists(SrcRefType sub | sub.getASourceSupertype() = t.getSourceDeclaration())
- )
-}
-
-private module ExactTypePropagation implements TypePropagation {
- class Typ = RefType;
-
- predicate candType = exactType/2;
-
- predicate supportsType = exactType/2;
-}
-
-/**
- * Holds if the runtime type of `n` is exactly `t` and if this bound is a
- * non-trivial lower bound, that is, `t` has a subtype.
- */
-private predicate exactType(TypeFlowNode n, RefType t) {
- exactTypeBase(n, t)
- or
- exists(TypeFlowNode mid | exactType(mid, t) and step(mid, n))
- or
- // The following is an optimized version of
- // `forex(TypeFlowNode mid | joinStep(mid, n) | exactType(mid, t))`
- ForAll::flowJoin(n, t)
- or
- exists(TypeFlowScc scc |
- sccRepr(n, scc) and
- // Optimized version of
- // `forex(TypeFlowNode mid | sccJoinStep(mid, scc) | exactType(mid, t))`
- ForAll::flowJoin(scc, t)
- )
-}
-
-/**
- * Holds if `n` occurs in a position where type information might be discarded;
- * `t1` is the type of `n`, `t1e` is the erasure of `t1`, `t2` is the type of
- * the implicit or explicit cast, and `t2e` is the erasure of `t2`.
- */
-pragma[nomagic]
-private predicate upcastCand(TypeFlowNode n, RefType t1, RefType t1e, RefType t2, RefType t2e) {
- exists(TypeFlowNode next | step(n, next) or joinStep(n, next) |
- n.getType() = t1 and
- next.getType() = t2 and
- t1.getErasure() = t1e and
- t2.getErasure() = t2e and
- t1 != t2
- )
-}
-
-private predicate unconstrained(BoundedType t) {
- t.(Wildcard).isUnconstrained()
- or
- t.getUpperBoundType() instanceof TypeObject and
- not t.(Wildcard).hasLowerBound()
- or
- unconstrained(t.getUpperBoundType())
- or
- unconstrained(t.(Wildcard).getLowerBoundType())
-}
-
-/** Holds if `t` is a raw type or parameterised type with unrestricted type arguments. */
-private predicate unbound(RefType t) {
- t instanceof RawType
- or
- exists(ParameterizedType pt | pt = t |
- forex(RefType arg | arg = pt.getATypeArgument() | unconstrained(arg))
- )
-}
-
-/** Holds if `n` occurs in a position where type information is discarded. */
-private predicate upcast(TypeFlowNode n, RefType t1) {
- exists(RefType t1e, RefType t2, RefType t2e | upcastCand(n, t1, t1e, t2, t2e) |
- t1e.getASourceSupertype+() = t2e
+ /**
+ * Holds if `t` is the type of the `this` value corresponding to the the
+ * `SuperAccess`. As the `SuperAccess` expression has the type of the supertype,
+ * the type `t` is a stronger type bound.
+ */
+ private predicate superAccess(SuperAccess sup, RefType t) {
+ sup.isEnclosingInstanceAccess(t)
or
- t1e = t2e and
- unbound(t2) and
- not unbound(t1)
- )
-}
+ sup.isOwnInstanceAccess() and
+ t = sup.getEnclosingCallable().getDeclaringType()
+ }
-/** Gets the element type of an array or subtype of `Iterable`. */
-private Type elementType(RefType t) {
- result = t.(Array).getComponentType()
- or
- exists(ParameterizedType it |
- it.getSourceDeclaration().hasQualifiedName("java.lang", "Iterable") and
- result = it.getATypeArgument() and
- t.extendsOrImplements*(it)
- )
-}
-
-private predicate upcastEnhancedForStmtAux(BaseSsaUpdate v, RefType t, RefType t1, RefType t2) {
- exists(EnhancedForStmt for |
- for.getVariable() = v.getDefiningExpr() and
- v.getSourceVariable().getType().getErasure() = t2 and
- t = boxIfNeeded(elementType(for.getExpr().getType())) and
- t.getErasure() = t1
- )
-}
-
-/**
- * Holds if `v` is the iteration variable of an enhanced for statement, `t` is
- * the type of the elements being iterated over, and this type is more precise
- * than the type of `v`.
- */
-private predicate upcastEnhancedForStmt(BaseSsaUpdate v, RefType t) {
- exists(RefType t1, RefType t2 |
- upcastEnhancedForStmtAux(v, t, t1, t2) and
- t1.getASourceSupertype+() = t2
- )
-}
-
-private predicate downcastSuccessorAux(
- CastingExpr cast, BaseSsaVariable v, RefType t, RefType t1, RefType t2
-) {
- cast.getExpr() = v.getAUse() and
- t = cast.getType() and
- t1 = t.getErasure() and
- t2 = v.getSourceVariable().getType().getErasure()
-}
-
-/**
- * Holds if `va` is an access to a value that has previously been downcast to `t`.
- */
-private predicate downcastSuccessor(VarAccess va, RefType t) {
- exists(CastingExpr cast, BaseSsaVariable v, RefType t1, RefType t2 |
- downcastSuccessorAux(pragma[only_bind_into](cast), v, t, t1, t2) and
- t1.getASourceSupertype+() = t2 and
- va = v.getAUse() and
- dominates(cast, va) and
- dominates(cast.(ControlFlowNode).getANormalSuccessor(), va)
- )
-}
-
-/**
- * Holds if `va` is an access to a value that is guarded by `instanceof t` or `case e t`.
- */
-private predicate typeTestGuarded(VarAccess va, RefType t) {
- exists(Guard typeTest, BaseSsaVariable v |
- typeTest.appliesTypeTest(v.getAUse(), t, _) and
- va = v.getAUse() and
- guardControls_v1(typeTest, va.getBasicBlock(), true)
- )
-}
-
-/**
- * Holds if `aa` is an access to a value that is guarded by `instanceof t` or `case e t`.
- */
-predicate arrayTypeTestGuarded(ArrayAccess aa, RefType t) {
- exists(Guard typeTest, BaseSsaVariable v1, BaseSsaVariable v2, ArrayAccess aa1 |
- typeTest.appliesTypeTest(aa1, t, _) and
- aa1.getArray() = v1.getAUse() and
- aa1.getIndexExpr() = v2.getAUse() and
- aa.getArray() = v1.getAUse() and
- aa.getIndexExpr() = v2.getAUse() and
- guardControls_v1(typeTest, aa.getBasicBlock(), true)
- )
-}
-
-/**
- * Holds if `t` is the type of the `this` value corresponding to the the
- * `SuperAccess`. As the `SuperAccess` expression has the type of the supertype,
- * the type `t` is a stronger type bound.
- */
-private predicate superAccess(SuperAccess sup, RefType t) {
- sup.isEnclosingInstanceAccess(t)
- or
- sup.isOwnInstanceAccess() and
- t = sup.getEnclosingCallable().getDeclaringType()
-}
-
-/**
- * Holds if `n` has type `t` and this information is discarded, such that `t`
- * might be a better type bound for nodes where `n` flows to. This might include
- * multiple bounds for a single node.
- */
-private predicate typeFlowBaseCand(TypeFlowNode n, RefType t) {
- exists(RefType srctype |
- upcast(n, srctype) or
- upcastEnhancedForStmt(n.asSsa(), srctype) or
- downcastSuccessor(n.asExpr(), srctype) or
- typeTestGuarded(n.asExpr(), srctype) or
- arrayTypeTestGuarded(n.asExpr(), srctype) or
- n.asExpr().(FunctionalExpr).getConstructedType() = srctype or
- superAccess(n.asExpr(), srctype)
- |
- t = srctype.(BoundedType).getAnUltimateUpperBoundType()
- or
- t = srctype and not srctype instanceof BoundedType
- )
-}
-
-/**
- * Holds if `n` has type `t` and this information is discarded, such that `t`
- * might be a better type bound for nodes where `n` flows to. This only includes
- * the best such bound for each node.
- */
-private predicate typeFlowBase(TypeFlowNode n, RefType t) {
- exists(RefType te |
- typeFlowBaseCand(n, t) and
- te = t.getErasure() and
- not exists(RefType better |
- typeFlowBaseCand(n, better) and
- better != t and
- not t.getASupertype+() = better
+ /**
+ * Holds if `n` has type `t` and this information is discarded, such that `t`
+ * might be a better type bound for nodes where `n` flows to. This might include
+ * multiple bounds for a single node.
+ */
+ predicate typeFlowBaseCand(TypeFlowNode n, RefType t) {
+ exists(RefType srctype |
+ upcast(n, srctype) or
+ upcastEnhancedForStmt(n.asSsa(), srctype) or
+ downcastSuccessor(n.asExpr(), srctype) or
+ typeTestGuarded(n.asExpr(), srctype) or
+ arrayTypeTestGuarded(n.asExpr(), srctype) or
+ n.asExpr().(FunctionalExpr).getConstructedType() = srctype or
+ superAccess(n.asExpr(), srctype)
|
- better.getASupertype+() = t or
- better.getErasure().(RefType).getASourceSupertype+() = te
- )
- )
-}
-
-private module TypeFlowPropagation implements TypePropagation {
- class Typ = RefType;
-
- predicate candType = typeFlow/2;
-
- bindingset[t]
- predicate supportsType(TypeFlowNode mid, RefType t) {
- exists(RefType midtyp | exactType(mid, midtyp) or typeFlow(mid, midtyp) |
- pragma[only_bind_out](midtyp).getAnAncestor() = t
+ t = srctype.(BoundedType).getAnUltimateUpperBoundType()
+ or
+ t = srctype and not srctype instanceof BoundedType
)
}
-}
-/**
- * Holds if the runtime type of `n` is bounded by `t` and if this bound is
- * likely to be better than the static type of `n`.
- */
-private predicate typeFlow(TypeFlowNode n, RefType t) {
- typeFlowBase(n, t)
- or
- exists(TypeFlowNode mid | typeFlow(mid, t) and step(mid, n))
- or
- ForAll::flowJoin(n, t)
- or
- exists(TypeFlowScc scc |
- sccRepr(n, scc) and
- ForAll::flowJoin(scc, t)
- )
-}
-
-pragma[nomagic]
-private predicate erasedTypeBound(RefType t) {
- exists(RefType t0 | typeFlow(_, t0) and t = t0.getErasure())
-}
-
-pragma[nomagic]
-private predicate typeBound(RefType t) { typeFlow(_, t) }
-
-/**
- * Holds if we have a bound for `n` that is better than `t`, taking only erased
- * types into account.
- */
-pragma[nomagic]
-private predicate irrelevantErasedBound(TypeFlowNode n, RefType t) {
- exists(RefType bound |
- typeFlow(n, bound)
- or
- n.getType() = bound and typeFlow(n, _)
- |
- t = bound.getErasure().(RefType).getASourceSupertype+() and
- erasedTypeBound(t)
- )
-}
-
-/**
- * Holds if we have a bound for `n` that is better than `t`.
- */
-pragma[nomagic]
-private predicate irrelevantBound(TypeFlowNode n, RefType t) {
- exists(RefType bound |
- typeFlow(n, bound) and
- t = bound.getAStrictAncestor() and
- typeBound(t) and
- typeFlow(n, pragma[only_bind_into](t)) and
- not t.getAnAncestor() = bound
- or
- n.getType() = pragma[only_bind_into](bound) and
- typeFlow(n, t) and
- t = bound.getAnAncestor()
- )
-}
-
-/**
- * Holds if the runtime type of `n` is bounded by `t`, if this bound is likely
- * to be better than the static type of `n`, and if this the best such bound.
- */
-private predicate bestTypeFlow(TypeFlowNode n, RefType t) {
- typeFlow(n, t) and
- not irrelevantErasedBound(n, t.getErasure()) and
- not irrelevantBound(n, t)
-}
-
-private predicate bestTypeFlow(TypeFlowNode n, RefType t, boolean exact) {
- exactType(n, t) and exact = true
- or
- not exactType(n, _) and bestTypeFlow(n, t) and exact = false
-}
-
-private predicate bestTypeFlowOrTypeFlowBase(TypeFlowNode n, RefType t, boolean exact) {
- bestTypeFlow(n, t, exact)
- or
- typeFlowBase(n, t) and
- exact = false and
- not bestTypeFlow(n, _, _)
-}
-
-/**
- * Holds if `n` has type `t` and this information is not propagated as a
- * universal bound to a subsequent node, such that `t` might form the basis for
- * a union type bound for that node.
- */
-private predicate unionTypeFlowBaseCand(TypeFlowNode n, RefType t, boolean exact) {
- exists(TypeFlowNode next |
- joinStep(n, next) and
- bestTypeFlowOrTypeFlowBase(n, t, exact) and
- not bestTypeFlowOrTypeFlowBase(next, t, exact) and
- not exactType(next, _)
- )
-}
-
-/**
- * Holds if `ioe` checks `v`, its true-successor is `bb`, and `bb` has multiple
- * predecessors.
- */
-private predicate instanceofDisjunct(InstanceOfExpr ioe, BasicBlock bb, BaseSsaVariable v) {
- ioe.getExpr() = v.getAUse() and
- strictcount(bb.getABBPredecessor()) > 1 and
- exists(ConditionBlock cb | cb.getCondition() = ioe and cb.getTestSuccessor(true) = bb)
-}
-
-/** Holds if `bb` is disjunctively guarded by multiple `instanceof` tests on `v`. */
-private predicate instanceofDisjunction(BasicBlock bb, BaseSsaVariable v) {
- strictcount(InstanceOfExpr ioe | instanceofDisjunct(ioe, bb, v)) =
- strictcount(bb.getABBPredecessor())
-}
-
-/**
- * Holds if `n` is a value that is guarded by a disjunction of
- * `instanceof t_i` where `t` is one of those `t_i`.
- */
-private predicate instanceofDisjunctionGuarded(TypeFlowNode n, RefType t) {
- exists(BasicBlock bb, InstanceOfExpr ioe, BaseSsaVariable v, VarAccess va |
- instanceofDisjunction(bb, v) and
- bb.bbDominates(va.getBasicBlock()) and
- va = v.getAUse() and
- instanceofDisjunct(ioe, bb, v) and
- t = ioe.getSyntacticCheckedType() and
- n.asExpr() = va
- )
-}
-
-private module HasUnionTypePropagation implements TypePropagation {
- class Typ = Unit;
-
- predicate candType(TypeFlowNode mid, Unit unit) {
- exists(unit) and
- (unionTypeFlowBaseCand(mid, _, _) or hasUnionTypeFlow(mid))
+ /**
+ * Holds if `ioe` checks `v`, its true-successor is `bb`, and `bb` has multiple
+ * predecessors.
+ */
+ private predicate instanceofDisjunct(InstanceOfExpr ioe, BasicBlock bb, BaseSsaVariable v) {
+ ioe.getExpr() = v.getAUse() and
+ strictcount(bb.getABBPredecessor()) > 1 and
+ exists(ConditionBlock cb | cb.getCondition() = ioe and cb.getTestSuccessor(true) = bb)
}
- predicate supportsType = candType/2;
-}
+ /** Holds if `bb` is disjunctively guarded by multiple `instanceof` tests on `v`. */
+ private predicate instanceofDisjunction(BasicBlock bb, BaseSsaVariable v) {
+ strictcount(InstanceOfExpr ioe | instanceofDisjunct(ioe, bb, v)) =
+ strictcount(bb.getABBPredecessor())
+ }
-/**
- * Holds if all incoming type flow can be traced back to a
- * `unionTypeFlowBaseCand`, such that we can compute a union type bound for `n`.
- * Disregards nodes for which we have an exact bound.
- */
-private predicate hasUnionTypeFlow(TypeFlowNode n) {
- not exactType(n, _) and
- (
- // Optimized version of
- // `forex(TypeFlowNode mid | joinStep(mid, n) | unionTypeFlowBaseCand(mid, _, _) or hasUnionTypeFlow(mid))`
- ForAll::flowJoin(n, _)
- or
- exists(TypeFlowScc scc |
- sccRepr(n, scc) and
- // Optimized version of
- // `forex(TypeFlowNode mid | sccJoinStep(mid, scc) | unionTypeFlowBaseCand(mid, _, _) or hasUnionTypeFlow(mid))`
- ForAll::flowJoin(scc, _)
+ /**
+ * Holds if `n` is a value that is guarded by a disjunction of
+ * `instanceof t_i` where `t` is one of those `t_i`.
+ */
+ predicate instanceofDisjunctionGuarded(TypeFlowNode n, RefType t) {
+ exists(BasicBlock bb, InstanceOfExpr ioe, BaseSsaVariable v, VarAccess va |
+ instanceofDisjunction(bb, v) and
+ bb.bbDominates(va.getBasicBlock()) and
+ va = v.getAUse() and
+ instanceofDisjunct(ioe, bb, v) and
+ t = ioe.getSyntacticCheckedType() and
+ n.asExpr() = va
)
- or
- exists(TypeFlowNode mid | step(mid, n) and hasUnionTypeFlow(mid))
- or
- instanceofDisjunctionGuarded(n, _)
- )
-}
+ }
-pragma[nomagic]
-private RefType getTypeBound(TypeFlowNode n) {
- bestTypeFlow(n, result)
- or
- not bestTypeFlow(n, _) and result = n.getType()
-}
+ private predicate unconstrained(BoundedType t) {
+ t.(Wildcard).isUnconstrained()
+ or
+ t.getUpperBoundType() instanceof TypeObject and
+ not t.(Wildcard).hasLowerBound()
+ or
+ unconstrained(t.getUpperBoundType())
+ or
+ unconstrained(t.(Wildcard).getLowerBoundType())
+ }
-pragma[nomagic]
-private predicate unionTypeFlow0(TypeFlowNode n, RefType t, boolean exact) {
- hasUnionTypeFlow(n) and
- (
- exists(TypeFlowNode mid | anyStep(mid, n) |
- unionTypeFlowBaseCand(mid, t, exact) or unionTypeFlow(mid, t, exact)
+ /** Holds if `t` is a raw type or parameterised type with unrestricted type arguments. */
+ predicate unbound(RefType t) {
+ t instanceof RawType
+ or
+ exists(ParameterizedType pt | pt = t |
+ forex(RefType arg | arg = pt.getATypeArgument() | unconstrained(arg))
)
- or
- instanceofDisjunctionGuarded(n, t) and exact = false
- )
-}
+ }
-/** Holds if we have a union type bound for `n` and `t` is one of its parts. */
-private predicate unionTypeFlow(TypeFlowNode n, RefType t, boolean exact) {
- unionTypeFlow0(n, t, exact) and
- // filter impossible union parts:
- exists(RefType tErased, RefType boundErased |
- pragma[only_bind_into](tErased) = t.getErasure() and
- pragma[only_bind_into](boundErased) = getTypeBound(n).getErasure()
- |
- if exact = true
- then tErased.getASourceSupertype*() = boundErased
- else erasedHaveIntersection(tErased, boundErased)
- )
-}
+ Type getErasure(Type t) { result = t.getErasure() }
-/**
- * Holds if the inferred union type bound for `n` contains the best universal
- * bound and thus is irrelevant.
- */
-private predicate irrelevantUnionType(TypeFlowNode n) {
- exists(RefType t, RefType nt, RefType te, RefType nte |
- unionTypeFlow(n, t, false) and
- nt = getTypeBound(n) and
- te = t.getErasure() and
- nte = nt.getErasure()
- |
- nt.getASupertype*() = t
- or
- nte.getASourceSupertype+() = te
- or
- nte = te and unbound(t)
- )
-}
+ Type getAnAncestor(Type sub) { result = sub.getAnAncestor() }
-/**
- * Holds if `t` is an irrelevant part of the union type bound for `n` due to
- * being contained in another part of the union type bound.
- */
-private predicate irrelevantUnionTypePart(TypeFlowNode n, RefType t, boolean exact) {
- unionTypeFlow(n, t, exact) and
- not irrelevantUnionType(n) and
- exists(RefType weaker |
- unionTypeFlow(n, weaker, false) and
- t.getASupertype*() = weaker
- |
- exact = true or not weaker.getASupertype*() = t
- )
-}
-
-/**
- * Holds if the runtime type of `n` is bounded by a union type and if this
- * bound is likely to be better than the static type of `n`. The union type is
- * made up of the types `t` related to `n` by this predicate, and the flag
- * `exact` indicates whether `t` is an exact bound or merely an upper bound.
- */
-private predicate bestUnionType(TypeFlowNode n, RefType t, boolean exact) {
- unionTypeFlow(n, t, exact) and
- not irrelevantUnionType(n) and
- not irrelevantUnionTypePart(n, t, exact)
+ RefType getSourceDeclaration(Type t) { result = t.getSourceDeclaration() }
}
cached
private module TypeFlowBounds {
+ private module TypeFlow = Make;
+
/**
* Holds if the runtime type of `f` is bounded by `t` and if this bound is
* likely to be better than the static type of `f`. The flag `exact` indicates
@@ -756,9 +365,9 @@ private module TypeFlowBounds {
*/
cached
predicate fieldTypeFlow(Field f, RefType t, boolean exact) {
- exists(TypeFlowNode n |
+ exists(Input::TypeFlowNode n |
n.asField() = f and
- bestTypeFlow(n, t, exact)
+ TypeFlow::bestTypeFlow(n, t, exact)
)
}
@@ -769,9 +378,9 @@ private module TypeFlowBounds {
*/
cached
predicate exprTypeFlow(Expr e, RefType t, boolean exact) {
- exists(TypeFlowNode n |
+ exists(Input::TypeFlowNode n |
n.asExpr() = e and
- bestTypeFlow(n, t, exact)
+ TypeFlow::bestTypeFlow(n, t, exact)
)
}
@@ -783,9 +392,9 @@ private module TypeFlowBounds {
*/
cached
predicate exprUnionTypeFlow(Expr e, RefType t, boolean exact) {
- exists(TypeFlowNode n |
+ exists(Input::TypeFlowNode n |
n.asExpr() = e and
- bestUnionType(n, t, exact)
+ TypeFlow::bestUnionType(n, t, exact)
)
}
}
From 690fdc076d2e65b9e238589dbc15f05ad57be3cf Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Mon, 26 Feb 2024 16:21:35 +0000
Subject: [PATCH 017/497] Shared: Add change note.
---
shared/typeflow/change-notes/2024-02-26-initial-version.md | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 shared/typeflow/change-notes/2024-02-26-initial-version.md
diff --git a/shared/typeflow/change-notes/2024-02-26-initial-version.md b/shared/typeflow/change-notes/2024-02-26-initial-version.md
new file mode 100644
index 00000000000..6b3dc344938
--- /dev/null
+++ b/shared/typeflow/change-notes/2024-02-26-initial-version.md
@@ -0,0 +1,4 @@
+---
+category: feature
+---
+* Initial release. Adds a library to implement type-flow analysis.
From 2fd57f6ee771e760d54749e649ceea8f3a8716af Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Wed, 28 Feb 2024 16:24:21 +0000
Subject: [PATCH 018/497] Shared: Remove cached annotation.
---
shared/typeflow/codeql/typeflow/TypeFlow.qll | 1 -
1 file changed, 1 deletion(-)
diff --git a/shared/typeflow/codeql/typeflow/TypeFlow.qll b/shared/typeflow/codeql/typeflow/TypeFlow.qll
index 5df8e53a914..bdf90dab7cf 100644
--- a/shared/typeflow/codeql/typeflow/TypeFlow.qll
+++ b/shared/typeflow/codeql/typeflow/TypeFlow.qll
@@ -112,7 +112,6 @@ private import internal.TypeFlowImpl as Impl
/**
* Provides an implementation of type-flow using input `I`.
*/
-cached
module Make {
import Impl::TypeFlow
}
From 2b2ea597ce384aa1488de9c98ec7bb229ee0aa2c Mon Sep 17 00:00:00 2001
From: Angela P Wen
Date: Mon, 4 Mar 2024 16:42:38 +0000
Subject: [PATCH 019/497] Fix formatting on changenotes
---
ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md | 2 +-
ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md b/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
index 56d2dcf5c73..6f3a90768ba 100644
--- a/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
+++ b/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
@@ -1,4 +1,4 @@
---
category: minorAnalysis
---
-Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
\ No newline at end of file
+* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md b/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
index f08bd54efa2..350e049b5bf 100644
--- a/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
+++ b/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
@@ -1,4 +1,4 @@
---
category: minorAnalysis
---
-Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
\ No newline at end of file
+* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
\ No newline at end of file
From a67218a0277be5516730cf3bdb0fb1932c14b2c1 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Mon, 4 Mar 2024 17:42:08 +0000
Subject: [PATCH 020/497] Release preparation for version 2.16.4
---
cpp/ql/lib/CHANGELOG.md | 6 ++++++
.../0.12.7.md} | 9 +++++----
cpp/ql/lib/codeql-pack.release.yml | 2 +-
cpp/ql/lib/qlpack.yml | 2 +-
cpp/ql/src/CHANGELOG.md | 7 +++++++
.../2024-02-29-non-constant-format-path-query.md | 4 ----
.../0.9.6.md} | 8 +++++---
cpp/ql/src/codeql-pack.release.yml | 2 +-
cpp/ql/src/qlpack.yml | 2 +-
csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md | 4 ++++
.../Solorigate/lib/change-notes/released/1.7.10.md | 3 +++
.../Solorigate/lib/codeql-pack.release.yml | 2 +-
csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +-
csharp/ql/campaigns/Solorigate/src/CHANGELOG.md | 4 ++++
.../Solorigate/src/change-notes/released/1.7.10.md | 3 +++
.../Solorigate/src/codeql-pack.release.yml | 2 +-
csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +-
csharp/ql/lib/CHANGELOG.md | 14 ++++++++++++++
.../change-notes/2024-02-21-getonly-properties.md | 4 ----
.../ql/lib/change-notes/2024-02-22-no-db-stats.md | 4 ----
.../change-notes/2024-02-23-compiler-generated.md | 4 ----
.../2024-02-26-variable-capture-flow.md | 4 ----
.../2024-02-28-experimental-attribute.md | 4 ----
.../2024-02-28-refreadonly-parameter.md | 4 ----
csharp/ql/lib/change-notes/released/0.8.10.md | 13 +++++++++++++
csharp/ql/lib/codeql-pack.release.yml | 2 +-
csharp/ql/lib/qlpack.yml | 2 +-
csharp/ql/src/CHANGELOG.md | 6 ++++++
.../0.8.10.md} | 9 +++++----
csharp/ql/src/codeql-pack.release.yml | 2 +-
csharp/ql/src/qlpack.yml | 2 +-
go/ql/consistency-queries/CHANGELOG.md | 4 ++++
.../change-notes/released/0.0.9.md | 3 +++
go/ql/consistency-queries/codeql-pack.release.yml | 2 +-
go/ql/consistency-queries/qlpack.yml | 2 +-
go/ql/lib/CHANGELOG.md | 11 +++++++++++
.../lib/change-notes/2024-02-14-range-map-read.md | 4 ----
.../0.7.10.md} | 11 ++++++++---
go/ql/lib/codeql-pack.release.yml | 2 +-
go/ql/lib/qlpack.yml | 2 +-
go/ql/src/CHANGELOG.md | 4 ++++
go/ql/src/change-notes/released/0.7.10.md | 3 +++
go/ql/src/codeql-pack.release.yml | 2 +-
go/ql/src/qlpack.yml | 2 +-
java/ql/automodel/src/CHANGELOG.md | 4 ++++
.../automodel/src/change-notes/released/0.0.17.md | 3 +++
java/ql/automodel/src/codeql-pack.release.yml | 2 +-
java/ql/automodel/src/qlpack.yml | 2 +-
java/ql/lib/CHANGELOG.md | 11 +++++++++++
.../change-notes/2024-02-23-widget-flowsteps.md | 4 ----
java/ql/lib/change-notes/2024-02-27-error-types.md | 4 ----
.../lib/change-notes/2024-02-27-mvnw-versions.md | 4 ----
java/ql/lib/change-notes/released/0.8.10.md | 10 ++++++++++
java/ql/lib/codeql-pack.release.yml | 2 +-
java/ql/lib/qlpack.yml | 2 +-
java/ql/src/CHANGELOG.md | 10 ++++++++++
.../2024-02-12-android-insecure-keys.md | 4 ----
.../0.8.10.md} | 11 ++++++++---
java/ql/src/codeql-pack.release.yml | 2 +-
java/ql/src/qlpack.yml | 2 +-
javascript/ql/lib/CHANGELOG.md | 4 ++++
javascript/ql/lib/change-notes/released/0.8.10.md | 3 +++
javascript/ql/lib/codeql-pack.release.yml | 2 +-
javascript/ql/lib/qlpack.yml | 2 +-
javascript/ql/src/CHANGELOG.md | 4 ++++
javascript/ql/src/change-notes/released/0.8.10.md | 3 +++
javascript/ql/src/codeql-pack.release.yml | 2 +-
javascript/ql/src/qlpack.yml | 2 +-
misc/suite-helpers/CHANGELOG.md | 4 ++++
misc/suite-helpers/change-notes/released/0.7.10.md | 3 +++
misc/suite-helpers/codeql-pack.release.yml | 2 +-
misc/suite-helpers/qlpack.yml | 2 +-
python/ql/lib/CHANGELOG.md | 7 +++++++
.../2024-02-28-iterable-unpacking-module-scope.md | 4 ----
.../0.11.10.md} | 8 +++++---
python/ql/lib/codeql-pack.release.yml | 2 +-
python/ql/lib/qlpack.yml | 2 +-
python/ql/src/CHANGELOG.md | 6 ++++++
.../0.9.10.md} | 7 ++++---
python/ql/src/codeql-pack.release.yml | 2 +-
python/ql/src/qlpack.yml | 2 +-
ruby/ql/lib/CHANGELOG.md | 9 +++++++++
...2024-02-15-activerecord_connection_sql_sinks.md | 4 ----
.../2024-02-20-activerecord-sql-sink-arguments.md | 4 ----
.../lib/change-notes/2024-02-26-arel-sqlliteral.md | 4 ----
.../lib/change-notes/2024-02-29-i18n-translate.md | 4 ----
ruby/ql/lib/change-notes/released/0.8.10.md | 8 ++++++++
ruby/ql/lib/codeql-pack.release.yml | 2 +-
ruby/ql/lib/qlpack.yml | 2 +-
ruby/ql/src/CHANGELOG.md | 7 +++++++
.../2024-02-13-rails-more-request-sources.md | 4 ----
.../0.8.10.md} | 10 ++++++----
ruby/ql/src/codeql-pack.release.yml | 2 +-
ruby/ql/src/qlpack.yml | 2 +-
shared/controlflow/CHANGELOG.md | 4 ++++
shared/controlflow/change-notes/released/0.1.10.md | 3 +++
shared/controlflow/codeql-pack.release.yml | 2 +-
shared/controlflow/qlpack.yml | 2 +-
shared/dataflow/CHANGELOG.md | 4 ++++
shared/dataflow/change-notes/released/0.2.1.md | 3 +++
shared/dataflow/codeql-pack.release.yml | 2 +-
shared/dataflow/qlpack.yml | 2 +-
shared/mad/CHANGELOG.md | 4 ++++
shared/mad/change-notes/released/0.2.10.md | 3 +++
shared/mad/codeql-pack.release.yml | 2 +-
shared/mad/qlpack.yml | 2 +-
shared/rangeanalysis/CHANGELOG.md | 4 ++++
.../rangeanalysis/change-notes/released/0.0.9.md | 3 +++
shared/rangeanalysis/codeql-pack.release.yml | 2 +-
shared/rangeanalysis/qlpack.yml | 2 +-
shared/regex/CHANGELOG.md | 4 ++++
shared/regex/change-notes/released/0.2.10.md | 3 +++
shared/regex/codeql-pack.release.yml | 2 +-
shared/regex/qlpack.yml | 2 +-
shared/ssa/CHANGELOG.md | 4 ++++
shared/ssa/change-notes/released/0.2.10.md | 3 +++
shared/ssa/codeql-pack.release.yml | 2 +-
shared/ssa/qlpack.yml | 2 +-
shared/threat-models/CHANGELOG.md | 4 ++++
.../threat-models/change-notes/released/0.0.9.md | 3 +++
shared/threat-models/codeql-pack.release.yml | 2 +-
shared/threat-models/qlpack.yml | 2 +-
shared/tutorial/CHANGELOG.md | 4 ++++
shared/tutorial/change-notes/released/0.2.10.md | 3 +++
shared/tutorial/codeql-pack.release.yml | 2 +-
shared/tutorial/qlpack.yml | 2 +-
shared/typetracking/CHANGELOG.md | 4 ++++
.../typetracking/change-notes/released/0.2.10.md | 3 +++
shared/typetracking/codeql-pack.release.yml | 2 +-
shared/typetracking/qlpack.yml | 2 +-
shared/typos/CHANGELOG.md | 4 ++++
shared/typos/change-notes/released/0.2.10.md | 3 +++
shared/typos/codeql-pack.release.yml | 2 +-
shared/typos/qlpack.yml | 2 +-
shared/util/CHANGELOG.md | 4 ++++
shared/util/change-notes/released/0.2.10.md | 3 +++
shared/util/codeql-pack.release.yml | 2 +-
shared/util/qlpack.yml | 2 +-
shared/yaml/CHANGELOG.md | 4 ++++
shared/yaml/change-notes/released/0.2.10.md | 3 +++
shared/yaml/codeql-pack.release.yml | 2 +-
shared/yaml/qlpack.yml | 2 +-
swift/ql/lib/CHANGELOG.md | 6 ++++++
.../0.3.10.md} | 7 ++++---
swift/ql/lib/codeql-pack.release.yml | 2 +-
swift/ql/lib/qlpack.yml | 2 +-
swift/ql/src/CHANGELOG.md | 4 ++++
swift/ql/src/change-notes/released/0.3.10.md | 3 +++
swift/ql/src/codeql-pack.release.yml | 2 +-
swift/ql/src/qlpack.yml | 2 +-
150 files changed, 394 insertions(+), 168 deletions(-)
rename cpp/ql/lib/change-notes/{2024-02-26-ir-named-destructors.md => released/0.12.7.md} (54%)
delete mode 100644 cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
rename cpp/ql/src/change-notes/{2024-02-16-modelled-functions-block-flow.md => released/0.9.6.md} (77%)
create mode 100644 csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
create mode 100644 csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
create mode 100644 csharp/ql/lib/change-notes/released/0.8.10.md
rename csharp/ql/src/change-notes/{2024-02-06-threat-models.md => released/0.8.10.md} (88%)
create mode 100644 go/ql/consistency-queries/change-notes/released/0.0.9.md
delete mode 100644 go/ql/lib/change-notes/2024-02-14-range-map-read.md
rename go/ql/lib/change-notes/{2024-03-04-autobuilder-changes.md => released/0.7.10.md} (68%)
create mode 100644 go/ql/src/change-notes/released/0.7.10.md
create mode 100644 java/ql/automodel/src/change-notes/released/0.0.17.md
delete mode 100644 java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
delete mode 100644 java/ql/lib/change-notes/2024-02-27-error-types.md
delete mode 100644 java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
create mode 100644 java/ql/lib/change-notes/released/0.8.10.md
delete mode 100644 java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
rename java/ql/src/change-notes/{2024-03-04-sensitive-log-remove-null-from-sources.md => released/0.8.10.md} (54%)
create mode 100644 javascript/ql/lib/change-notes/released/0.8.10.md
create mode 100644 javascript/ql/src/change-notes/released/0.8.10.md
create mode 100644 misc/suite-helpers/change-notes/released/0.7.10.md
delete mode 100644 python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
rename python/ql/lib/change-notes/{2024-03-01-dict-update-content.md => released/0.11.10.md} (52%)
rename python/ql/src/change-notes/{2024-03-04-nosql-injection.md => released/0.9.10.md} (81%)
delete mode 100644 ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
delete mode 100644 ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
delete mode 100644 ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
delete mode 100644 ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
create mode 100644 ruby/ql/lib/change-notes/released/0.8.10.md
delete mode 100644 ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
rename ruby/ql/src/change-notes/{2024-03-01-method-code-injection-sinks.md => released/0.8.10.md} (51%)
create mode 100644 shared/controlflow/change-notes/released/0.1.10.md
create mode 100644 shared/dataflow/change-notes/released/0.2.1.md
create mode 100644 shared/mad/change-notes/released/0.2.10.md
create mode 100644 shared/rangeanalysis/change-notes/released/0.0.9.md
create mode 100644 shared/regex/change-notes/released/0.2.10.md
create mode 100644 shared/ssa/change-notes/released/0.2.10.md
create mode 100644 shared/threat-models/change-notes/released/0.0.9.md
create mode 100644 shared/tutorial/change-notes/released/0.2.10.md
create mode 100644 shared/typetracking/change-notes/released/0.2.10.md
create mode 100644 shared/typos/change-notes/released/0.2.10.md
create mode 100644 shared/util/change-notes/released/0.2.10.md
create mode 100644 shared/yaml/change-notes/released/0.2.10.md
rename swift/ql/lib/change-notes/{2024-02-22-extension-patch.md => released/0.3.10.md} (83%)
create mode 100644 swift/ql/src/change-notes/released/0.3.10.md
diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md
index b3091ec37d8..e1c0dfbecd9 100644
--- a/cpp/ql/lib/CHANGELOG.md
+++ b/cpp/ql/lib/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.12.7
+
+### Minor Analysis Improvements
+
+* Added destructors for named objects to the intermediate representation.
+
## 0.12.6
### New Features
diff --git a/cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md b/cpp/ql/lib/change-notes/released/0.12.7.md
similarity index 54%
rename from cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md
rename to cpp/ql/lib/change-notes/released/0.12.7.md
index 4e35decaf8e..856a8b665c7 100644
--- a/cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md
+++ b/cpp/ql/lib/change-notes/released/0.12.7.md
@@ -1,4 +1,5 @@
----
-category: minorAnalysis
----
-* Added destructors for named objects to the intermediate representation.
\ No newline at end of file
+## 0.12.7
+
+### Minor Analysis Improvements
+
+* Added destructors for named objects to the intermediate representation.
diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml
index 170a312c104..20419e9c610 100644
--- a/cpp/ql/lib/codeql-pack.release.yml
+++ b/cpp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.12.6
+lastReleaseVersion: 0.12.7
diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml
index 8e201fff594..3bb9229bf94 100644
--- a/cpp/ql/lib/qlpack.yml
+++ b/cpp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-all
-version: 0.12.7-dev
+version: 0.12.7
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md
index ffcd73ff5d7..f6acd424bb0 100644
--- a/cpp/ql/src/CHANGELOG.md
+++ b/cpp/ql/src/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.9.6
+
+### Minor Analysis Improvements
+
+* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
+* The new C/C++ dataflow and taint-tracking libraries (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`) now implicitly assume that dataflow and taint modelled via `DataFlowFunction` and `TaintFunction` always fully overwrite their buffers and thus act as flow barriers. As a result, many dataflow and taint-tracking queries now produce fewer false positives. To remove this assumption and go back to the previous behavior for a given model, one can override the new `isPartialWrite` predicate.
+
## 0.9.5
### Minor Analysis Improvements
diff --git a/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md b/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
deleted file mode 100644
index 2e5933a61e8..00000000000
--- a/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
\ No newline at end of file
diff --git a/cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md b/cpp/ql/src/change-notes/released/0.9.6.md
similarity index 77%
rename from cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md
rename to cpp/ql/src/change-notes/released/0.9.6.md
index d6ef3c3e056..0c85f3f9f0f 100644
--- a/cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md
+++ b/cpp/ql/src/change-notes/released/0.9.6.md
@@ -1,4 +1,6 @@
----
-category: minorAnalysis
----
+## 0.9.6
+
+### Minor Analysis Improvements
+
+* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
* The new C/C++ dataflow and taint-tracking libraries (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`) now implicitly assume that dataflow and taint modelled via `DataFlowFunction` and `TaintFunction` always fully overwrite their buffers and thus act as flow barriers. As a result, many dataflow and taint-tracking queries now produce fewer false positives. To remove this assumption and go back to the previous behavior for a given model, one can override the new `isPartialWrite` predicate.
diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml
index 460240feaff..19139c132b2 100644
--- a/cpp/ql/src/codeql-pack.release.yml
+++ b/cpp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.9.5
+lastReleaseVersion: 0.9.6
diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml
index 31bd20166b2..4052647bb97 100644
--- a/cpp/ql/src/qlpack.yml
+++ b/cpp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-queries
-version: 0.9.6-dev
+version: 0.9.6
groups:
- cpp
- queries
diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
index 190b83b0f25..82eacfc84f7 100644
--- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
+++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.7.10
+
+No user-facing changes.
+
## 1.7.9
No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
new file mode 100644
index 00000000000..8e8007d8475
--- /dev/null
+++ b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
@@ -0,0 +1,3 @@
+## 1.7.10
+
+No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
index 678da6bc37e..31c7fe07020 100644
--- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
+++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.7.9
+lastReleaseVersion: 1.7.10
diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
index 7e643b0fac3..ee993bed0c9 100644
--- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
-version: 1.7.10-dev
+version: 1.7.10
groups:
- csharp
- solorigate
diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
index 190b83b0f25..82eacfc84f7 100644
--- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
+++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.7.10
+
+No user-facing changes.
+
## 1.7.9
No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
new file mode 100644
index 00000000000..8e8007d8475
--- /dev/null
+++ b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
@@ -0,0 +1,3 @@
+## 1.7.10
+
+No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
index 678da6bc37e..31c7fe07020 100644
--- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
+++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.7.9
+lastReleaseVersion: 1.7.10
diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
index 8654bbfd031..1f421754fc8 100644
--- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
-version: 1.7.10-dev
+version: 1.7.10
groups:
- csharp
- solorigate
diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md
index 95fd64c5270..16cc14259e1 100644
--- a/csharp/ql/lib/CHANGELOG.md
+++ b/csharp/ql/lib/CHANGELOG.md
@@ -1,3 +1,17 @@
+## 0.8.10
+
+### Major Analysis Improvements
+
+* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
+* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
+
+### Minor Analysis Improvements
+
+* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
+* C# 12: Add extractor and QL library support for `ref readonly` parameters.
+* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
+* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
+
## 0.8.9
### Minor Analysis Improvements
diff --git a/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md b/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
deleted file mode 100644
index 6bb8e99c71e..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
diff --git a/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md b/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
deleted file mode 100644
index d6ffbd523ac..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: majorAnalysis
----
-* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
diff --git a/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md b/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
deleted file mode 100644
index 9b1739b9b6d..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
diff --git a/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md b/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
deleted file mode 100644
index 66ab65083dc..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: majorAnalysis
----
-* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
\ No newline at end of file
diff --git a/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md b/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
deleted file mode 100644
index 8749c790954..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
diff --git a/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md b/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
deleted file mode 100644
index 586b5341d29..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* C# 12: Add extractor and QL library support for `ref readonly` parameters.
diff --git a/csharp/ql/lib/change-notes/released/0.8.10.md b/csharp/ql/lib/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..f591ddc5b21
--- /dev/null
+++ b/csharp/ql/lib/change-notes/released/0.8.10.md
@@ -0,0 +1,13 @@
+## 0.8.10
+
+### Major Analysis Improvements
+
+* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
+* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
+
+### Minor Analysis Improvements
+
+* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
+* C# 12: Add extractor and QL library support for `ref readonly` parameters.
+* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
+* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/csharp/ql/lib/codeql-pack.release.yml
+++ b/csharp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml
index d75ea3c6320..93c5c1120a2 100644
--- a/csharp/ql/lib/qlpack.yml
+++ b/csharp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-all
-version: 0.8.10-dev
+version: 0.8.10
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp
diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md
index 9fe1609363f..46c939e5cee 100644
--- a/csharp/ql/src/CHANGELOG.md
+++ b/csharp/ql/src/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
+
## 0.8.9
### Minor Analysis Improvements
diff --git a/csharp/ql/src/change-notes/2024-02-06-threat-models.md b/csharp/ql/src/change-notes/released/0.8.10.md
similarity index 88%
rename from csharp/ql/src/change-notes/2024-02-06-threat-models.md
rename to csharp/ql/src/change-notes/released/0.8.10.md
index 69ac4e4dc17..702161c3d28 100644
--- a/csharp/ql/src/change-notes/2024-02-06-threat-models.md
+++ b/csharp/ql/src/change-notes/released/0.8.10.md
@@ -1,4 +1,5 @@
----
-category: minorAnalysis
----
-* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
\ No newline at end of file
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/csharp/ql/src/codeql-pack.release.yml
+++ b/csharp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml
index 9ee23cc7307..46384094b19 100644
--- a/csharp/ql/src/qlpack.yml
+++ b/csharp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-queries
-version: 0.8.10-dev
+version: 0.8.10
groups:
- csharp
- queries
diff --git a/go/ql/consistency-queries/CHANGELOG.md b/go/ql/consistency-queries/CHANGELOG.md
index fba2a870356..a59e560c415 100644
--- a/go/ql/consistency-queries/CHANGELOG.md
+++ b/go/ql/consistency-queries/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.9
+
+No user-facing changes.
+
## 0.0.8
No user-facing changes.
diff --git a/go/ql/consistency-queries/change-notes/released/0.0.9.md b/go/ql/consistency-queries/change-notes/released/0.0.9.md
new file mode 100644
index 00000000000..c9e17c6d6cf
--- /dev/null
+++ b/go/ql/consistency-queries/change-notes/released/0.0.9.md
@@ -0,0 +1,3 @@
+## 0.0.9
+
+No user-facing changes.
diff --git a/go/ql/consistency-queries/codeql-pack.release.yml b/go/ql/consistency-queries/codeql-pack.release.yml
index 58fdc6b45de..ecdd64fbab8 100644
--- a/go/ql/consistency-queries/codeql-pack.release.yml
+++ b/go/ql/consistency-queries/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.8
+lastReleaseVersion: 0.0.9
diff --git a/go/ql/consistency-queries/qlpack.yml b/go/ql/consistency-queries/qlpack.yml
index b574796b995..d5a2fbee5f1 100644
--- a/go/ql/consistency-queries/qlpack.yml
+++ b/go/ql/consistency-queries/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql-go-consistency-queries
-version: 0.0.9-dev
+version: 0.0.9
groups:
- go
- queries
diff --git a/go/ql/lib/CHANGELOG.md b/go/ql/lib/CHANGELOG.md
index 65a2376217b..fee5fd37a26 100644
--- a/go/ql/lib/CHANGELOG.md
+++ b/go/ql/lib/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 0.7.10
+
+### Major Analysis Improvements
+
+* We have significantly improved the Go autobuilder to understand a greater range of project layouts, which allows Go source files to be analysed that could previously not be processed.
+* Go 1.22 has been included in the range of supported Go versions.
+
+### Bug Fixes
+
+* Fixed dataflow out of a `map` using a `range` statement.
+
## 0.7.9
No user-facing changes.
diff --git a/go/ql/lib/change-notes/2024-02-14-range-map-read.md b/go/ql/lib/change-notes/2024-02-14-range-map-read.md
deleted file mode 100644
index ea45737a72e..00000000000
--- a/go/ql/lib/change-notes/2024-02-14-range-map-read.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: fix
----
-* Fixed dataflow out of a `map` using a `range` statement.
diff --git a/go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md b/go/ql/lib/change-notes/released/0.7.10.md
similarity index 68%
rename from go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md
rename to go/ql/lib/change-notes/released/0.7.10.md
index 0442a571029..55954f8a394 100644
--- a/go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md
+++ b/go/ql/lib/change-notes/released/0.7.10.md
@@ -1,5 +1,10 @@
----
-category: majorAnalysis
----
+## 0.7.10
+
+### Major Analysis Improvements
+
* We have significantly improved the Go autobuilder to understand a greater range of project layouts, which allows Go source files to be analysed that could previously not be processed.
* Go 1.22 has been included in the range of supported Go versions.
+
+### Bug Fixes
+
+* Fixed dataflow out of a `map` using a `range` statement.
diff --git a/go/ql/lib/codeql-pack.release.yml b/go/ql/lib/codeql-pack.release.yml
index 576395f3405..67518567297 100644
--- a/go/ql/lib/codeql-pack.release.yml
+++ b/go/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.9
+lastReleaseVersion: 0.7.10
diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml
index f21e478efa6..8cc190fa880 100644
--- a/go/ql/lib/qlpack.yml
+++ b/go/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/go-all
-version: 0.7.10-dev
+version: 0.7.10
groups: go
dbscheme: go.dbscheme
extractor: go
diff --git a/go/ql/src/CHANGELOG.md b/go/ql/src/CHANGELOG.md
index d95165a3a34..24e38b9890e 100644
--- a/go/ql/src/CHANGELOG.md
+++ b/go/ql/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.7.10
+
+No user-facing changes.
+
## 0.7.9
### New Queries
diff --git a/go/ql/src/change-notes/released/0.7.10.md b/go/ql/src/change-notes/released/0.7.10.md
new file mode 100644
index 00000000000..989c5b8f682
--- /dev/null
+++ b/go/ql/src/change-notes/released/0.7.10.md
@@ -0,0 +1,3 @@
+## 0.7.10
+
+No user-facing changes.
diff --git a/go/ql/src/codeql-pack.release.yml b/go/ql/src/codeql-pack.release.yml
index 576395f3405..67518567297 100644
--- a/go/ql/src/codeql-pack.release.yml
+++ b/go/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.9
+lastReleaseVersion: 0.7.10
diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml
index d91cab59612..4ded3a52f63 100644
--- a/go/ql/src/qlpack.yml
+++ b/go/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/go-queries
-version: 0.7.10-dev
+version: 0.7.10
groups:
- go
- queries
diff --git a/java/ql/automodel/src/CHANGELOG.md b/java/ql/automodel/src/CHANGELOG.md
index 4a3c54adb38..c3282c773a9 100644
--- a/java/ql/automodel/src/CHANGELOG.md
+++ b/java/ql/automodel/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.17
+
+No user-facing changes.
+
## 0.0.16
No user-facing changes.
diff --git a/java/ql/automodel/src/change-notes/released/0.0.17.md b/java/ql/automodel/src/change-notes/released/0.0.17.md
new file mode 100644
index 00000000000..62cc89030a6
--- /dev/null
+++ b/java/ql/automodel/src/change-notes/released/0.0.17.md
@@ -0,0 +1,3 @@
+## 0.0.17
+
+No user-facing changes.
diff --git a/java/ql/automodel/src/codeql-pack.release.yml b/java/ql/automodel/src/codeql-pack.release.yml
index a49f7be4cff..cbc3d3cd493 100644
--- a/java/ql/automodel/src/codeql-pack.release.yml
+++ b/java/ql/automodel/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.16
+lastReleaseVersion: 0.0.17
diff --git a/java/ql/automodel/src/qlpack.yml b/java/ql/automodel/src/qlpack.yml
index 898239be098..59fab0cdcc5 100644
--- a/java/ql/automodel/src/qlpack.yml
+++ b/java/ql/automodel/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-automodel-queries
-version: 0.0.17-dev
+version: 0.0.17
groups:
- java
- automodel
diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md
index d369cbdc931..2a02ccee6ab 100644
--- a/java/ql/lib/CHANGELOG.md
+++ b/java/ql/lib/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
+
+### Bug Fixes
+
+* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
+* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
+
## 0.8.9
### Deprecated APIs
diff --git a/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md b/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
deleted file mode 100644
index eb560fba07d..00000000000
--- a/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: fix
----
-* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
diff --git a/java/ql/lib/change-notes/2024-02-27-error-types.md b/java/ql/lib/change-notes/2024-02-27-error-types.md
deleted file mode 100644
index cdc6d7620aa..00000000000
--- a/java/ql/lib/change-notes/2024-02-27-error-types.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
diff --git a/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md b/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
deleted file mode 100644
index a0227088ae9..00000000000
--- a/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: fix
----
-* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
diff --git a/java/ql/lib/change-notes/released/0.8.10.md b/java/ql/lib/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..b45f14bf347
--- /dev/null
+++ b/java/ql/lib/change-notes/released/0.8.10.md
@@ -0,0 +1,10 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
+
+### Bug Fixes
+
+* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
+* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
diff --git a/java/ql/lib/codeql-pack.release.yml b/java/ql/lib/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/java/ql/lib/codeql-pack.release.yml
+++ b/java/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml
index 15b4982d41e..428eedc75e3 100644
--- a/java/ql/lib/qlpack.yml
+++ b/java/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-all
-version: 0.8.10-dev
+version: 0.8.10
groups: java
dbscheme: config/semmlecode.dbscheme
extractor: java
diff --git a/java/ql/src/CHANGELOG.md b/java/ql/src/CHANGELOG.md
index 5d835351453..c61275f5ed8 100644
--- a/java/ql/src/CHANGELOG.md
+++ b/java/ql/src/CHANGELOG.md
@@ -1,3 +1,13 @@
+## 0.8.10
+
+### New Queries
+
+* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
+
+### Minor Analysis Improvements
+
+* To reduce the number of false positives in the query "Insertion of sensitive information into log files" (`java/sensitive-log`), variables with names that contain "null" (case-insensitively) are no longer considered sources of sensitive information.
+
## 0.8.9
### New Queries
diff --git a/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md b/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
deleted file mode 100644
index 1de07727796..00000000000
--- a/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: newQuery
----
-* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
\ No newline at end of file
diff --git a/java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md b/java/ql/src/change-notes/released/0.8.10.md
similarity index 54%
rename from java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md
rename to java/ql/src/change-notes/released/0.8.10.md
index 0bb4f18f2bd..c5d18ae3379 100644
--- a/java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md
+++ b/java/ql/src/change-notes/released/0.8.10.md
@@ -1,4 +1,9 @@
----
-category: minorAnalysis
----
+## 0.8.10
+
+### New Queries
+
+* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
+
+### Minor Analysis Improvements
+
* To reduce the number of false positives in the query "Insertion of sensitive information into log files" (`java/sensitive-log`), variables with names that contain "null" (case-insensitively) are no longer considered sources of sensitive information.
diff --git a/java/ql/src/codeql-pack.release.yml b/java/ql/src/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/java/ql/src/codeql-pack.release.yml
+++ b/java/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml
index 8f4de528e21..ebbdbeee3b2 100644
--- a/java/ql/src/qlpack.yml
+++ b/java/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-queries
-version: 0.8.10-dev
+version: 0.8.10
groups:
- java
- queries
diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md
index 5b97ebbb22b..d5edcc00513 100644
--- a/javascript/ql/lib/CHANGELOG.md
+++ b/javascript/ql/lib/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.8.10
+
+No user-facing changes.
+
## 0.8.9
### Minor Analysis Improvements
diff --git a/javascript/ql/lib/change-notes/released/0.8.10.md b/javascript/ql/lib/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..777bbd2fded
--- /dev/null
+++ b/javascript/ql/lib/change-notes/released/0.8.10.md
@@ -0,0 +1,3 @@
+## 0.8.10
+
+No user-facing changes.
diff --git a/javascript/ql/lib/codeql-pack.release.yml b/javascript/ql/lib/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/javascript/ql/lib/codeql-pack.release.yml
+++ b/javascript/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml
index ef3ca7521ac..da16493a21c 100644
--- a/javascript/ql/lib/qlpack.yml
+++ b/javascript/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-all
-version: 0.8.10-dev
+version: 0.8.10
groups: javascript
dbscheme: semmlecode.javascript.dbscheme
extractor: javascript
diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md
index 85516e3625d..b9627cac5ee 100644
--- a/javascript/ql/src/CHANGELOG.md
+++ b/javascript/ql/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.8.10
+
+No user-facing changes.
+
## 0.8.9
### Bug Fixes
diff --git a/javascript/ql/src/change-notes/released/0.8.10.md b/javascript/ql/src/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..777bbd2fded
--- /dev/null
+++ b/javascript/ql/src/change-notes/released/0.8.10.md
@@ -0,0 +1,3 @@
+## 0.8.10
+
+No user-facing changes.
diff --git a/javascript/ql/src/codeql-pack.release.yml b/javascript/ql/src/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/javascript/ql/src/codeql-pack.release.yml
+++ b/javascript/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml
index b6181aa30e9..d224952c564 100644
--- a/javascript/ql/src/qlpack.yml
+++ b/javascript/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-queries
-version: 0.8.10-dev
+version: 0.8.10
groups:
- javascript
- queries
diff --git a/misc/suite-helpers/CHANGELOG.md b/misc/suite-helpers/CHANGELOG.md
index 3c06dd69b0f..1c4455b66c4 100644
--- a/misc/suite-helpers/CHANGELOG.md
+++ b/misc/suite-helpers/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.7.10
+
+No user-facing changes.
+
## 0.7.9
No user-facing changes.
diff --git a/misc/suite-helpers/change-notes/released/0.7.10.md b/misc/suite-helpers/change-notes/released/0.7.10.md
new file mode 100644
index 00000000000..989c5b8f682
--- /dev/null
+++ b/misc/suite-helpers/change-notes/released/0.7.10.md
@@ -0,0 +1,3 @@
+## 0.7.10
+
+No user-facing changes.
diff --git a/misc/suite-helpers/codeql-pack.release.yml b/misc/suite-helpers/codeql-pack.release.yml
index 576395f3405..67518567297 100644
--- a/misc/suite-helpers/codeql-pack.release.yml
+++ b/misc/suite-helpers/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.9
+lastReleaseVersion: 0.7.10
diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml
index 49b7a6bda4c..54d978d5efe 100644
--- a/misc/suite-helpers/qlpack.yml
+++ b/misc/suite-helpers/qlpack.yml
@@ -1,4 +1,4 @@
name: codeql/suite-helpers
-version: 0.7.10-dev
+version: 0.7.10
groups: shared
warnOnImplicitThis: true
diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md
index e6f318c51ea..f095607ca1b 100644
--- a/python/ql/lib/CHANGELOG.md
+++ b/python/ql/lib/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.11.10
+
+### Minor Analysis Improvements
+
+* Fixed missing flow for dictionary updates (`d[] = ...`) when `` is a string constant not used in dictionary literals or as name of keyword-argument.
+* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
+
## 0.11.9
### Minor Analysis Improvements
diff --git a/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md b/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
deleted file mode 100644
index 3c47c6ba866..00000000000
--- a/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
diff --git a/python/ql/lib/change-notes/2024-03-01-dict-update-content.md b/python/ql/lib/change-notes/released/0.11.10.md
similarity index 52%
rename from python/ql/lib/change-notes/2024-03-01-dict-update-content.md
rename to python/ql/lib/change-notes/released/0.11.10.md
index dfb8d247fff..ed873724e4f 100644
--- a/python/ql/lib/change-notes/2024-03-01-dict-update-content.md
+++ b/python/ql/lib/change-notes/released/0.11.10.md
@@ -1,4 +1,6 @@
----
-category: minorAnalysis
----
+## 0.11.10
+
+### Minor Analysis Improvements
+
* Fixed missing flow for dictionary updates (`d[] = ...`) when `` is a string constant not used in dictionary literals or as name of keyword-argument.
+* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
diff --git a/python/ql/lib/codeql-pack.release.yml b/python/ql/lib/codeql-pack.release.yml
index b064d1778a1..ddddcbe9193 100644
--- a/python/ql/lib/codeql-pack.release.yml
+++ b/python/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.11.9
+lastReleaseVersion: 0.11.10
diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml
index e9f66e205f2..59a8b4c96d1 100644
--- a/python/ql/lib/qlpack.yml
+++ b/python/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/python-all
-version: 0.11.10-dev
+version: 0.11.10
groups: python
dbscheme: semmlecode.python.dbscheme
extractor: python
diff --git a/python/ql/src/CHANGELOG.md b/python/ql/src/CHANGELOG.md
index 50762bcbf34..d4245aba7a6 100644
--- a/python/ql/src/CHANGELOG.md
+++ b/python/ql/src/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.9.10
+
+### New Queries
+
+* The query `py/nosql-injection` for finding NoSQL injection vulnerabilities is now part of the default security suite.
+
## 0.9.9
No user-facing changes.
diff --git a/python/ql/src/change-notes/2024-03-04-nosql-injection.md b/python/ql/src/change-notes/released/0.9.10.md
similarity index 81%
rename from python/ql/src/change-notes/2024-03-04-nosql-injection.md
rename to python/ql/src/change-notes/released/0.9.10.md
index 6e98540c757..4cbb221b789 100644
--- a/python/ql/src/change-notes/2024-03-04-nosql-injection.md
+++ b/python/ql/src/change-notes/released/0.9.10.md
@@ -1,4 +1,5 @@
----
-category: newQuery
----
+## 0.9.10
+
+### New Queries
+
* The query `py/nosql-injection` for finding NoSQL injection vulnerabilities is now part of the default security suite.
diff --git a/python/ql/src/codeql-pack.release.yml b/python/ql/src/codeql-pack.release.yml
index aabed7c396b..d086ed69541 100644
--- a/python/ql/src/codeql-pack.release.yml
+++ b/python/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.9.9
+lastReleaseVersion: 0.9.10
diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml
index aa18f2d8707..c920f667836 100644
--- a/python/ql/src/qlpack.yml
+++ b/python/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/python-queries
-version: 0.9.10-dev
+version: 0.9.10
groups:
- python
- queries
diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md
index a623a151e89..c61a12e0f4a 100644
--- a/ruby/ql/lib/CHANGELOG.md
+++ b/ruby/ql/lib/CHANGELOG.md
@@ -1,3 +1,12 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
+* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
+* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
+* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
+
## 0.8.9
### Minor Analysis Improvements
diff --git a/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md b/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
deleted file mode 100644
index c2276f284a8..00000000000
--- a/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md b/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
deleted file mode 100644
index 1486c7a472d..00000000000
--- a/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md b/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
deleted file mode 100644
index 6f3a90768ba..00000000000
--- a/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md b/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
deleted file mode 100644
index 350e049b5bf..00000000000
--- a/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/released/0.8.10.md b/ruby/ql/lib/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..666e28f840e
--- /dev/null
+++ b/ruby/ql/lib/change-notes/released/0.8.10.md
@@ -0,0 +1,8 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
+* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
+* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
+* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
diff --git a/ruby/ql/lib/codeql-pack.release.yml b/ruby/ql/lib/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/ruby/ql/lib/codeql-pack.release.yml
+++ b/ruby/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml
index 7d409b83adb..de5b41999fe 100644
--- a/ruby/ql/lib/qlpack.yml
+++ b/ruby/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ruby-all
-version: 0.8.10-dev
+version: 0.8.10
groups: ruby
extractor: ruby
dbscheme: ruby.dbscheme
diff --git a/ruby/ql/src/CHANGELOG.md b/ruby/ql/src/CHANGELOG.md
index 4149c728eff..f875b6d16ad 100644
--- a/ruby/ql/src/CHANGELOG.md
+++ b/ruby/ql/src/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
+* Added additional request sources for Ruby on Rails.
+
## 0.8.9
No user-facing changes.
diff --git a/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md b/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
deleted file mode 100644
index 84ea696dfef..00000000000
--- a/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Added additional request sources for Ruby on Rails.
\ No newline at end of file
diff --git a/ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md b/ruby/ql/src/change-notes/released/0.8.10.md
similarity index 51%
rename from ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md
rename to ruby/ql/src/change-notes/released/0.8.10.md
index 43e40d3fd53..985cdf8d22e 100644
--- a/ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md
+++ b/ruby/ql/src/change-notes/released/0.8.10.md
@@ -1,4 +1,6 @@
----
-category: minorAnalysis
----
-* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
\ No newline at end of file
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
+* Added additional request sources for Ruby on Rails.
diff --git a/ruby/ql/src/codeql-pack.release.yml b/ruby/ql/src/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/ruby/ql/src/codeql-pack.release.yml
+++ b/ruby/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml
index 8af7f9fd797..5e379268234 100644
--- a/ruby/ql/src/qlpack.yml
+++ b/ruby/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ruby-queries
-version: 0.8.10-dev
+version: 0.8.10
groups:
- ruby
- queries
diff --git a/shared/controlflow/CHANGELOG.md b/shared/controlflow/CHANGELOG.md
index dbfa6ef4512..75f2ca53f98 100644
--- a/shared/controlflow/CHANGELOG.md
+++ b/shared/controlflow/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.10
+
+No user-facing changes.
+
## 0.1.9
No user-facing changes.
diff --git a/shared/controlflow/change-notes/released/0.1.10.md b/shared/controlflow/change-notes/released/0.1.10.md
new file mode 100644
index 00000000000..47358eeee93
--- /dev/null
+++ b/shared/controlflow/change-notes/released/0.1.10.md
@@ -0,0 +1,3 @@
+## 0.1.10
+
+No user-facing changes.
diff --git a/shared/controlflow/codeql-pack.release.yml b/shared/controlflow/codeql-pack.release.yml
index 1425c0edf7f..30f5ca88be0 100644
--- a/shared/controlflow/codeql-pack.release.yml
+++ b/shared/controlflow/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.1.9
+lastReleaseVersion: 0.1.10
diff --git a/shared/controlflow/qlpack.yml b/shared/controlflow/qlpack.yml
index 9d35a678276..1d43802be42 100644
--- a/shared/controlflow/qlpack.yml
+++ b/shared/controlflow/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/controlflow
-version: 0.1.10-dev
+version: 0.1.10
groups: shared
library: true
dependencies:
diff --git a/shared/dataflow/CHANGELOG.md b/shared/dataflow/CHANGELOG.md
index 67a5bf589f4..ef80788bded 100644
--- a/shared/dataflow/CHANGELOG.md
+++ b/shared/dataflow/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.1
+
+No user-facing changes.
+
## 0.2.0
### Breaking Changes
diff --git a/shared/dataflow/change-notes/released/0.2.1.md b/shared/dataflow/change-notes/released/0.2.1.md
new file mode 100644
index 00000000000..3dbfc85fe11
--- /dev/null
+++ b/shared/dataflow/change-notes/released/0.2.1.md
@@ -0,0 +1,3 @@
+## 0.2.1
+
+No user-facing changes.
diff --git a/shared/dataflow/codeql-pack.release.yml b/shared/dataflow/codeql-pack.release.yml
index 5274e27ed52..df29a726bcc 100644
--- a/shared/dataflow/codeql-pack.release.yml
+++ b/shared/dataflow/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.0
+lastReleaseVersion: 0.2.1
diff --git a/shared/dataflow/qlpack.yml b/shared/dataflow/qlpack.yml
index 1e7becf71c4..ee422e02ea9 100644
--- a/shared/dataflow/qlpack.yml
+++ b/shared/dataflow/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/dataflow
-version: 0.2.1-dev
+version: 0.2.1
groups: shared
library: true
dependencies:
diff --git a/shared/mad/CHANGELOG.md b/shared/mad/CHANGELOG.md
index 4d09057118c..4730366775e 100644
--- a/shared/mad/CHANGELOG.md
+++ b/shared/mad/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/mad/change-notes/released/0.2.10.md b/shared/mad/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/mad/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/mad/codeql-pack.release.yml b/shared/mad/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/mad/codeql-pack.release.yml
+++ b/shared/mad/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml
index 22c8f271ccc..6d7269ef3da 100644
--- a/shared/mad/qlpack.yml
+++ b/shared/mad/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/mad
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies: null
diff --git a/shared/rangeanalysis/CHANGELOG.md b/shared/rangeanalysis/CHANGELOG.md
index 5b8dbcfab22..9943dcb7972 100644
--- a/shared/rangeanalysis/CHANGELOG.md
+++ b/shared/rangeanalysis/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.9
+
+No user-facing changes.
+
## 0.0.8
No user-facing changes.
diff --git a/shared/rangeanalysis/change-notes/released/0.0.9.md b/shared/rangeanalysis/change-notes/released/0.0.9.md
new file mode 100644
index 00000000000..c9e17c6d6cf
--- /dev/null
+++ b/shared/rangeanalysis/change-notes/released/0.0.9.md
@@ -0,0 +1,3 @@
+## 0.0.9
+
+No user-facing changes.
diff --git a/shared/rangeanalysis/codeql-pack.release.yml b/shared/rangeanalysis/codeql-pack.release.yml
index 58fdc6b45de..ecdd64fbab8 100644
--- a/shared/rangeanalysis/codeql-pack.release.yml
+++ b/shared/rangeanalysis/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.8
+lastReleaseVersion: 0.0.9
diff --git a/shared/rangeanalysis/qlpack.yml b/shared/rangeanalysis/qlpack.yml
index 836fe51ee34..01db5d5734d 100644
--- a/shared/rangeanalysis/qlpack.yml
+++ b/shared/rangeanalysis/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/rangeanalysis
-version: 0.0.9-dev
+version: 0.0.9
groups: shared
library: true
dependencies:
diff --git a/shared/regex/CHANGELOG.md b/shared/regex/CHANGELOG.md
index cd5f91f71ec..c05869c153d 100644
--- a/shared/regex/CHANGELOG.md
+++ b/shared/regex/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/regex/change-notes/released/0.2.10.md b/shared/regex/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/regex/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/regex/codeql-pack.release.yml b/shared/regex/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/regex/codeql-pack.release.yml
+++ b/shared/regex/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml
index ea3f7f9b238..0d4f485312f 100644
--- a/shared/regex/qlpack.yml
+++ b/shared/regex/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/regex
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies:
diff --git a/shared/ssa/CHANGELOG.md b/shared/ssa/CHANGELOG.md
index 01acfae0148..a9161ff578b 100644
--- a/shared/ssa/CHANGELOG.md
+++ b/shared/ssa/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/ssa/change-notes/released/0.2.10.md b/shared/ssa/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/ssa/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/ssa/codeql-pack.release.yml b/shared/ssa/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/ssa/codeql-pack.release.yml
+++ b/shared/ssa/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml
index 19304ad107f..2ad254711a5 100644
--- a/shared/ssa/qlpack.yml
+++ b/shared/ssa/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ssa
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies:
diff --git a/shared/threat-models/CHANGELOG.md b/shared/threat-models/CHANGELOG.md
index fba2a870356..a59e560c415 100644
--- a/shared/threat-models/CHANGELOG.md
+++ b/shared/threat-models/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.9
+
+No user-facing changes.
+
## 0.0.8
No user-facing changes.
diff --git a/shared/threat-models/change-notes/released/0.0.9.md b/shared/threat-models/change-notes/released/0.0.9.md
new file mode 100644
index 00000000000..c9e17c6d6cf
--- /dev/null
+++ b/shared/threat-models/change-notes/released/0.0.9.md
@@ -0,0 +1,3 @@
+## 0.0.9
+
+No user-facing changes.
diff --git a/shared/threat-models/codeql-pack.release.yml b/shared/threat-models/codeql-pack.release.yml
index 58fdc6b45de..ecdd64fbab8 100644
--- a/shared/threat-models/codeql-pack.release.yml
+++ b/shared/threat-models/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.8
+lastReleaseVersion: 0.0.9
diff --git a/shared/threat-models/qlpack.yml b/shared/threat-models/qlpack.yml
index d0ed9a913b2..60cbbc56fcb 100644
--- a/shared/threat-models/qlpack.yml
+++ b/shared/threat-models/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/threat-models
-version: 0.0.9-dev
+version: 0.0.9
library: true
groups: shared
dataExtensions:
diff --git a/shared/tutorial/CHANGELOG.md b/shared/tutorial/CHANGELOG.md
index 1db3a01af0b..560ad058d5b 100644
--- a/shared/tutorial/CHANGELOG.md
+++ b/shared/tutorial/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/tutorial/change-notes/released/0.2.10.md b/shared/tutorial/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/tutorial/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/tutorial/codeql-pack.release.yml b/shared/tutorial/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/tutorial/codeql-pack.release.yml
+++ b/shared/tutorial/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml
index b595ae9ee70..69116705c1b 100644
--- a/shared/tutorial/qlpack.yml
+++ b/shared/tutorial/qlpack.yml
@@ -1,7 +1,7 @@
name: codeql/tutorial
description: Library for the CodeQL detective tutorials, helping new users learn to
write CodeQL queries.
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/shared/typetracking/CHANGELOG.md b/shared/typetracking/CHANGELOG.md
index afc857bc6bc..350f9ecbeae 100644
--- a/shared/typetracking/CHANGELOG.md
+++ b/shared/typetracking/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/typetracking/change-notes/released/0.2.10.md b/shared/typetracking/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/typetracking/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/typetracking/codeql-pack.release.yml b/shared/typetracking/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/typetracking/codeql-pack.release.yml
+++ b/shared/typetracking/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml
index b55927f59bb..fbbdcf5162a 100644
--- a/shared/typetracking/qlpack.yml
+++ b/shared/typetracking/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/typetracking
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies:
diff --git a/shared/typos/CHANGELOG.md b/shared/typos/CHANGELOG.md
index 66c5871d982..54b1eaa4d58 100644
--- a/shared/typos/CHANGELOG.md
+++ b/shared/typos/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/typos/change-notes/released/0.2.10.md b/shared/typos/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/typos/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/typos/codeql-pack.release.yml b/shared/typos/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/typos/codeql-pack.release.yml
+++ b/shared/typos/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml
index 644bfe11bff..4d59d9b3c34 100644
--- a/shared/typos/qlpack.yml
+++ b/shared/typos/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/typos
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/shared/util/CHANGELOG.md b/shared/util/CHANGELOG.md
index 63832e927fa..1ca1f71bcbc 100644
--- a/shared/util/CHANGELOG.md
+++ b/shared/util/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/util/change-notes/released/0.2.10.md b/shared/util/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/util/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/util/codeql-pack.release.yml b/shared/util/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/util/codeql-pack.release.yml
+++ b/shared/util/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml
index ca1a866a53d..28ed738a93d 100644
--- a/shared/util/qlpack.yml
+++ b/shared/util/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/util
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies: null
diff --git a/shared/yaml/CHANGELOG.md b/shared/yaml/CHANGELOG.md
index e5495abcd50..9fd5ebc26ab 100644
--- a/shared/yaml/CHANGELOG.md
+++ b/shared/yaml/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/yaml/change-notes/released/0.2.10.md b/shared/yaml/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/yaml/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/yaml/codeql-pack.release.yml b/shared/yaml/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/yaml/codeql-pack.release.yml
+++ b/shared/yaml/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml
index de5b47e120a..9643ffcec66 100644
--- a/shared/yaml/qlpack.yml
+++ b/shared/yaml/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/yaml
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/swift/ql/lib/CHANGELOG.md b/swift/ql/lib/CHANGELOG.md
index e88cd0259cc..8f14bfcedc9 100644
--- a/swift/ql/lib/CHANGELOG.md
+++ b/swift/ql/lib/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.3.10
+
+### Bug Fixes
+
+* Fixed an issue where `TypeDecl.getFullName` would get stuck in an loop and fail when minor database inconsistencies are present.
+
## 0.3.9
### Minor Analysis Improvements
diff --git a/swift/ql/lib/change-notes/2024-02-22-extension-patch.md b/swift/ql/lib/change-notes/released/0.3.10.md
similarity index 83%
rename from swift/ql/lib/change-notes/2024-02-22-extension-patch.md
rename to swift/ql/lib/change-notes/released/0.3.10.md
index 7bd78f3b785..9d6286ff58a 100644
--- a/swift/ql/lib/change-notes/2024-02-22-extension-patch.md
+++ b/swift/ql/lib/change-notes/released/0.3.10.md
@@ -1,4 +1,5 @@
----
-category: fix
----
+## 0.3.10
+
+### Bug Fixes
+
* Fixed an issue where `TypeDecl.getFullName` would get stuck in an loop and fail when minor database inconsistencies are present.
diff --git a/swift/ql/lib/codeql-pack.release.yml b/swift/ql/lib/codeql-pack.release.yml
index 3fa5180bcb4..76ca0ac8ba7 100644
--- a/swift/ql/lib/codeql-pack.release.yml
+++ b/swift/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.3.9
+lastReleaseVersion: 0.3.10
diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml
index a37a4cb3d58..70ec4798ea8 100644
--- a/swift/ql/lib/qlpack.yml
+++ b/swift/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/swift-all
-version: 0.3.10-dev
+version: 0.3.10
groups: swift
extractor: swift
dbscheme: swift.dbscheme
diff --git a/swift/ql/src/CHANGELOG.md b/swift/ql/src/CHANGELOG.md
index 96615d06972..bda9834c9bc 100644
--- a/swift/ql/src/CHANGELOG.md
+++ b/swift/ql/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.3.10
+
+No user-facing changes.
+
## 0.3.9
### New Queries
diff --git a/swift/ql/src/change-notes/released/0.3.10.md b/swift/ql/src/change-notes/released/0.3.10.md
new file mode 100644
index 00000000000..925a48fc52e
--- /dev/null
+++ b/swift/ql/src/change-notes/released/0.3.10.md
@@ -0,0 +1,3 @@
+## 0.3.10
+
+No user-facing changes.
diff --git a/swift/ql/src/codeql-pack.release.yml b/swift/ql/src/codeql-pack.release.yml
index 3fa5180bcb4..76ca0ac8ba7 100644
--- a/swift/ql/src/codeql-pack.release.yml
+++ b/swift/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.3.9
+lastReleaseVersion: 0.3.10
diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml
index e3ead42c98b..ba66b065529 100644
--- a/swift/ql/src/qlpack.yml
+++ b/swift/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/swift-queries
-version: 0.3.10-dev
+version: 0.3.10
groups:
- swift
- queries
From 87f3b43576864cc32cd9b677bf62273c506388f1 Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Tue, 5 Mar 2024 08:28:16 +0000
Subject: [PATCH 021/497] Ruby: remove deprecated private class
---
ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll | 5 -----
1 file changed, 5 deletions(-)
diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
index c8667b2b2f2..6fde1705018 100644
--- a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
+++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll
@@ -441,11 +441,6 @@ class ActionControllerSkipForgeryProtectionCall extends CsrfProtectionSetting::R
override boolean getVerificationSetting() { result = false }
}
-/**
- * DEPRECATED: Use `ActionController::ProtectFromForgeryCall` instead.
- */
-deprecated class ActionControllerProtectFromForgeryCall = ActionController::ProtectFromForgeryCall;
-
/**
* A call to `send_file`, which sends the file at the given path to the client.
*/
From 2aa093c95cde5faed2aef27e119f8266e660863b Mon Sep 17 00:00:00 2001
From: "Michael B. Gale"
Date: Tue, 5 Mar 2024 11:25:02 +0000
Subject: [PATCH 022/497] Go: Move `getImportPath` to shared `util` package
---
.../cli/go-autobuilder/go-autobuilder.go | 60 +------------------
go/extractor/util/util.go | 59 ++++++++++++++++++
.../util_test.go} | 2 +-
3 files changed, 61 insertions(+), 60 deletions(-)
rename go/extractor/{cli/go-autobuilder/go-autobuilder_test.go => util/util_test.go} (98%)
diff --git a/go/extractor/cli/go-autobuilder/go-autobuilder.go b/go/extractor/cli/go-autobuilder/go-autobuilder.go
index 91291c77144..b2e2a78666f 100644
--- a/go/extractor/cli/go-autobuilder/go-autobuilder.go
+++ b/go/extractor/cli/go-autobuilder/go-autobuilder.go
@@ -3,7 +3,6 @@ package main
import (
"fmt"
"log"
- "net/url"
"os"
"os/exec"
"path/filepath"
@@ -56,63 +55,6 @@ Build behavior:
fmt.Fprintf(os.Stderr, "Usage:\n\n %s\n", os.Args[0])
}
-// Returns the import path of the package being built, or "" if it cannot be determined.
-func getImportPath() (importpath string) {
- importpath = os.Getenv("LGTM_INDEX_IMPORT_PATH")
- if importpath == "" {
- repourl := os.Getenv("SEMMLE_REPO_URL")
- if repourl == "" {
- githubrepo := os.Getenv("GITHUB_REPOSITORY")
- if githubrepo == "" {
- log.Printf("Unable to determine import path, as neither LGTM_INDEX_IMPORT_PATH nor GITHUB_REPOSITORY is set\n")
- return ""
- } else {
- importpath = "github.com/" + githubrepo
- }
- } else {
- importpath = getImportPathFromRepoURL(repourl)
- if importpath == "" {
- log.Printf("Failed to determine import path from SEMMLE_REPO_URL '%s'\n", repourl)
- return
- }
- }
- }
- log.Printf("Import path is '%s'\n", importpath)
- return
-}
-
-// Returns the import path of the package being built from `repourl`, or "" if it cannot be
-// determined.
-func getImportPathFromRepoURL(repourl string) string {
- // check for scp-like URL as in "git@github.com:github/codeql-go.git"
- shorturl := regexp.MustCompile(`^([^@]+@)?([^:]+):([^/].*?)(\.git)?$`)
- m := shorturl.FindStringSubmatch(repourl)
- if m != nil {
- return m[2] + "/" + m[3]
- }
-
- // otherwise parse as proper URL
- u, err := url.Parse(repourl)
- if err != nil {
- log.Fatalf("Malformed repository URL '%s'\n", repourl)
- }
-
- if u.Scheme == "file" {
- // we can't determine import paths from file paths
- return ""
- }
-
- if u.Hostname() == "" || u.Path == "" {
- return ""
- }
-
- host := u.Hostname()
- path := u.Path
- // strip off leading slashes and trailing `.git` if present
- path = regexp.MustCompile(`^/+|\.git$`).ReplaceAllString(path, "")
- return host + "/" + path
-}
-
func restoreRepoLayout(fromDir string, dirEntries []string, scratchDirName string, toDir string) {
for _, dirEntry := range dirEntries {
if dirEntry != scratchDirName {
@@ -568,7 +510,7 @@ func installDependenciesAndBuild() {
if len(workspaces) == 1 {
workspace := workspaces[0]
- importpath := getImportPath()
+ importpath := util.GetImportPath()
needGopath := getNeedGopath(workspace, importpath)
inLGTM := os.Getenv("LGTM_SRC") != "" || os.Getenv("LGTM_INDEX_NEED_GOPATH") != ""
diff --git a/go/extractor/util/util.go b/go/extractor/util/util.go
index b5b28089e78..2ae6a2b0cd2 100644
--- a/go/extractor/util/util.go
+++ b/go/extractor/util/util.go
@@ -6,9 +6,11 @@ import (
"io"
"io/fs"
"log"
+ "net/url"
"os"
"os/exec"
"path/filepath"
+ "regexp"
"runtime"
"slices"
"strings"
@@ -350,3 +352,60 @@ func GetParentDirs(paths []string) []string {
}
return dirs
}
+
+// Returns the import path of the package being built, or "" if it cannot be determined.
+func GetImportPath() (importpath string) {
+ importpath = os.Getenv("LGTM_INDEX_IMPORT_PATH")
+ if importpath == "" {
+ repourl := os.Getenv("SEMMLE_REPO_URL")
+ if repourl == "" {
+ githubrepo := os.Getenv("GITHUB_REPOSITORY")
+ if githubrepo == "" {
+ log.Printf("Unable to determine import path, as neither LGTM_INDEX_IMPORT_PATH nor GITHUB_REPOSITORY is set\n")
+ return ""
+ } else {
+ importpath = "github.com/" + githubrepo
+ }
+ } else {
+ importpath = getImportPathFromRepoURL(repourl)
+ if importpath == "" {
+ log.Printf("Failed to determine import path from SEMMLE_REPO_URL '%s'\n", repourl)
+ return
+ }
+ }
+ }
+ log.Printf("Import path is '%s'\n", importpath)
+ return
+}
+
+// Returns the import path of the package being built from `repourl`, or "" if it cannot be
+// determined.
+func getImportPathFromRepoURL(repourl string) string {
+ // check for scp-like URL as in "git@github.com:github/codeql-go.git"
+ shorturl := regexp.MustCompile(`^([^@]+@)?([^:]+):([^/].*?)(\.git)?$`)
+ m := shorturl.FindStringSubmatch(repourl)
+ if m != nil {
+ return m[2] + "/" + m[3]
+ }
+
+ // otherwise parse as proper URL
+ u, err := url.Parse(repourl)
+ if err != nil {
+ log.Fatalf("Malformed repository URL '%s'\n", repourl)
+ }
+
+ if u.Scheme == "file" {
+ // we can't determine import paths from file paths
+ return ""
+ }
+
+ if u.Hostname() == "" || u.Path == "" {
+ return ""
+ }
+
+ host := u.Hostname()
+ path := u.Path
+ // strip off leading slashes and trailing `.git` if present
+ path = regexp.MustCompile(`^/+|\.git$`).ReplaceAllString(path, "")
+ return host + "/" + path
+}
diff --git a/go/extractor/cli/go-autobuilder/go-autobuilder_test.go b/go/extractor/util/util_test.go
similarity index 98%
rename from go/extractor/cli/go-autobuilder/go-autobuilder_test.go
rename to go/extractor/util/util_test.go
index f4e8405fe36..45d32bda3e1 100644
--- a/go/extractor/cli/go-autobuilder/go-autobuilder_test.go
+++ b/go/extractor/util/util_test.go
@@ -1,4 +1,4 @@
-package main
+package util
import "testing"
From 367ecf75d5889bb20da8e8a2123804d6cb76d79b Mon Sep 17 00:00:00 2001
From: "Michael B. Gale"
Date: Tue, 5 Mar 2024 11:37:51 +0000
Subject: [PATCH 023/497] Go: Use import path for auto-generated Go module
names
---
go/extractor/toolchain/toolchain.go | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/go/extractor/toolchain/toolchain.go b/go/extractor/toolchain/toolchain.go
index 38abfd43874..104894c5975 100644
--- a/go/extractor/toolchain/toolchain.go
+++ b/go/extractor/toolchain/toolchain.go
@@ -5,8 +5,10 @@ import (
"log"
"os"
"os/exec"
+ "path/filepath"
"strings"
+ "github.com/github/codeql-go/extractor/util"
"golang.org/x/mod/semver"
)
@@ -81,7 +83,20 @@ func TidyModule(path string) *exec.Cmd {
// Run `go mod init` in the directory given by `path`.
func InitModule(path string) *exec.Cmd {
- modInit := exec.Command("go", "mod", "init", "codeql/auto-project")
+ moduleName := "codeql/auto-project"
+
+ if importpath := util.GetImportPath(); importpath != "" {
+ // This should be something like `github.com/user/repo`
+ moduleName = importpath
+
+ // If we are not initialising the new module in the root directory of the workspace,
+ // append the relative path to the module name.
+ if relPath, err := filepath.Rel(".", path); err != nil && relPath != "." {
+ moduleName = moduleName + "/" + relPath
+ }
+ }
+
+ modInit := exec.Command("go", "mod", "init", moduleName)
modInit.Dir = path
return modInit
}
From b1e0bc03ab34a271563ac8a5ba66577b0f59b954 Mon Sep 17 00:00:00 2001
From: "Michael B. Gale"
Date: Tue, 5 Mar 2024 11:55:10 +0000
Subject: [PATCH 024/497] Go: Fix check for whether it is safe to initialise a
`go.mod` file in a given directory
---
go/extractor/project/project.go | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/go/extractor/project/project.go b/go/extractor/project/project.go
index 187389ecd55..9315a33f04c 100644
--- a/go/extractor/project/project.go
+++ b/go/extractor/project/project.go
@@ -439,8 +439,9 @@ func getBuildRoots(emitDiagnostics bool) (goWorkspaces []GoWorkspace, totalModul
for _, component := range components {
path = filepath.Join(path, component)
- // Try to initialize a `go.mod` file automatically for the stray source files.
- if !slices.Contains(goModDirs, path) {
+ // Try to initialize a `go.mod` file automatically for the stray source files if
+ // doing so would not place it in a parent directory of an existing `go.mod` file.
+ if !startsWithAnyOf(path, goModDirs) {
goWorkspaces = append(goWorkspaces, GoWorkspace{
BaseDir: path,
DepMode: GoGetNoModules,
@@ -477,6 +478,16 @@ func getBuildRoots(emitDiagnostics bool) (goWorkspaces []GoWorkspace, totalModul
return
}
+// Determines whether `str` starts with any of `prefixes`.
+func startsWithAnyOf(str string, prefixes []string) bool {
+ for _, prefix := range prefixes {
+ if strings.HasPrefix(str, prefix) {
+ return true
+ }
+ }
+ return false
+}
+
// Finds Go workspaces in the current working directory.
func GetWorkspaceInfo(emitDiagnostics bool) []GoWorkspace {
bazelPaths := slices.Concat(
From ac394dc80ce6e3488285fd5abc01f2c5543ba0fb Mon Sep 17 00:00:00 2001
From: "Michael B. Gale"
Date: Tue, 5 Mar 2024 13:46:33 +0000
Subject: [PATCH 025/497] Go: Better check for path prefixes
---
go/extractor/project/project.go | 2 +-
go/extractor/project/project_test.go | 27 +++++++++++++++++++++++++++
2 files changed, 28 insertions(+), 1 deletion(-)
create mode 100644 go/extractor/project/project_test.go
diff --git a/go/extractor/project/project.go b/go/extractor/project/project.go
index 9315a33f04c..22c0f856c79 100644
--- a/go/extractor/project/project.go
+++ b/go/extractor/project/project.go
@@ -481,7 +481,7 @@ func getBuildRoots(emitDiagnostics bool) (goWorkspaces []GoWorkspace, totalModul
// Determines whether `str` starts with any of `prefixes`.
func startsWithAnyOf(str string, prefixes []string) bool {
for _, prefix := range prefixes {
- if strings.HasPrefix(str, prefix) {
+ if relPath, err := filepath.Rel(str, prefix); err == nil && !strings.HasPrefix(relPath, "..") {
return true
}
}
diff --git a/go/extractor/project/project_test.go b/go/extractor/project/project_test.go
new file mode 100644
index 00000000000..f2de420773f
--- /dev/null
+++ b/go/extractor/project/project_test.go
@@ -0,0 +1,27 @@
+package project
+
+import (
+ "path/filepath"
+ "testing"
+)
+
+func testStartsWithAnyOf(t *testing.T, path string, prefix string, expectation bool) {
+ result := startsWithAnyOf(path, []string{prefix})
+ if result != expectation {
+ t.Errorf("Expected startsWithAnyOf(%s, %s) to be %t, but it is %t.", path, prefix, expectation, result)
+ }
+}
+
+func TestStartsWithAnyOf(t *testing.T) {
+ testStartsWithAnyOf(t, ".", ".", true)
+ testStartsWithAnyOf(t, ".", "dir", true)
+ testStartsWithAnyOf(t, ".", filepath.Join("foo", "bar"), true)
+ testStartsWithAnyOf(t, "dir", "dir", true)
+ testStartsWithAnyOf(t, "foo", filepath.Join("foo", "bar"), true)
+ testStartsWithAnyOf(t, filepath.Join("foo", "bar"), filepath.Join("foo", "bar"), true)
+ testStartsWithAnyOf(t, filepath.Join("foo", "bar"), filepath.Join("foo", "bar", "baz"), true)
+
+ testStartsWithAnyOf(t, filepath.Join("foo", "bar"), "foo", false)
+ testStartsWithAnyOf(t, filepath.Join("foo", "bar"), "bar", false)
+ testStartsWithAnyOf(t, filepath.Join("foo", "bar"), filepath.Join("foo", "baz"), false)
+}
From a8d240dd7278a4d0e73b92daff10bfd1e7d17d98 Mon Sep 17 00:00:00 2001
From: "Michael B. Gale"
Date: Tue, 5 Mar 2024 14:08:16 +0000
Subject: [PATCH 026/497] Go: Add integration test for mixed layout project
---
.../go/mixed-layout/diagnostics.expected | 28 +++++++++++++++++++
.../force_sequential_test_execution | 2 ++
.../go/mixed-layout/src/module/go.mod | 5 ++++
.../go/mixed-layout/src/module/go.sum | 7 +++++
.../go/mixed-layout/src/module/test.go | 13 +++++++++
.../go/mixed-layout/src/stray-files/test.go | 13 +++++++++
.../go/mixed-layout/src/workspace/go.work | 3 ++
.../mixed-layout/src/workspace/subdir/go.mod | 5 ++++
.../mixed-layout/src/workspace/subdir/go.sum | 7 +++++
.../mixed-layout/src/workspace/subdir/test.go | 13 +++++++++
.../go/mixed-layout/test.expected | 8 ++++++
.../all-platforms/go/mixed-layout/test.py | 18 ++++++++++++
.../all-platforms/go/mixed-layout/test.ql | 8 ++++++
13 files changed, 130 insertions(+)
create mode 100644 go/ql/integration-tests/all-platforms/go/mixed-layout/diagnostics.expected
create mode 100644 go/ql/integration-tests/all-platforms/go/mixed-layout/force_sequential_test_execution
create mode 100644 go/ql/integration-tests/all-platforms/go/mixed-layout/src/module/go.mod
create mode 100644 go/ql/integration-tests/all-platforms/go/mixed-layout/src/module/go.sum
create mode 100644 go/ql/integration-tests/all-platforms/go/mixed-layout/src/module/test.go
create mode 100644 go/ql/integration-tests/all-platforms/go/mixed-layout/src/stray-files/test.go
create mode 100644 go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/go.work
create mode 100644 go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/subdir/go.mod
create mode 100644 go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/subdir/go.sum
create mode 100644 go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/subdir/test.go
create mode 100644 go/ql/integration-tests/all-platforms/go/mixed-layout/test.expected
create mode 100644 go/ql/integration-tests/all-platforms/go/mixed-layout/test.py
create mode 100644 go/ql/integration-tests/all-platforms/go/mixed-layout/test.ql
diff --git a/go/ql/integration-tests/all-platforms/go/mixed-layout/diagnostics.expected b/go/ql/integration-tests/all-platforms/go/mixed-layout/diagnostics.expected
new file mode 100644
index 00000000000..bbbdd515d68
--- /dev/null
+++ b/go/ql/integration-tests/all-platforms/go/mixed-layout/diagnostics.expected
@@ -0,0 +1,28 @@
+{
+ "markdownMessage": "1 `go.work` file was found:\n\n`workspace/go.work`",
+ "severity": "note",
+ "source": {
+ "extractorName": "go",
+ "id": "go/autobuilder/go-work-found",
+ "name": "`go.work` file found"
+ },
+ "visibility": {
+ "cliSummaryTable": false,
+ "statusPage": false,
+ "telemetry": true
+ }
+}
+{
+ "markdownMessage": "Go files were found outside of the Go modules corresponding to these `go.mod` files.\n\n`workspace/subdir/go.mod`, `module/go.mod`",
+ "severity": "note",
+ "source": {
+ "extractorName": "go",
+ "id": "go/autobuilder/go-files-outside-go-modules",
+ "name": "Go files were found outside Go modules"
+ },
+ "visibility": {
+ "cliSummaryTable": false,
+ "statusPage": false,
+ "telemetry": true
+ }
+}
diff --git a/go/ql/integration-tests/all-platforms/go/mixed-layout/force_sequential_test_execution b/go/ql/integration-tests/all-platforms/go/mixed-layout/force_sequential_test_execution
new file mode 100644
index 00000000000..47ca9929099
--- /dev/null
+++ b/go/ql/integration-tests/all-platforms/go/mixed-layout/force_sequential_test_execution
@@ -0,0 +1,2 @@
+# go get has been observed to sometimes fail when multiple tests try to simultaneously fetch the same package.
+goget
diff --git a/go/ql/integration-tests/all-platforms/go/mixed-layout/src/module/go.mod b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/module/go.mod
new file mode 100644
index 00000000000..0b8f33b9069
--- /dev/null
+++ b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/module/go.mod
@@ -0,0 +1,5 @@
+go 1.14
+
+require golang.org/x/net v0.0.0-20200505041828-1ed23360d12c
+
+module module
diff --git a/go/ql/integration-tests/all-platforms/go/mixed-layout/src/module/go.sum b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/module/go.sum
new file mode 100644
index 00000000000..6c5ffa613d0
--- /dev/null
+++ b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/module/go.sum
@@ -0,0 +1,7 @@
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/net v0.0.0-20200505041828-1ed23360d12c h1:zJ0mtu4jCalhKg6Oaukv6iIkb+cOvDrajDH9DH46Q4M=
+golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/go/ql/integration-tests/all-platforms/go/mixed-layout/src/module/test.go b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/module/test.go
new file mode 100644
index 00000000000..afc86ac3a12
--- /dev/null
+++ b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/module/test.go
@@ -0,0 +1,13 @@
+package subdir
+
+import (
+ "fmt"
+
+ "golang.org/x/net/ipv4"
+)
+
+func test() {
+
+ header := ipv4.Header{}
+ fmt.Print(header.String())
+}
diff --git a/go/ql/integration-tests/all-platforms/go/mixed-layout/src/stray-files/test.go b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/stray-files/test.go
new file mode 100644
index 00000000000..afc86ac3a12
--- /dev/null
+++ b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/stray-files/test.go
@@ -0,0 +1,13 @@
+package subdir
+
+import (
+ "fmt"
+
+ "golang.org/x/net/ipv4"
+)
+
+func test() {
+
+ header := ipv4.Header{}
+ fmt.Print(header.String())
+}
diff --git a/go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/go.work b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/go.work
new file mode 100644
index 00000000000..e7e866fbe27
--- /dev/null
+++ b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/go.work
@@ -0,0 +1,3 @@
+go 1.22.0
+
+use ./subdir
diff --git a/go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/subdir/go.mod b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/subdir/go.mod
new file mode 100644
index 00000000000..40a3b330c38
--- /dev/null
+++ b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/subdir/go.mod
@@ -0,0 +1,5 @@
+go 1.22.0
+
+require golang.org/x/net v0.0.0-20200505041828-1ed23360d12c
+
+module subdir
diff --git a/go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/subdir/go.sum b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/subdir/go.sum
new file mode 100644
index 00000000000..6c5ffa613d0
--- /dev/null
+++ b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/subdir/go.sum
@@ -0,0 +1,7 @@
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/net v0.0.0-20200505041828-1ed23360d12c h1:zJ0mtu4jCalhKg6Oaukv6iIkb+cOvDrajDH9DH46Q4M=
+golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/subdir/test.go b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/subdir/test.go
new file mode 100644
index 00000000000..afc86ac3a12
--- /dev/null
+++ b/go/ql/integration-tests/all-platforms/go/mixed-layout/src/workspace/subdir/test.go
@@ -0,0 +1,13 @@
+package subdir
+
+import (
+ "fmt"
+
+ "golang.org/x/net/ipv4"
+)
+
+func test() {
+
+ header := ipv4.Header{}
+ fmt.Print(header.String())
+}
diff --git a/go/ql/integration-tests/all-platforms/go/mixed-layout/test.expected b/go/ql/integration-tests/all-platforms/go/mixed-layout/test.expected
new file mode 100644
index 00000000000..ddd1888562f
--- /dev/null
+++ b/go/ql/integration-tests/all-platforms/go/mixed-layout/test.expected
@@ -0,0 +1,8 @@
+extractedFiles
+| src/module/go.mod:0:0:0:0 | src/module/go.mod |
+| src/module/test.go:0:0:0:0 | src/module/test.go |
+| src/stray-files/go.mod:0:0:0:0 | src/stray-files/go.mod |
+| src/stray-files/test.go:0:0:0:0 | src/stray-files/test.go |
+| src/workspace/subdir/go.mod:0:0:0:0 | src/workspace/subdir/go.mod |
+| src/workspace/subdir/test.go:0:0:0:0 | src/workspace/subdir/test.go |
+#select
diff --git a/go/ql/integration-tests/all-platforms/go/mixed-layout/test.py b/go/ql/integration-tests/all-platforms/go/mixed-layout/test.py
new file mode 100644
index 00000000000..43c7d1b38e8
--- /dev/null
+++ b/go/ql/integration-tests/all-platforms/go/mixed-layout/test.py
@@ -0,0 +1,18 @@
+import os
+import subprocess
+
+from create_database_utils import *
+from diagnostics_test_utils import *
+
+# Set up a GOPATH relative to this test's root directory;
+# we set os.environ instead of using extra_env because we
+# need it to be set for the call to "go clean -modcache" later
+goPath = os.path.join(os.path.abspath(os.getcwd()), ".go")
+os.environ['GOPATH'] = goPath
+run_codeql_database_create([], lang="go", source="src")
+
+check_diagnostics()
+
+# Clean up the temporary GOPATH to prevent Bazel failures next
+# time the tests are run; see https://github.com/golang/go/issues/27161
+subprocess.call(["go", "clean", "-modcache"])
diff --git a/go/ql/integration-tests/all-platforms/go/mixed-layout/test.ql b/go/ql/integration-tests/all-platforms/go/mixed-layout/test.ql
new file mode 100644
index 00000000000..459a4301560
--- /dev/null
+++ b/go/ql/integration-tests/all-platforms/go/mixed-layout/test.ql
@@ -0,0 +1,8 @@
+import go
+import semmle.go.DiagnosticsReporting
+
+query predicate extractedFiles(File f) { any() }
+
+from string msg, int sev
+where reportableDiagnostics(_, msg, sev)
+select msg, sev
From 40ff75db07a66f4663ba00b7d76ea8d7ff870aa6 Mon Sep 17 00:00:00 2001
From: "Michael B. Gale"
Date: Tue, 5 Mar 2024 14:56:51 +0000
Subject: [PATCH 027/497] Go: Update list of expected files for
`single-go-mod-and-go-files-not-under-it` test
---
.../go/single-go-mod-and-go-files-not-under-it/test.expected | 2 --
1 file changed, 2 deletions(-)
diff --git a/go/ql/integration-tests/all-platforms/go/single-go-mod-and-go-files-not-under-it/test.expected b/go/ql/integration-tests/all-platforms/go/single-go-mod-and-go-files-not-under-it/test.expected
index 957d2f845a4..66ba3ef588f 100644
--- a/go/ql/integration-tests/all-platforms/go/single-go-mod-and-go-files-not-under-it/test.expected
+++ b/go/ql/integration-tests/all-platforms/go/single-go-mod-and-go-files-not-under-it/test.expected
@@ -1,6 +1,4 @@
extractedFiles
-| src/go.mod:0:0:0:0 | src/go.mod |
-| src/main.go:0:0:0:0 | src/main.go |
| src/subdir/go.mod:0:0:0:0 | src/subdir/go.mod |
| src/subdir/subsubdir/add.go:0:0:0:0 | src/subdir/subsubdir/add.go |
| src/subdir/test.go:0:0:0:0 | src/subdir/test.go |
From 967963a6534b1fcdda3d4f5b6960c29346516303 Mon Sep 17 00:00:00 2001
From: Angela P Wen
Date: Tue, 5 Mar 2024 08:53:33 -0800
Subject: [PATCH 028/497] Revert "Release preparation for version 2.16.4"
---
cpp/ql/lib/CHANGELOG.md | 6 ------
....12.7.md => 2024-02-26-ir-named-destructors.md} | 9 ++++-----
cpp/ql/lib/codeql-pack.release.yml | 2 +-
cpp/ql/lib/qlpack.yml | 2 +-
cpp/ql/src/CHANGELOG.md | 7 -------
...=> 2024-02-16-modelled-functions-block-flow.md} | 8 +++-----
.../2024-02-29-non-constant-format-path-query.md | 4 ++++
cpp/ql/src/codeql-pack.release.yml | 2 +-
cpp/ql/src/qlpack.yml | 2 +-
csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md | 4 ----
.../Solorigate/lib/change-notes/released/1.7.10.md | 3 ---
.../Solorigate/lib/codeql-pack.release.yml | 2 +-
csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +-
csharp/ql/campaigns/Solorigate/src/CHANGELOG.md | 4 ----
.../Solorigate/src/change-notes/released/1.7.10.md | 3 ---
.../Solorigate/src/codeql-pack.release.yml | 2 +-
csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +-
csharp/ql/lib/CHANGELOG.md | 14 --------------
.../change-notes/2024-02-21-getonly-properties.md | 4 ++++
.../ql/lib/change-notes/2024-02-22-no-db-stats.md | 4 ++++
.../change-notes/2024-02-23-compiler-generated.md | 4 ++++
.../2024-02-26-variable-capture-flow.md | 4 ++++
.../2024-02-28-experimental-attribute.md | 4 ++++
.../2024-02-28-refreadonly-parameter.md | 4 ++++
csharp/ql/lib/change-notes/released/0.8.10.md | 13 -------------
csharp/ql/lib/codeql-pack.release.yml | 2 +-
csharp/ql/lib/qlpack.yml | 2 +-
csharp/ql/src/CHANGELOG.md | 6 ------
.../0.8.10.md => 2024-02-06-threat-models.md} | 9 ++++-----
csharp/ql/src/codeql-pack.release.yml | 2 +-
csharp/ql/src/qlpack.yml | 2 +-
go/ql/consistency-queries/CHANGELOG.md | 4 ----
.../change-notes/released/0.0.9.md | 3 ---
go/ql/consistency-queries/codeql-pack.release.yml | 2 +-
go/ql/consistency-queries/qlpack.yml | 2 +-
go/ql/lib/CHANGELOG.md | 11 -----------
.../lib/change-notes/2024-02-14-range-map-read.md | 4 ++++
...0.7.10.md => 2024-03-04-autobuilder-changes.md} | 11 +++--------
go/ql/lib/codeql-pack.release.yml | 2 +-
go/ql/lib/qlpack.yml | 2 +-
go/ql/src/CHANGELOG.md | 4 ----
go/ql/src/change-notes/released/0.7.10.md | 3 ---
go/ql/src/codeql-pack.release.yml | 2 +-
go/ql/src/qlpack.yml | 2 +-
java/ql/automodel/src/CHANGELOG.md | 4 ----
.../automodel/src/change-notes/released/0.0.17.md | 3 ---
java/ql/automodel/src/codeql-pack.release.yml | 2 +-
java/ql/automodel/src/qlpack.yml | 2 +-
java/ql/lib/CHANGELOG.md | 11 -----------
.../change-notes/2024-02-23-widget-flowsteps.md | 4 ++++
java/ql/lib/change-notes/2024-02-27-error-types.md | 4 ++++
.../lib/change-notes/2024-02-27-mvnw-versions.md | 4 ++++
java/ql/lib/change-notes/released/0.8.10.md | 10 ----------
java/ql/lib/codeql-pack.release.yml | 2 +-
java/ql/lib/qlpack.yml | 2 +-
java/ql/src/CHANGELOG.md | 10 ----------
.../2024-02-12-android-insecure-keys.md | 4 ++++
...3-04-sensitive-log-remove-null-from-sources.md} | 11 +++--------
java/ql/src/codeql-pack.release.yml | 2 +-
java/ql/src/qlpack.yml | 2 +-
javascript/ql/lib/CHANGELOG.md | 4 ----
javascript/ql/lib/change-notes/released/0.8.10.md | 3 ---
javascript/ql/lib/codeql-pack.release.yml | 2 +-
javascript/ql/lib/qlpack.yml | 2 +-
javascript/ql/src/CHANGELOG.md | 4 ----
javascript/ql/src/change-notes/released/0.8.10.md | 3 ---
javascript/ql/src/codeql-pack.release.yml | 2 +-
javascript/ql/src/qlpack.yml | 2 +-
misc/suite-helpers/CHANGELOG.md | 4 ----
misc/suite-helpers/change-notes/released/0.7.10.md | 3 ---
misc/suite-helpers/codeql-pack.release.yml | 2 +-
misc/suite-helpers/qlpack.yml | 2 +-
python/ql/lib/CHANGELOG.md | 7 -------
.../2024-02-28-iterable-unpacking-module-scope.md | 4 ++++
....11.10.md => 2024-03-01-dict-update-content.md} | 8 +++-----
python/ql/lib/codeql-pack.release.yml | 2 +-
python/ql/lib/qlpack.yml | 2 +-
python/ql/src/CHANGELOG.md | 6 ------
.../0.9.10.md => 2024-03-04-nosql-injection.md} | 7 +++----
python/ql/src/codeql-pack.release.yml | 2 +-
python/ql/src/qlpack.yml | 2 +-
ruby/ql/lib/CHANGELOG.md | 9 ---------
...2024-02-15-activerecord_connection_sql_sinks.md | 4 ++++
.../2024-02-20-activerecord-sql-sink-arguments.md | 4 ++++
.../lib/change-notes/2024-02-26-arel-sqlliteral.md | 4 ++++
.../lib/change-notes/2024-02-29-i18n-translate.md | 4 ++++
ruby/ql/lib/change-notes/released/0.8.10.md | 8 --------
ruby/ql/lib/codeql-pack.release.yml | 2 +-
ruby/ql/lib/qlpack.yml | 2 +-
ruby/ql/src/CHANGELOG.md | 7 -------
.../2024-02-13-rails-more-request-sources.md | 4 ++++
...d => 2024-03-01-method-code-injection-sinks.md} | 10 ++++------
ruby/ql/src/codeql-pack.release.yml | 2 +-
ruby/ql/src/qlpack.yml | 2 +-
shared/controlflow/CHANGELOG.md | 4 ----
shared/controlflow/change-notes/released/0.1.10.md | 3 ---
shared/controlflow/codeql-pack.release.yml | 2 +-
shared/controlflow/qlpack.yml | 2 +-
shared/dataflow/CHANGELOG.md | 4 ----
shared/dataflow/change-notes/released/0.2.1.md | 3 ---
shared/dataflow/codeql-pack.release.yml | 2 +-
shared/dataflow/qlpack.yml | 2 +-
shared/mad/CHANGELOG.md | 4 ----
shared/mad/change-notes/released/0.2.10.md | 3 ---
shared/mad/codeql-pack.release.yml | 2 +-
shared/mad/qlpack.yml | 2 +-
shared/rangeanalysis/CHANGELOG.md | 4 ----
.../rangeanalysis/change-notes/released/0.0.9.md | 3 ---
shared/rangeanalysis/codeql-pack.release.yml | 2 +-
shared/rangeanalysis/qlpack.yml | 2 +-
shared/regex/CHANGELOG.md | 4 ----
shared/regex/change-notes/released/0.2.10.md | 3 ---
shared/regex/codeql-pack.release.yml | 2 +-
shared/regex/qlpack.yml | 2 +-
shared/ssa/CHANGELOG.md | 4 ----
shared/ssa/change-notes/released/0.2.10.md | 3 ---
shared/ssa/codeql-pack.release.yml | 2 +-
shared/ssa/qlpack.yml | 2 +-
shared/threat-models/CHANGELOG.md | 4 ----
.../threat-models/change-notes/released/0.0.9.md | 3 ---
shared/threat-models/codeql-pack.release.yml | 2 +-
shared/threat-models/qlpack.yml | 2 +-
shared/tutorial/CHANGELOG.md | 4 ----
shared/tutorial/change-notes/released/0.2.10.md | 3 ---
shared/tutorial/codeql-pack.release.yml | 2 +-
shared/tutorial/qlpack.yml | 2 +-
shared/typetracking/CHANGELOG.md | 4 ----
.../typetracking/change-notes/released/0.2.10.md | 3 ---
shared/typetracking/codeql-pack.release.yml | 2 +-
shared/typetracking/qlpack.yml | 2 +-
shared/typos/CHANGELOG.md | 4 ----
shared/typos/change-notes/released/0.2.10.md | 3 ---
shared/typos/codeql-pack.release.yml | 2 +-
shared/typos/qlpack.yml | 2 +-
shared/util/CHANGELOG.md | 4 ----
shared/util/change-notes/released/0.2.10.md | 3 ---
shared/util/codeql-pack.release.yml | 2 +-
shared/util/qlpack.yml | 2 +-
shared/yaml/CHANGELOG.md | 4 ----
shared/yaml/change-notes/released/0.2.10.md | 3 ---
shared/yaml/codeql-pack.release.yml | 2 +-
shared/yaml/qlpack.yml | 2 +-
swift/ql/lib/CHANGELOG.md | 6 ------
.../0.3.10.md => 2024-02-22-extension-patch.md} | 7 +++----
swift/ql/lib/codeql-pack.release.yml | 2 +-
swift/ql/lib/qlpack.yml | 2 +-
swift/ql/src/CHANGELOG.md | 4 ----
swift/ql/src/change-notes/released/0.3.10.md | 3 ---
swift/ql/src/codeql-pack.release.yml | 2 +-
swift/ql/src/qlpack.yml | 2 +-
150 files changed, 168 insertions(+), 394 deletions(-)
rename cpp/ql/lib/change-notes/{released/0.12.7.md => 2024-02-26-ir-named-destructors.md} (54%)
rename cpp/ql/src/change-notes/{released/0.9.6.md => 2024-02-16-modelled-functions-block-flow.md} (77%)
create mode 100644 cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
delete mode 100644 csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
delete mode 100644 csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
create mode 100644 csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
create mode 100644 csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
create mode 100644 csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
create mode 100644 csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
create mode 100644 csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
create mode 100644 csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
delete mode 100644 csharp/ql/lib/change-notes/released/0.8.10.md
rename csharp/ql/src/change-notes/{released/0.8.10.md => 2024-02-06-threat-models.md} (88%)
delete mode 100644 go/ql/consistency-queries/change-notes/released/0.0.9.md
create mode 100644 go/ql/lib/change-notes/2024-02-14-range-map-read.md
rename go/ql/lib/change-notes/{released/0.7.10.md => 2024-03-04-autobuilder-changes.md} (68%)
delete mode 100644 go/ql/src/change-notes/released/0.7.10.md
delete mode 100644 java/ql/automodel/src/change-notes/released/0.0.17.md
create mode 100644 java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
create mode 100644 java/ql/lib/change-notes/2024-02-27-error-types.md
create mode 100644 java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
delete mode 100644 java/ql/lib/change-notes/released/0.8.10.md
create mode 100644 java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
rename java/ql/src/change-notes/{released/0.8.10.md => 2024-03-04-sensitive-log-remove-null-from-sources.md} (54%)
delete mode 100644 javascript/ql/lib/change-notes/released/0.8.10.md
delete mode 100644 javascript/ql/src/change-notes/released/0.8.10.md
delete mode 100644 misc/suite-helpers/change-notes/released/0.7.10.md
create mode 100644 python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
rename python/ql/lib/change-notes/{released/0.11.10.md => 2024-03-01-dict-update-content.md} (52%)
rename python/ql/src/change-notes/{released/0.9.10.md => 2024-03-04-nosql-injection.md} (81%)
create mode 100644 ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
create mode 100644 ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
create mode 100644 ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
create mode 100644 ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
delete mode 100644 ruby/ql/lib/change-notes/released/0.8.10.md
create mode 100644 ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
rename ruby/ql/src/change-notes/{released/0.8.10.md => 2024-03-01-method-code-injection-sinks.md} (51%)
delete mode 100644 shared/controlflow/change-notes/released/0.1.10.md
delete mode 100644 shared/dataflow/change-notes/released/0.2.1.md
delete mode 100644 shared/mad/change-notes/released/0.2.10.md
delete mode 100644 shared/rangeanalysis/change-notes/released/0.0.9.md
delete mode 100644 shared/regex/change-notes/released/0.2.10.md
delete mode 100644 shared/ssa/change-notes/released/0.2.10.md
delete mode 100644 shared/threat-models/change-notes/released/0.0.9.md
delete mode 100644 shared/tutorial/change-notes/released/0.2.10.md
delete mode 100644 shared/typetracking/change-notes/released/0.2.10.md
delete mode 100644 shared/typos/change-notes/released/0.2.10.md
delete mode 100644 shared/util/change-notes/released/0.2.10.md
delete mode 100644 shared/yaml/change-notes/released/0.2.10.md
rename swift/ql/lib/change-notes/{released/0.3.10.md => 2024-02-22-extension-patch.md} (83%)
delete mode 100644 swift/ql/src/change-notes/released/0.3.10.md
diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md
index e1c0dfbecd9..b3091ec37d8 100644
--- a/cpp/ql/lib/CHANGELOG.md
+++ b/cpp/ql/lib/CHANGELOG.md
@@ -1,9 +1,3 @@
-## 0.12.7
-
-### Minor Analysis Improvements
-
-* Added destructors for named objects to the intermediate representation.
-
## 0.12.6
### New Features
diff --git a/cpp/ql/lib/change-notes/released/0.12.7.md b/cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md
similarity index 54%
rename from cpp/ql/lib/change-notes/released/0.12.7.md
rename to cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md
index 856a8b665c7..4e35decaf8e 100644
--- a/cpp/ql/lib/change-notes/released/0.12.7.md
+++ b/cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md
@@ -1,5 +1,4 @@
-## 0.12.7
-
-### Minor Analysis Improvements
-
-* Added destructors for named objects to the intermediate representation.
+---
+category: minorAnalysis
+---
+* Added destructors for named objects to the intermediate representation.
\ No newline at end of file
diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml
index 20419e9c610..170a312c104 100644
--- a/cpp/ql/lib/codeql-pack.release.yml
+++ b/cpp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.12.7
+lastReleaseVersion: 0.12.6
diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml
index 3bb9229bf94..8e201fff594 100644
--- a/cpp/ql/lib/qlpack.yml
+++ b/cpp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-all
-version: 0.12.7
+version: 0.12.7-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md
index f6acd424bb0..ffcd73ff5d7 100644
--- a/cpp/ql/src/CHANGELOG.md
+++ b/cpp/ql/src/CHANGELOG.md
@@ -1,10 +1,3 @@
-## 0.9.6
-
-### Minor Analysis Improvements
-
-* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
-* The new C/C++ dataflow and taint-tracking libraries (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`) now implicitly assume that dataflow and taint modelled via `DataFlowFunction` and `TaintFunction` always fully overwrite their buffers and thus act as flow barriers. As a result, many dataflow and taint-tracking queries now produce fewer false positives. To remove this assumption and go back to the previous behavior for a given model, one can override the new `isPartialWrite` predicate.
-
## 0.9.5
### Minor Analysis Improvements
diff --git a/cpp/ql/src/change-notes/released/0.9.6.md b/cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md
similarity index 77%
rename from cpp/ql/src/change-notes/released/0.9.6.md
rename to cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md
index 0c85f3f9f0f..d6ef3c3e056 100644
--- a/cpp/ql/src/change-notes/released/0.9.6.md
+++ b/cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md
@@ -1,6 +1,4 @@
-## 0.9.6
-
-### Minor Analysis Improvements
-
-* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
+---
+category: minorAnalysis
+---
* The new C/C++ dataflow and taint-tracking libraries (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`) now implicitly assume that dataflow and taint modelled via `DataFlowFunction` and `TaintFunction` always fully overwrite their buffers and thus act as flow barriers. As a result, many dataflow and taint-tracking queries now produce fewer false positives. To remove this assumption and go back to the previous behavior for a given model, one can override the new `isPartialWrite` predicate.
diff --git a/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md b/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
new file mode 100644
index 00000000000..2e5933a61e8
--- /dev/null
+++ b/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
\ No newline at end of file
diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml
index 19139c132b2..460240feaff 100644
--- a/cpp/ql/src/codeql-pack.release.yml
+++ b/cpp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.9.6
+lastReleaseVersion: 0.9.5
diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml
index 4052647bb97..31bd20166b2 100644
--- a/cpp/ql/src/qlpack.yml
+++ b/cpp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-queries
-version: 0.9.6
+version: 0.9.6-dev
groups:
- cpp
- queries
diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
index 82eacfc84f7..190b83b0f25 100644
--- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
+++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 1.7.10
-
-No user-facing changes.
-
## 1.7.9
No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
deleted file mode 100644
index 8e8007d8475..00000000000
--- a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 1.7.10
-
-No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
index 31c7fe07020..678da6bc37e 100644
--- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
+++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.7.10
+lastReleaseVersion: 1.7.9
diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
index ee993bed0c9..7e643b0fac3 100644
--- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
-version: 1.7.10
+version: 1.7.10-dev
groups:
- csharp
- solorigate
diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
index 82eacfc84f7..190b83b0f25 100644
--- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
+++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 1.7.10
-
-No user-facing changes.
-
## 1.7.9
No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
deleted file mode 100644
index 8e8007d8475..00000000000
--- a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 1.7.10
-
-No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
index 31c7fe07020..678da6bc37e 100644
--- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
+++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.7.10
+lastReleaseVersion: 1.7.9
diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
index 1f421754fc8..8654bbfd031 100644
--- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
-version: 1.7.10
+version: 1.7.10-dev
groups:
- csharp
- solorigate
diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md
index 16cc14259e1..95fd64c5270 100644
--- a/csharp/ql/lib/CHANGELOG.md
+++ b/csharp/ql/lib/CHANGELOG.md
@@ -1,17 +1,3 @@
-## 0.8.10
-
-### Major Analysis Improvements
-
-* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
-* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
-
-### Minor Analysis Improvements
-
-* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
-* C# 12: Add extractor and QL library support for `ref readonly` parameters.
-* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
-* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
-
## 0.8.9
### Minor Analysis Improvements
diff --git a/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md b/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
new file mode 100644
index 00000000000..6bb8e99c71e
--- /dev/null
+++ b/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
diff --git a/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md b/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
new file mode 100644
index 00000000000..d6ffbd523ac
--- /dev/null
+++ b/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
@@ -0,0 +1,4 @@
+---
+category: majorAnalysis
+---
+* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
diff --git a/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md b/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
new file mode 100644
index 00000000000..9b1739b9b6d
--- /dev/null
+++ b/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
diff --git a/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md b/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
new file mode 100644
index 00000000000..66ab65083dc
--- /dev/null
+++ b/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
@@ -0,0 +1,4 @@
+---
+category: majorAnalysis
+---
+* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
\ No newline at end of file
diff --git a/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md b/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
new file mode 100644
index 00000000000..8749c790954
--- /dev/null
+++ b/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
diff --git a/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md b/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
new file mode 100644
index 00000000000..586b5341d29
--- /dev/null
+++ b/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* C# 12: Add extractor and QL library support for `ref readonly` parameters.
diff --git a/csharp/ql/lib/change-notes/released/0.8.10.md b/csharp/ql/lib/change-notes/released/0.8.10.md
deleted file mode 100644
index f591ddc5b21..00000000000
--- a/csharp/ql/lib/change-notes/released/0.8.10.md
+++ /dev/null
@@ -1,13 +0,0 @@
-## 0.8.10
-
-### Major Analysis Improvements
-
-* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
-* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
-
-### Minor Analysis Improvements
-
-* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
-* C# 12: Add extractor and QL library support for `ref readonly` parameters.
-* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
-* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/csharp/ql/lib/codeql-pack.release.yml
+++ b/csharp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml
index 93c5c1120a2..d75ea3c6320 100644
--- a/csharp/ql/lib/qlpack.yml
+++ b/csharp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-all
-version: 0.8.10
+version: 0.8.10-dev
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp
diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md
index 46c939e5cee..9fe1609363f 100644
--- a/csharp/ql/src/CHANGELOG.md
+++ b/csharp/ql/src/CHANGELOG.md
@@ -1,9 +1,3 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
-
## 0.8.9
### Minor Analysis Improvements
diff --git a/csharp/ql/src/change-notes/released/0.8.10.md b/csharp/ql/src/change-notes/2024-02-06-threat-models.md
similarity index 88%
rename from csharp/ql/src/change-notes/released/0.8.10.md
rename to csharp/ql/src/change-notes/2024-02-06-threat-models.md
index 702161c3d28..69ac4e4dc17 100644
--- a/csharp/ql/src/change-notes/released/0.8.10.md
+++ b/csharp/ql/src/change-notes/2024-02-06-threat-models.md
@@ -1,5 +1,4 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
+---
+category: minorAnalysis
+---
+* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
\ No newline at end of file
diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/csharp/ql/src/codeql-pack.release.yml
+++ b/csharp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml
index 46384094b19..9ee23cc7307 100644
--- a/csharp/ql/src/qlpack.yml
+++ b/csharp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-queries
-version: 0.8.10
+version: 0.8.10-dev
groups:
- csharp
- queries
diff --git a/go/ql/consistency-queries/CHANGELOG.md b/go/ql/consistency-queries/CHANGELOG.md
index a59e560c415..fba2a870356 100644
--- a/go/ql/consistency-queries/CHANGELOG.md
+++ b/go/ql/consistency-queries/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.0.9
-
-No user-facing changes.
-
## 0.0.8
No user-facing changes.
diff --git a/go/ql/consistency-queries/change-notes/released/0.0.9.md b/go/ql/consistency-queries/change-notes/released/0.0.9.md
deleted file mode 100644
index c9e17c6d6cf..00000000000
--- a/go/ql/consistency-queries/change-notes/released/0.0.9.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.0.9
-
-No user-facing changes.
diff --git a/go/ql/consistency-queries/codeql-pack.release.yml b/go/ql/consistency-queries/codeql-pack.release.yml
index ecdd64fbab8..58fdc6b45de 100644
--- a/go/ql/consistency-queries/codeql-pack.release.yml
+++ b/go/ql/consistency-queries/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.9
+lastReleaseVersion: 0.0.8
diff --git a/go/ql/consistency-queries/qlpack.yml b/go/ql/consistency-queries/qlpack.yml
index d5a2fbee5f1..b574796b995 100644
--- a/go/ql/consistency-queries/qlpack.yml
+++ b/go/ql/consistency-queries/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql-go-consistency-queries
-version: 0.0.9
+version: 0.0.9-dev
groups:
- go
- queries
diff --git a/go/ql/lib/CHANGELOG.md b/go/ql/lib/CHANGELOG.md
index fee5fd37a26..65a2376217b 100644
--- a/go/ql/lib/CHANGELOG.md
+++ b/go/ql/lib/CHANGELOG.md
@@ -1,14 +1,3 @@
-## 0.7.10
-
-### Major Analysis Improvements
-
-* We have significantly improved the Go autobuilder to understand a greater range of project layouts, which allows Go source files to be analysed that could previously not be processed.
-* Go 1.22 has been included in the range of supported Go versions.
-
-### Bug Fixes
-
-* Fixed dataflow out of a `map` using a `range` statement.
-
## 0.7.9
No user-facing changes.
diff --git a/go/ql/lib/change-notes/2024-02-14-range-map-read.md b/go/ql/lib/change-notes/2024-02-14-range-map-read.md
new file mode 100644
index 00000000000..ea45737a72e
--- /dev/null
+++ b/go/ql/lib/change-notes/2024-02-14-range-map-read.md
@@ -0,0 +1,4 @@
+---
+category: fix
+---
+* Fixed dataflow out of a `map` using a `range` statement.
diff --git a/go/ql/lib/change-notes/released/0.7.10.md b/go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md
similarity index 68%
rename from go/ql/lib/change-notes/released/0.7.10.md
rename to go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md
index 55954f8a394..0442a571029 100644
--- a/go/ql/lib/change-notes/released/0.7.10.md
+++ b/go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md
@@ -1,10 +1,5 @@
-## 0.7.10
-
-### Major Analysis Improvements
-
+---
+category: majorAnalysis
+---
* We have significantly improved the Go autobuilder to understand a greater range of project layouts, which allows Go source files to be analysed that could previously not be processed.
* Go 1.22 has been included in the range of supported Go versions.
-
-### Bug Fixes
-
-* Fixed dataflow out of a `map` using a `range` statement.
diff --git a/go/ql/lib/codeql-pack.release.yml b/go/ql/lib/codeql-pack.release.yml
index 67518567297..576395f3405 100644
--- a/go/ql/lib/codeql-pack.release.yml
+++ b/go/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.10
+lastReleaseVersion: 0.7.9
diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml
index 8cc190fa880..f21e478efa6 100644
--- a/go/ql/lib/qlpack.yml
+++ b/go/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/go-all
-version: 0.7.10
+version: 0.7.10-dev
groups: go
dbscheme: go.dbscheme
extractor: go
diff --git a/go/ql/src/CHANGELOG.md b/go/ql/src/CHANGELOG.md
index 24e38b9890e..d95165a3a34 100644
--- a/go/ql/src/CHANGELOG.md
+++ b/go/ql/src/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.7.10
-
-No user-facing changes.
-
## 0.7.9
### New Queries
diff --git a/go/ql/src/change-notes/released/0.7.10.md b/go/ql/src/change-notes/released/0.7.10.md
deleted file mode 100644
index 989c5b8f682..00000000000
--- a/go/ql/src/change-notes/released/0.7.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.7.10
-
-No user-facing changes.
diff --git a/go/ql/src/codeql-pack.release.yml b/go/ql/src/codeql-pack.release.yml
index 67518567297..576395f3405 100644
--- a/go/ql/src/codeql-pack.release.yml
+++ b/go/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.10
+lastReleaseVersion: 0.7.9
diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml
index 4ded3a52f63..d91cab59612 100644
--- a/go/ql/src/qlpack.yml
+++ b/go/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/go-queries
-version: 0.7.10
+version: 0.7.10-dev
groups:
- go
- queries
diff --git a/java/ql/automodel/src/CHANGELOG.md b/java/ql/automodel/src/CHANGELOG.md
index c3282c773a9..4a3c54adb38 100644
--- a/java/ql/automodel/src/CHANGELOG.md
+++ b/java/ql/automodel/src/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.0.17
-
-No user-facing changes.
-
## 0.0.16
No user-facing changes.
diff --git a/java/ql/automodel/src/change-notes/released/0.0.17.md b/java/ql/automodel/src/change-notes/released/0.0.17.md
deleted file mode 100644
index 62cc89030a6..00000000000
--- a/java/ql/automodel/src/change-notes/released/0.0.17.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.0.17
-
-No user-facing changes.
diff --git a/java/ql/automodel/src/codeql-pack.release.yml b/java/ql/automodel/src/codeql-pack.release.yml
index cbc3d3cd493..a49f7be4cff 100644
--- a/java/ql/automodel/src/codeql-pack.release.yml
+++ b/java/ql/automodel/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.17
+lastReleaseVersion: 0.0.16
diff --git a/java/ql/automodel/src/qlpack.yml b/java/ql/automodel/src/qlpack.yml
index 59fab0cdcc5..898239be098 100644
--- a/java/ql/automodel/src/qlpack.yml
+++ b/java/ql/automodel/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-automodel-queries
-version: 0.0.17
+version: 0.0.17-dev
groups:
- java
- automodel
diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md
index 2a02ccee6ab..d369cbdc931 100644
--- a/java/ql/lib/CHANGELOG.md
+++ b/java/ql/lib/CHANGELOG.md
@@ -1,14 +1,3 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
-
-### Bug Fixes
-
-* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
-* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
-
## 0.8.9
### Deprecated APIs
diff --git a/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md b/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
new file mode 100644
index 00000000000..eb560fba07d
--- /dev/null
+++ b/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
@@ -0,0 +1,4 @@
+---
+category: fix
+---
+* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
diff --git a/java/ql/lib/change-notes/2024-02-27-error-types.md b/java/ql/lib/change-notes/2024-02-27-error-types.md
new file mode 100644
index 00000000000..cdc6d7620aa
--- /dev/null
+++ b/java/ql/lib/change-notes/2024-02-27-error-types.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
diff --git a/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md b/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
new file mode 100644
index 00000000000..a0227088ae9
--- /dev/null
+++ b/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
@@ -0,0 +1,4 @@
+---
+category: fix
+---
+* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
diff --git a/java/ql/lib/change-notes/released/0.8.10.md b/java/ql/lib/change-notes/released/0.8.10.md
deleted file mode 100644
index b45f14bf347..00000000000
--- a/java/ql/lib/change-notes/released/0.8.10.md
+++ /dev/null
@@ -1,10 +0,0 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
-
-### Bug Fixes
-
-* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
-* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
diff --git a/java/ql/lib/codeql-pack.release.yml b/java/ql/lib/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/java/ql/lib/codeql-pack.release.yml
+++ b/java/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml
index 428eedc75e3..15b4982d41e 100644
--- a/java/ql/lib/qlpack.yml
+++ b/java/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-all
-version: 0.8.10
+version: 0.8.10-dev
groups: java
dbscheme: config/semmlecode.dbscheme
extractor: java
diff --git a/java/ql/src/CHANGELOG.md b/java/ql/src/CHANGELOG.md
index c61275f5ed8..5d835351453 100644
--- a/java/ql/src/CHANGELOG.md
+++ b/java/ql/src/CHANGELOG.md
@@ -1,13 +1,3 @@
-## 0.8.10
-
-### New Queries
-
-* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
-
-### Minor Analysis Improvements
-
-* To reduce the number of false positives in the query "Insertion of sensitive information into log files" (`java/sensitive-log`), variables with names that contain "null" (case-insensitively) are no longer considered sources of sensitive information.
-
## 0.8.9
### New Queries
diff --git a/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md b/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
new file mode 100644
index 00000000000..1de07727796
--- /dev/null
+++ b/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
@@ -0,0 +1,4 @@
+---
+category: newQuery
+---
+* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
\ No newline at end of file
diff --git a/java/ql/src/change-notes/released/0.8.10.md b/java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md
similarity index 54%
rename from java/ql/src/change-notes/released/0.8.10.md
rename to java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md
index c5d18ae3379..0bb4f18f2bd 100644
--- a/java/ql/src/change-notes/released/0.8.10.md
+++ b/java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md
@@ -1,9 +1,4 @@
-## 0.8.10
-
-### New Queries
-
-* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
-
-### Minor Analysis Improvements
-
+---
+category: minorAnalysis
+---
* To reduce the number of false positives in the query "Insertion of sensitive information into log files" (`java/sensitive-log`), variables with names that contain "null" (case-insensitively) are no longer considered sources of sensitive information.
diff --git a/java/ql/src/codeql-pack.release.yml b/java/ql/src/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/java/ql/src/codeql-pack.release.yml
+++ b/java/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml
index ebbdbeee3b2..8f4de528e21 100644
--- a/java/ql/src/qlpack.yml
+++ b/java/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-queries
-version: 0.8.10
+version: 0.8.10-dev
groups:
- java
- queries
diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md
index d5edcc00513..5b97ebbb22b 100644
--- a/javascript/ql/lib/CHANGELOG.md
+++ b/javascript/ql/lib/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.8.10
-
-No user-facing changes.
-
## 0.8.9
### Minor Analysis Improvements
diff --git a/javascript/ql/lib/change-notes/released/0.8.10.md b/javascript/ql/lib/change-notes/released/0.8.10.md
deleted file mode 100644
index 777bbd2fded..00000000000
--- a/javascript/ql/lib/change-notes/released/0.8.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.8.10
-
-No user-facing changes.
diff --git a/javascript/ql/lib/codeql-pack.release.yml b/javascript/ql/lib/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/javascript/ql/lib/codeql-pack.release.yml
+++ b/javascript/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml
index da16493a21c..ef3ca7521ac 100644
--- a/javascript/ql/lib/qlpack.yml
+++ b/javascript/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-all
-version: 0.8.10
+version: 0.8.10-dev
groups: javascript
dbscheme: semmlecode.javascript.dbscheme
extractor: javascript
diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md
index b9627cac5ee..85516e3625d 100644
--- a/javascript/ql/src/CHANGELOG.md
+++ b/javascript/ql/src/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.8.10
-
-No user-facing changes.
-
## 0.8.9
### Bug Fixes
diff --git a/javascript/ql/src/change-notes/released/0.8.10.md b/javascript/ql/src/change-notes/released/0.8.10.md
deleted file mode 100644
index 777bbd2fded..00000000000
--- a/javascript/ql/src/change-notes/released/0.8.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.8.10
-
-No user-facing changes.
diff --git a/javascript/ql/src/codeql-pack.release.yml b/javascript/ql/src/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/javascript/ql/src/codeql-pack.release.yml
+++ b/javascript/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml
index d224952c564..b6181aa30e9 100644
--- a/javascript/ql/src/qlpack.yml
+++ b/javascript/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-queries
-version: 0.8.10
+version: 0.8.10-dev
groups:
- javascript
- queries
diff --git a/misc/suite-helpers/CHANGELOG.md b/misc/suite-helpers/CHANGELOG.md
index 1c4455b66c4..3c06dd69b0f 100644
--- a/misc/suite-helpers/CHANGELOG.md
+++ b/misc/suite-helpers/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.7.10
-
-No user-facing changes.
-
## 0.7.9
No user-facing changes.
diff --git a/misc/suite-helpers/change-notes/released/0.7.10.md b/misc/suite-helpers/change-notes/released/0.7.10.md
deleted file mode 100644
index 989c5b8f682..00000000000
--- a/misc/suite-helpers/change-notes/released/0.7.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.7.10
-
-No user-facing changes.
diff --git a/misc/suite-helpers/codeql-pack.release.yml b/misc/suite-helpers/codeql-pack.release.yml
index 67518567297..576395f3405 100644
--- a/misc/suite-helpers/codeql-pack.release.yml
+++ b/misc/suite-helpers/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.10
+lastReleaseVersion: 0.7.9
diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml
index 54d978d5efe..49b7a6bda4c 100644
--- a/misc/suite-helpers/qlpack.yml
+++ b/misc/suite-helpers/qlpack.yml
@@ -1,4 +1,4 @@
name: codeql/suite-helpers
-version: 0.7.10
+version: 0.7.10-dev
groups: shared
warnOnImplicitThis: true
diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md
index f095607ca1b..e6f318c51ea 100644
--- a/python/ql/lib/CHANGELOG.md
+++ b/python/ql/lib/CHANGELOG.md
@@ -1,10 +1,3 @@
-## 0.11.10
-
-### Minor Analysis Improvements
-
-* Fixed missing flow for dictionary updates (`d[] = ...`) when `` is a string constant not used in dictionary literals or as name of keyword-argument.
-* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
-
## 0.11.9
### Minor Analysis Improvements
diff --git a/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md b/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
new file mode 100644
index 00000000000..3c47c6ba866
--- /dev/null
+++ b/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
diff --git a/python/ql/lib/change-notes/released/0.11.10.md b/python/ql/lib/change-notes/2024-03-01-dict-update-content.md
similarity index 52%
rename from python/ql/lib/change-notes/released/0.11.10.md
rename to python/ql/lib/change-notes/2024-03-01-dict-update-content.md
index ed873724e4f..dfb8d247fff 100644
--- a/python/ql/lib/change-notes/released/0.11.10.md
+++ b/python/ql/lib/change-notes/2024-03-01-dict-update-content.md
@@ -1,6 +1,4 @@
-## 0.11.10
-
-### Minor Analysis Improvements
-
+---
+category: minorAnalysis
+---
* Fixed missing flow for dictionary updates (`d[] = ...`) when `` is a string constant not used in dictionary literals or as name of keyword-argument.
-* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
diff --git a/python/ql/lib/codeql-pack.release.yml b/python/ql/lib/codeql-pack.release.yml
index ddddcbe9193..b064d1778a1 100644
--- a/python/ql/lib/codeql-pack.release.yml
+++ b/python/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.11.10
+lastReleaseVersion: 0.11.9
diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml
index 59a8b4c96d1..e9f66e205f2 100644
--- a/python/ql/lib/qlpack.yml
+++ b/python/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/python-all
-version: 0.11.10
+version: 0.11.10-dev
groups: python
dbscheme: semmlecode.python.dbscheme
extractor: python
diff --git a/python/ql/src/CHANGELOG.md b/python/ql/src/CHANGELOG.md
index d4245aba7a6..50762bcbf34 100644
--- a/python/ql/src/CHANGELOG.md
+++ b/python/ql/src/CHANGELOG.md
@@ -1,9 +1,3 @@
-## 0.9.10
-
-### New Queries
-
-* The query `py/nosql-injection` for finding NoSQL injection vulnerabilities is now part of the default security suite.
-
## 0.9.9
No user-facing changes.
diff --git a/python/ql/src/change-notes/released/0.9.10.md b/python/ql/src/change-notes/2024-03-04-nosql-injection.md
similarity index 81%
rename from python/ql/src/change-notes/released/0.9.10.md
rename to python/ql/src/change-notes/2024-03-04-nosql-injection.md
index 4cbb221b789..6e98540c757 100644
--- a/python/ql/src/change-notes/released/0.9.10.md
+++ b/python/ql/src/change-notes/2024-03-04-nosql-injection.md
@@ -1,5 +1,4 @@
-## 0.9.10
-
-### New Queries
-
+---
+category: newQuery
+---
* The query `py/nosql-injection` for finding NoSQL injection vulnerabilities is now part of the default security suite.
diff --git a/python/ql/src/codeql-pack.release.yml b/python/ql/src/codeql-pack.release.yml
index d086ed69541..aabed7c396b 100644
--- a/python/ql/src/codeql-pack.release.yml
+++ b/python/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.9.10
+lastReleaseVersion: 0.9.9
diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml
index c920f667836..aa18f2d8707 100644
--- a/python/ql/src/qlpack.yml
+++ b/python/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/python-queries
-version: 0.9.10
+version: 0.9.10-dev
groups:
- python
- queries
diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md
index c61a12e0f4a..a623a151e89 100644
--- a/ruby/ql/lib/CHANGELOG.md
+++ b/ruby/ql/lib/CHANGELOG.md
@@ -1,12 +1,3 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
-* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
-* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
-* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
-
## 0.8.9
### Minor Analysis Improvements
diff --git a/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md b/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
new file mode 100644
index 00000000000..c2276f284a8
--- /dev/null
+++ b/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md b/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
new file mode 100644
index 00000000000..1486c7a472d
--- /dev/null
+++ b/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md b/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
new file mode 100644
index 00000000000..6f3a90768ba
--- /dev/null
+++ b/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md b/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
new file mode 100644
index 00000000000..350e049b5bf
--- /dev/null
+++ b/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/released/0.8.10.md b/ruby/ql/lib/change-notes/released/0.8.10.md
deleted file mode 100644
index 666e28f840e..00000000000
--- a/ruby/ql/lib/change-notes/released/0.8.10.md
+++ /dev/null
@@ -1,8 +0,0 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
-* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
-* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
-* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
diff --git a/ruby/ql/lib/codeql-pack.release.yml b/ruby/ql/lib/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/ruby/ql/lib/codeql-pack.release.yml
+++ b/ruby/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml
index de5b41999fe..7d409b83adb 100644
--- a/ruby/ql/lib/qlpack.yml
+++ b/ruby/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ruby-all
-version: 0.8.10
+version: 0.8.10-dev
groups: ruby
extractor: ruby
dbscheme: ruby.dbscheme
diff --git a/ruby/ql/src/CHANGELOG.md b/ruby/ql/src/CHANGELOG.md
index f875b6d16ad..4149c728eff 100644
--- a/ruby/ql/src/CHANGELOG.md
+++ b/ruby/ql/src/CHANGELOG.md
@@ -1,10 +1,3 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
-* Added additional request sources for Ruby on Rails.
-
## 0.8.9
No user-facing changes.
diff --git a/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md b/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
new file mode 100644
index 00000000000..84ea696dfef
--- /dev/null
+++ b/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Added additional request sources for Ruby on Rails.
\ No newline at end of file
diff --git a/ruby/ql/src/change-notes/released/0.8.10.md b/ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md
similarity index 51%
rename from ruby/ql/src/change-notes/released/0.8.10.md
rename to ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md
index 985cdf8d22e..43e40d3fd53 100644
--- a/ruby/ql/src/change-notes/released/0.8.10.md
+++ b/ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md
@@ -1,6 +1,4 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
-* Added additional request sources for Ruby on Rails.
+---
+category: minorAnalysis
+---
+* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
\ No newline at end of file
diff --git a/ruby/ql/src/codeql-pack.release.yml b/ruby/ql/src/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/ruby/ql/src/codeql-pack.release.yml
+++ b/ruby/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml
index 5e379268234..8af7f9fd797 100644
--- a/ruby/ql/src/qlpack.yml
+++ b/ruby/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ruby-queries
-version: 0.8.10
+version: 0.8.10-dev
groups:
- ruby
- queries
diff --git a/shared/controlflow/CHANGELOG.md b/shared/controlflow/CHANGELOG.md
index 75f2ca53f98..dbfa6ef4512 100644
--- a/shared/controlflow/CHANGELOG.md
+++ b/shared/controlflow/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.1.10
-
-No user-facing changes.
-
## 0.1.9
No user-facing changes.
diff --git a/shared/controlflow/change-notes/released/0.1.10.md b/shared/controlflow/change-notes/released/0.1.10.md
deleted file mode 100644
index 47358eeee93..00000000000
--- a/shared/controlflow/change-notes/released/0.1.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.1.10
-
-No user-facing changes.
diff --git a/shared/controlflow/codeql-pack.release.yml b/shared/controlflow/codeql-pack.release.yml
index 30f5ca88be0..1425c0edf7f 100644
--- a/shared/controlflow/codeql-pack.release.yml
+++ b/shared/controlflow/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.1.10
+lastReleaseVersion: 0.1.9
diff --git a/shared/controlflow/qlpack.yml b/shared/controlflow/qlpack.yml
index 1d43802be42..9d35a678276 100644
--- a/shared/controlflow/qlpack.yml
+++ b/shared/controlflow/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/controlflow
-version: 0.1.10
+version: 0.1.10-dev
groups: shared
library: true
dependencies:
diff --git a/shared/dataflow/CHANGELOG.md b/shared/dataflow/CHANGELOG.md
index ef80788bded..67a5bf589f4 100644
--- a/shared/dataflow/CHANGELOG.md
+++ b/shared/dataflow/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.1
-
-No user-facing changes.
-
## 0.2.0
### Breaking Changes
diff --git a/shared/dataflow/change-notes/released/0.2.1.md b/shared/dataflow/change-notes/released/0.2.1.md
deleted file mode 100644
index 3dbfc85fe11..00000000000
--- a/shared/dataflow/change-notes/released/0.2.1.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.1
-
-No user-facing changes.
diff --git a/shared/dataflow/codeql-pack.release.yml b/shared/dataflow/codeql-pack.release.yml
index df29a726bcc..5274e27ed52 100644
--- a/shared/dataflow/codeql-pack.release.yml
+++ b/shared/dataflow/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.1
+lastReleaseVersion: 0.2.0
diff --git a/shared/dataflow/qlpack.yml b/shared/dataflow/qlpack.yml
index ee422e02ea9..1e7becf71c4 100644
--- a/shared/dataflow/qlpack.yml
+++ b/shared/dataflow/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/dataflow
-version: 0.2.1
+version: 0.2.1-dev
groups: shared
library: true
dependencies:
diff --git a/shared/mad/CHANGELOG.md b/shared/mad/CHANGELOG.md
index 4730366775e..4d09057118c 100644
--- a/shared/mad/CHANGELOG.md
+++ b/shared/mad/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/mad/change-notes/released/0.2.10.md b/shared/mad/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/mad/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/mad/codeql-pack.release.yml b/shared/mad/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/mad/codeql-pack.release.yml
+++ b/shared/mad/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml
index 6d7269ef3da..22c8f271ccc 100644
--- a/shared/mad/qlpack.yml
+++ b/shared/mad/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/mad
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
dependencies: null
diff --git a/shared/rangeanalysis/CHANGELOG.md b/shared/rangeanalysis/CHANGELOG.md
index 9943dcb7972..5b8dbcfab22 100644
--- a/shared/rangeanalysis/CHANGELOG.md
+++ b/shared/rangeanalysis/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.0.9
-
-No user-facing changes.
-
## 0.0.8
No user-facing changes.
diff --git a/shared/rangeanalysis/change-notes/released/0.0.9.md b/shared/rangeanalysis/change-notes/released/0.0.9.md
deleted file mode 100644
index c9e17c6d6cf..00000000000
--- a/shared/rangeanalysis/change-notes/released/0.0.9.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.0.9
-
-No user-facing changes.
diff --git a/shared/rangeanalysis/codeql-pack.release.yml b/shared/rangeanalysis/codeql-pack.release.yml
index ecdd64fbab8..58fdc6b45de 100644
--- a/shared/rangeanalysis/codeql-pack.release.yml
+++ b/shared/rangeanalysis/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.9
+lastReleaseVersion: 0.0.8
diff --git a/shared/rangeanalysis/qlpack.yml b/shared/rangeanalysis/qlpack.yml
index 01db5d5734d..836fe51ee34 100644
--- a/shared/rangeanalysis/qlpack.yml
+++ b/shared/rangeanalysis/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/rangeanalysis
-version: 0.0.9
+version: 0.0.9-dev
groups: shared
library: true
dependencies:
diff --git a/shared/regex/CHANGELOG.md b/shared/regex/CHANGELOG.md
index c05869c153d..cd5f91f71ec 100644
--- a/shared/regex/CHANGELOG.md
+++ b/shared/regex/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/regex/change-notes/released/0.2.10.md b/shared/regex/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/regex/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/regex/codeql-pack.release.yml b/shared/regex/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/regex/codeql-pack.release.yml
+++ b/shared/regex/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml
index 0d4f485312f..ea3f7f9b238 100644
--- a/shared/regex/qlpack.yml
+++ b/shared/regex/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/regex
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
dependencies:
diff --git a/shared/ssa/CHANGELOG.md b/shared/ssa/CHANGELOG.md
index a9161ff578b..01acfae0148 100644
--- a/shared/ssa/CHANGELOG.md
+++ b/shared/ssa/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/ssa/change-notes/released/0.2.10.md b/shared/ssa/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/ssa/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/ssa/codeql-pack.release.yml b/shared/ssa/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/ssa/codeql-pack.release.yml
+++ b/shared/ssa/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml
index 2ad254711a5..19304ad107f 100644
--- a/shared/ssa/qlpack.yml
+++ b/shared/ssa/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ssa
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
dependencies:
diff --git a/shared/threat-models/CHANGELOG.md b/shared/threat-models/CHANGELOG.md
index a59e560c415..fba2a870356 100644
--- a/shared/threat-models/CHANGELOG.md
+++ b/shared/threat-models/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.0.9
-
-No user-facing changes.
-
## 0.0.8
No user-facing changes.
diff --git a/shared/threat-models/change-notes/released/0.0.9.md b/shared/threat-models/change-notes/released/0.0.9.md
deleted file mode 100644
index c9e17c6d6cf..00000000000
--- a/shared/threat-models/change-notes/released/0.0.9.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.0.9
-
-No user-facing changes.
diff --git a/shared/threat-models/codeql-pack.release.yml b/shared/threat-models/codeql-pack.release.yml
index ecdd64fbab8..58fdc6b45de 100644
--- a/shared/threat-models/codeql-pack.release.yml
+++ b/shared/threat-models/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.9
+lastReleaseVersion: 0.0.8
diff --git a/shared/threat-models/qlpack.yml b/shared/threat-models/qlpack.yml
index 60cbbc56fcb..d0ed9a913b2 100644
--- a/shared/threat-models/qlpack.yml
+++ b/shared/threat-models/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/threat-models
-version: 0.0.9
+version: 0.0.9-dev
library: true
groups: shared
dataExtensions:
diff --git a/shared/tutorial/CHANGELOG.md b/shared/tutorial/CHANGELOG.md
index 560ad058d5b..1db3a01af0b 100644
--- a/shared/tutorial/CHANGELOG.md
+++ b/shared/tutorial/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/tutorial/change-notes/released/0.2.10.md b/shared/tutorial/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/tutorial/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/tutorial/codeql-pack.release.yml b/shared/tutorial/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/tutorial/codeql-pack.release.yml
+++ b/shared/tutorial/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml
index 69116705c1b..b595ae9ee70 100644
--- a/shared/tutorial/qlpack.yml
+++ b/shared/tutorial/qlpack.yml
@@ -1,7 +1,7 @@
name: codeql/tutorial
description: Library for the CodeQL detective tutorials, helping new users learn to
write CodeQL queries.
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/shared/typetracking/CHANGELOG.md b/shared/typetracking/CHANGELOG.md
index 350f9ecbeae..afc857bc6bc 100644
--- a/shared/typetracking/CHANGELOG.md
+++ b/shared/typetracking/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/typetracking/change-notes/released/0.2.10.md b/shared/typetracking/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/typetracking/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/typetracking/codeql-pack.release.yml b/shared/typetracking/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/typetracking/codeql-pack.release.yml
+++ b/shared/typetracking/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml
index fbbdcf5162a..b55927f59bb 100644
--- a/shared/typetracking/qlpack.yml
+++ b/shared/typetracking/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/typetracking
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
dependencies:
diff --git a/shared/typos/CHANGELOG.md b/shared/typos/CHANGELOG.md
index 54b1eaa4d58..66c5871d982 100644
--- a/shared/typos/CHANGELOG.md
+++ b/shared/typos/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/typos/change-notes/released/0.2.10.md b/shared/typos/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/typos/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/typos/codeql-pack.release.yml b/shared/typos/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/typos/codeql-pack.release.yml
+++ b/shared/typos/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml
index 4d59d9b3c34..644bfe11bff 100644
--- a/shared/typos/qlpack.yml
+++ b/shared/typos/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/typos
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/shared/util/CHANGELOG.md b/shared/util/CHANGELOG.md
index 1ca1f71bcbc..63832e927fa 100644
--- a/shared/util/CHANGELOG.md
+++ b/shared/util/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/util/change-notes/released/0.2.10.md b/shared/util/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/util/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/util/codeql-pack.release.yml b/shared/util/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/util/codeql-pack.release.yml
+++ b/shared/util/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml
index 28ed738a93d..ca1a866a53d 100644
--- a/shared/util/qlpack.yml
+++ b/shared/util/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/util
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
dependencies: null
diff --git a/shared/yaml/CHANGELOG.md b/shared/yaml/CHANGELOG.md
index 9fd5ebc26ab..e5495abcd50 100644
--- a/shared/yaml/CHANGELOG.md
+++ b/shared/yaml/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/yaml/change-notes/released/0.2.10.md b/shared/yaml/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/yaml/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/yaml/codeql-pack.release.yml b/shared/yaml/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/yaml/codeql-pack.release.yml
+++ b/shared/yaml/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml
index 9643ffcec66..de5b47e120a 100644
--- a/shared/yaml/qlpack.yml
+++ b/shared/yaml/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/yaml
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/swift/ql/lib/CHANGELOG.md b/swift/ql/lib/CHANGELOG.md
index 8f14bfcedc9..e88cd0259cc 100644
--- a/swift/ql/lib/CHANGELOG.md
+++ b/swift/ql/lib/CHANGELOG.md
@@ -1,9 +1,3 @@
-## 0.3.10
-
-### Bug Fixes
-
-* Fixed an issue where `TypeDecl.getFullName` would get stuck in an loop and fail when minor database inconsistencies are present.
-
## 0.3.9
### Minor Analysis Improvements
diff --git a/swift/ql/lib/change-notes/released/0.3.10.md b/swift/ql/lib/change-notes/2024-02-22-extension-patch.md
similarity index 83%
rename from swift/ql/lib/change-notes/released/0.3.10.md
rename to swift/ql/lib/change-notes/2024-02-22-extension-patch.md
index 9d6286ff58a..7bd78f3b785 100644
--- a/swift/ql/lib/change-notes/released/0.3.10.md
+++ b/swift/ql/lib/change-notes/2024-02-22-extension-patch.md
@@ -1,5 +1,4 @@
-## 0.3.10
-
-### Bug Fixes
-
+---
+category: fix
+---
* Fixed an issue where `TypeDecl.getFullName` would get stuck in an loop and fail when minor database inconsistencies are present.
diff --git a/swift/ql/lib/codeql-pack.release.yml b/swift/ql/lib/codeql-pack.release.yml
index 76ca0ac8ba7..3fa5180bcb4 100644
--- a/swift/ql/lib/codeql-pack.release.yml
+++ b/swift/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.3.10
+lastReleaseVersion: 0.3.9
diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml
index 70ec4798ea8..a37a4cb3d58 100644
--- a/swift/ql/lib/qlpack.yml
+++ b/swift/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/swift-all
-version: 0.3.10
+version: 0.3.10-dev
groups: swift
extractor: swift
dbscheme: swift.dbscheme
diff --git a/swift/ql/src/CHANGELOG.md b/swift/ql/src/CHANGELOG.md
index bda9834c9bc..96615d06972 100644
--- a/swift/ql/src/CHANGELOG.md
+++ b/swift/ql/src/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.3.10
-
-No user-facing changes.
-
## 0.3.9
### New Queries
diff --git a/swift/ql/src/change-notes/released/0.3.10.md b/swift/ql/src/change-notes/released/0.3.10.md
deleted file mode 100644
index 925a48fc52e..00000000000
--- a/swift/ql/src/change-notes/released/0.3.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.3.10
-
-No user-facing changes.
diff --git a/swift/ql/src/codeql-pack.release.yml b/swift/ql/src/codeql-pack.release.yml
index 76ca0ac8ba7..3fa5180bcb4 100644
--- a/swift/ql/src/codeql-pack.release.yml
+++ b/swift/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.3.10
+lastReleaseVersion: 0.3.9
diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml
index ba66b065529..e3ead42c98b 100644
--- a/swift/ql/src/qlpack.yml
+++ b/swift/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/swift-queries
-version: 0.3.10
+version: 0.3.10-dev
groups:
- swift
- queries
From 661e68dab5ee8d71edcec82139314a481dd983d5 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Tue, 5 Mar 2024 18:13:58 +0000
Subject: [PATCH 029/497] Release preparation for version 2.16.4
---
cpp/ql/lib/CHANGELOG.md | 6 ++++++
.../0.12.7.md} | 9 +++++----
cpp/ql/lib/codeql-pack.release.yml | 2 +-
cpp/ql/lib/qlpack.yml | 2 +-
cpp/ql/src/CHANGELOG.md | 7 +++++++
.../2024-02-29-non-constant-format-path-query.md | 4 ----
.../0.9.6.md} | 8 +++++---
cpp/ql/src/codeql-pack.release.yml | 2 +-
cpp/ql/src/qlpack.yml | 2 +-
csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md | 4 ++++
.../Solorigate/lib/change-notes/released/1.7.10.md | 3 +++
.../Solorigate/lib/codeql-pack.release.yml | 2 +-
csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +-
csharp/ql/campaigns/Solorigate/src/CHANGELOG.md | 4 ++++
.../Solorigate/src/change-notes/released/1.7.10.md | 3 +++
.../Solorigate/src/codeql-pack.release.yml | 2 +-
csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +-
csharp/ql/lib/CHANGELOG.md | 14 ++++++++++++++
.../change-notes/2024-02-21-getonly-properties.md | 4 ----
.../ql/lib/change-notes/2024-02-22-no-db-stats.md | 4 ----
.../change-notes/2024-02-23-compiler-generated.md | 4 ----
.../2024-02-26-variable-capture-flow.md | 4 ----
.../2024-02-28-experimental-attribute.md | 4 ----
.../2024-02-28-refreadonly-parameter.md | 4 ----
csharp/ql/lib/change-notes/released/0.8.10.md | 13 +++++++++++++
csharp/ql/lib/codeql-pack.release.yml | 2 +-
csharp/ql/lib/qlpack.yml | 2 +-
csharp/ql/src/CHANGELOG.md | 6 ++++++
.../0.8.10.md} | 9 +++++----
csharp/ql/src/codeql-pack.release.yml | 2 +-
csharp/ql/src/qlpack.yml | 2 +-
go/ql/consistency-queries/CHANGELOG.md | 4 ++++
.../change-notes/released/0.0.9.md | 3 +++
go/ql/consistency-queries/codeql-pack.release.yml | 2 +-
go/ql/consistency-queries/qlpack.yml | 2 +-
go/ql/lib/CHANGELOG.md | 11 +++++++++++
.../lib/change-notes/2024-02-14-range-map-read.md | 4 ----
.../0.7.10.md} | 11 ++++++++---
go/ql/lib/codeql-pack.release.yml | 2 +-
go/ql/lib/qlpack.yml | 2 +-
go/ql/src/CHANGELOG.md | 4 ++++
go/ql/src/change-notes/released/0.7.10.md | 3 +++
go/ql/src/codeql-pack.release.yml | 2 +-
go/ql/src/qlpack.yml | 2 +-
java/ql/automodel/src/CHANGELOG.md | 4 ++++
.../automodel/src/change-notes/released/0.0.17.md | 3 +++
java/ql/automodel/src/codeql-pack.release.yml | 2 +-
java/ql/automodel/src/qlpack.yml | 2 +-
java/ql/lib/CHANGELOG.md | 11 +++++++++++
.../change-notes/2024-02-23-widget-flowsteps.md | 4 ----
java/ql/lib/change-notes/2024-02-27-error-types.md | 4 ----
.../lib/change-notes/2024-02-27-mvnw-versions.md | 4 ----
java/ql/lib/change-notes/released/0.8.10.md | 10 ++++++++++
java/ql/lib/codeql-pack.release.yml | 2 +-
java/ql/lib/qlpack.yml | 2 +-
java/ql/src/CHANGELOG.md | 10 ++++++++++
.../2024-02-12-android-insecure-keys.md | 4 ----
.../0.8.10.md} | 11 ++++++++---
java/ql/src/codeql-pack.release.yml | 2 +-
java/ql/src/qlpack.yml | 2 +-
javascript/ql/lib/CHANGELOG.md | 4 ++++
javascript/ql/lib/change-notes/released/0.8.10.md | 3 +++
javascript/ql/lib/codeql-pack.release.yml | 2 +-
javascript/ql/lib/qlpack.yml | 2 +-
javascript/ql/src/CHANGELOG.md | 4 ++++
javascript/ql/src/change-notes/released/0.8.10.md | 3 +++
javascript/ql/src/codeql-pack.release.yml | 2 +-
javascript/ql/src/qlpack.yml | 2 +-
misc/suite-helpers/CHANGELOG.md | 4 ++++
misc/suite-helpers/change-notes/released/0.7.10.md | 3 +++
misc/suite-helpers/codeql-pack.release.yml | 2 +-
misc/suite-helpers/qlpack.yml | 2 +-
python/ql/lib/CHANGELOG.md | 7 +++++++
.../2024-02-28-iterable-unpacking-module-scope.md | 4 ----
.../0.11.10.md} | 8 +++++---
python/ql/lib/codeql-pack.release.yml | 2 +-
python/ql/lib/qlpack.yml | 2 +-
python/ql/src/CHANGELOG.md | 6 ++++++
.../0.9.10.md} | 7 ++++---
python/ql/src/codeql-pack.release.yml | 2 +-
python/ql/src/qlpack.yml | 2 +-
ruby/ql/lib/CHANGELOG.md | 9 +++++++++
...2024-02-15-activerecord_connection_sql_sinks.md | 4 ----
.../2024-02-20-activerecord-sql-sink-arguments.md | 4 ----
.../lib/change-notes/2024-02-26-arel-sqlliteral.md | 4 ----
.../lib/change-notes/2024-02-29-i18n-translate.md | 4 ----
ruby/ql/lib/change-notes/released/0.8.10.md | 8 ++++++++
ruby/ql/lib/codeql-pack.release.yml | 2 +-
ruby/ql/lib/qlpack.yml | 2 +-
ruby/ql/src/CHANGELOG.md | 7 +++++++
.../2024-02-13-rails-more-request-sources.md | 4 ----
.../0.8.10.md} | 10 ++++++----
ruby/ql/src/codeql-pack.release.yml | 2 +-
ruby/ql/src/qlpack.yml | 2 +-
shared/controlflow/CHANGELOG.md | 4 ++++
shared/controlflow/change-notes/released/0.1.10.md | 3 +++
shared/controlflow/codeql-pack.release.yml | 2 +-
shared/controlflow/qlpack.yml | 2 +-
shared/dataflow/CHANGELOG.md | 4 ++++
shared/dataflow/change-notes/released/0.2.1.md | 3 +++
shared/dataflow/codeql-pack.release.yml | 2 +-
shared/dataflow/qlpack.yml | 2 +-
shared/mad/CHANGELOG.md | 4 ++++
shared/mad/change-notes/released/0.2.10.md | 3 +++
shared/mad/codeql-pack.release.yml | 2 +-
shared/mad/qlpack.yml | 2 +-
shared/rangeanalysis/CHANGELOG.md | 4 ++++
.../rangeanalysis/change-notes/released/0.0.9.md | 3 +++
shared/rangeanalysis/codeql-pack.release.yml | 2 +-
shared/rangeanalysis/qlpack.yml | 2 +-
shared/regex/CHANGELOG.md | 4 ++++
shared/regex/change-notes/released/0.2.10.md | 3 +++
shared/regex/codeql-pack.release.yml | 2 +-
shared/regex/qlpack.yml | 2 +-
shared/ssa/CHANGELOG.md | 4 ++++
shared/ssa/change-notes/released/0.2.10.md | 3 +++
shared/ssa/codeql-pack.release.yml | 2 +-
shared/ssa/qlpack.yml | 2 +-
shared/threat-models/CHANGELOG.md | 4 ++++
.../threat-models/change-notes/released/0.0.9.md | 3 +++
shared/threat-models/codeql-pack.release.yml | 2 +-
shared/threat-models/qlpack.yml | 2 +-
shared/tutorial/CHANGELOG.md | 4 ++++
shared/tutorial/change-notes/released/0.2.10.md | 3 +++
shared/tutorial/codeql-pack.release.yml | 2 +-
shared/tutorial/qlpack.yml | 2 +-
shared/typetracking/CHANGELOG.md | 4 ++++
.../typetracking/change-notes/released/0.2.10.md | 3 +++
shared/typetracking/codeql-pack.release.yml | 2 +-
shared/typetracking/qlpack.yml | 2 +-
shared/typos/CHANGELOG.md | 4 ++++
shared/typos/change-notes/released/0.2.10.md | 3 +++
shared/typos/codeql-pack.release.yml | 2 +-
shared/typos/qlpack.yml | 2 +-
shared/util/CHANGELOG.md | 4 ++++
shared/util/change-notes/released/0.2.10.md | 3 +++
shared/util/codeql-pack.release.yml | 2 +-
shared/util/qlpack.yml | 2 +-
shared/yaml/CHANGELOG.md | 4 ++++
shared/yaml/change-notes/released/0.2.10.md | 3 +++
shared/yaml/codeql-pack.release.yml | 2 +-
shared/yaml/qlpack.yml | 2 +-
swift/ql/lib/CHANGELOG.md | 6 ++++++
.../0.3.10.md} | 7 ++++---
swift/ql/lib/codeql-pack.release.yml | 2 +-
swift/ql/lib/qlpack.yml | 2 +-
swift/ql/src/CHANGELOG.md | 4 ++++
swift/ql/src/change-notes/released/0.3.10.md | 3 +++
swift/ql/src/codeql-pack.release.yml | 2 +-
swift/ql/src/qlpack.yml | 2 +-
150 files changed, 394 insertions(+), 168 deletions(-)
rename cpp/ql/lib/change-notes/{2024-02-26-ir-named-destructors.md => released/0.12.7.md} (54%)
delete mode 100644 cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
rename cpp/ql/src/change-notes/{2024-02-16-modelled-functions-block-flow.md => released/0.9.6.md} (77%)
create mode 100644 csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
create mode 100644 csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
create mode 100644 csharp/ql/lib/change-notes/released/0.8.10.md
rename csharp/ql/src/change-notes/{2024-02-06-threat-models.md => released/0.8.10.md} (88%)
create mode 100644 go/ql/consistency-queries/change-notes/released/0.0.9.md
delete mode 100644 go/ql/lib/change-notes/2024-02-14-range-map-read.md
rename go/ql/lib/change-notes/{2024-03-04-autobuilder-changes.md => released/0.7.10.md} (68%)
create mode 100644 go/ql/src/change-notes/released/0.7.10.md
create mode 100644 java/ql/automodel/src/change-notes/released/0.0.17.md
delete mode 100644 java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
delete mode 100644 java/ql/lib/change-notes/2024-02-27-error-types.md
delete mode 100644 java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
create mode 100644 java/ql/lib/change-notes/released/0.8.10.md
delete mode 100644 java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
rename java/ql/src/change-notes/{2024-03-04-sensitive-log-remove-null-from-sources.md => released/0.8.10.md} (54%)
create mode 100644 javascript/ql/lib/change-notes/released/0.8.10.md
create mode 100644 javascript/ql/src/change-notes/released/0.8.10.md
create mode 100644 misc/suite-helpers/change-notes/released/0.7.10.md
delete mode 100644 python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
rename python/ql/lib/change-notes/{2024-03-01-dict-update-content.md => released/0.11.10.md} (52%)
rename python/ql/src/change-notes/{2024-03-04-nosql-injection.md => released/0.9.10.md} (81%)
delete mode 100644 ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
delete mode 100644 ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
delete mode 100644 ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
delete mode 100644 ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
create mode 100644 ruby/ql/lib/change-notes/released/0.8.10.md
delete mode 100644 ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
rename ruby/ql/src/change-notes/{2024-03-01-method-code-injection-sinks.md => released/0.8.10.md} (51%)
create mode 100644 shared/controlflow/change-notes/released/0.1.10.md
create mode 100644 shared/dataflow/change-notes/released/0.2.1.md
create mode 100644 shared/mad/change-notes/released/0.2.10.md
create mode 100644 shared/rangeanalysis/change-notes/released/0.0.9.md
create mode 100644 shared/regex/change-notes/released/0.2.10.md
create mode 100644 shared/ssa/change-notes/released/0.2.10.md
create mode 100644 shared/threat-models/change-notes/released/0.0.9.md
create mode 100644 shared/tutorial/change-notes/released/0.2.10.md
create mode 100644 shared/typetracking/change-notes/released/0.2.10.md
create mode 100644 shared/typos/change-notes/released/0.2.10.md
create mode 100644 shared/util/change-notes/released/0.2.10.md
create mode 100644 shared/yaml/change-notes/released/0.2.10.md
rename swift/ql/lib/change-notes/{2024-02-22-extension-patch.md => released/0.3.10.md} (83%)
create mode 100644 swift/ql/src/change-notes/released/0.3.10.md
diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md
index b3091ec37d8..e1c0dfbecd9 100644
--- a/cpp/ql/lib/CHANGELOG.md
+++ b/cpp/ql/lib/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.12.7
+
+### Minor Analysis Improvements
+
+* Added destructors for named objects to the intermediate representation.
+
## 0.12.6
### New Features
diff --git a/cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md b/cpp/ql/lib/change-notes/released/0.12.7.md
similarity index 54%
rename from cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md
rename to cpp/ql/lib/change-notes/released/0.12.7.md
index 4e35decaf8e..856a8b665c7 100644
--- a/cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md
+++ b/cpp/ql/lib/change-notes/released/0.12.7.md
@@ -1,4 +1,5 @@
----
-category: minorAnalysis
----
-* Added destructors for named objects to the intermediate representation.
\ No newline at end of file
+## 0.12.7
+
+### Minor Analysis Improvements
+
+* Added destructors for named objects to the intermediate representation.
diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml
index 170a312c104..20419e9c610 100644
--- a/cpp/ql/lib/codeql-pack.release.yml
+++ b/cpp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.12.6
+lastReleaseVersion: 0.12.7
diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml
index 8e201fff594..3bb9229bf94 100644
--- a/cpp/ql/lib/qlpack.yml
+++ b/cpp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-all
-version: 0.12.7-dev
+version: 0.12.7
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md
index ffcd73ff5d7..f6acd424bb0 100644
--- a/cpp/ql/src/CHANGELOG.md
+++ b/cpp/ql/src/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.9.6
+
+### Minor Analysis Improvements
+
+* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
+* The new C/C++ dataflow and taint-tracking libraries (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`) now implicitly assume that dataflow and taint modelled via `DataFlowFunction` and `TaintFunction` always fully overwrite their buffers and thus act as flow barriers. As a result, many dataflow and taint-tracking queries now produce fewer false positives. To remove this assumption and go back to the previous behavior for a given model, one can override the new `isPartialWrite` predicate.
+
## 0.9.5
### Minor Analysis Improvements
diff --git a/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md b/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
deleted file mode 100644
index 2e5933a61e8..00000000000
--- a/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
\ No newline at end of file
diff --git a/cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md b/cpp/ql/src/change-notes/released/0.9.6.md
similarity index 77%
rename from cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md
rename to cpp/ql/src/change-notes/released/0.9.6.md
index d6ef3c3e056..0c85f3f9f0f 100644
--- a/cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md
+++ b/cpp/ql/src/change-notes/released/0.9.6.md
@@ -1,4 +1,6 @@
----
-category: minorAnalysis
----
+## 0.9.6
+
+### Minor Analysis Improvements
+
+* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
* The new C/C++ dataflow and taint-tracking libraries (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`) now implicitly assume that dataflow and taint modelled via `DataFlowFunction` and `TaintFunction` always fully overwrite their buffers and thus act as flow barriers. As a result, many dataflow and taint-tracking queries now produce fewer false positives. To remove this assumption and go back to the previous behavior for a given model, one can override the new `isPartialWrite` predicate.
diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml
index 460240feaff..19139c132b2 100644
--- a/cpp/ql/src/codeql-pack.release.yml
+++ b/cpp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.9.5
+lastReleaseVersion: 0.9.6
diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml
index 31bd20166b2..4052647bb97 100644
--- a/cpp/ql/src/qlpack.yml
+++ b/cpp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-queries
-version: 0.9.6-dev
+version: 0.9.6
groups:
- cpp
- queries
diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
index 190b83b0f25..82eacfc84f7 100644
--- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
+++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.7.10
+
+No user-facing changes.
+
## 1.7.9
No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
new file mode 100644
index 00000000000..8e8007d8475
--- /dev/null
+++ b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
@@ -0,0 +1,3 @@
+## 1.7.10
+
+No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
index 678da6bc37e..31c7fe07020 100644
--- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
+++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.7.9
+lastReleaseVersion: 1.7.10
diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
index 7e643b0fac3..ee993bed0c9 100644
--- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
-version: 1.7.10-dev
+version: 1.7.10
groups:
- csharp
- solorigate
diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
index 190b83b0f25..82eacfc84f7 100644
--- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
+++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.7.10
+
+No user-facing changes.
+
## 1.7.9
No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
new file mode 100644
index 00000000000..8e8007d8475
--- /dev/null
+++ b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
@@ -0,0 +1,3 @@
+## 1.7.10
+
+No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
index 678da6bc37e..31c7fe07020 100644
--- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
+++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.7.9
+lastReleaseVersion: 1.7.10
diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
index 8654bbfd031..1f421754fc8 100644
--- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
-version: 1.7.10-dev
+version: 1.7.10
groups:
- csharp
- solorigate
diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md
index 95fd64c5270..16cc14259e1 100644
--- a/csharp/ql/lib/CHANGELOG.md
+++ b/csharp/ql/lib/CHANGELOG.md
@@ -1,3 +1,17 @@
+## 0.8.10
+
+### Major Analysis Improvements
+
+* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
+* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
+
+### Minor Analysis Improvements
+
+* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
+* C# 12: Add extractor and QL library support for `ref readonly` parameters.
+* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
+* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
+
## 0.8.9
### Minor Analysis Improvements
diff --git a/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md b/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
deleted file mode 100644
index 6bb8e99c71e..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
diff --git a/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md b/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
deleted file mode 100644
index d6ffbd523ac..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: majorAnalysis
----
-* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
diff --git a/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md b/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
deleted file mode 100644
index 9b1739b9b6d..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
diff --git a/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md b/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
deleted file mode 100644
index 66ab65083dc..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: majorAnalysis
----
-* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
\ No newline at end of file
diff --git a/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md b/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
deleted file mode 100644
index 8749c790954..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
diff --git a/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md b/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
deleted file mode 100644
index 586b5341d29..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* C# 12: Add extractor and QL library support for `ref readonly` parameters.
diff --git a/csharp/ql/lib/change-notes/released/0.8.10.md b/csharp/ql/lib/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..f591ddc5b21
--- /dev/null
+++ b/csharp/ql/lib/change-notes/released/0.8.10.md
@@ -0,0 +1,13 @@
+## 0.8.10
+
+### Major Analysis Improvements
+
+* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
+* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
+
+### Minor Analysis Improvements
+
+* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
+* C# 12: Add extractor and QL library support for `ref readonly` parameters.
+* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
+* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/csharp/ql/lib/codeql-pack.release.yml
+++ b/csharp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml
index d75ea3c6320..93c5c1120a2 100644
--- a/csharp/ql/lib/qlpack.yml
+++ b/csharp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-all
-version: 0.8.10-dev
+version: 0.8.10
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp
diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md
index 9fe1609363f..46c939e5cee 100644
--- a/csharp/ql/src/CHANGELOG.md
+++ b/csharp/ql/src/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
+
## 0.8.9
### Minor Analysis Improvements
diff --git a/csharp/ql/src/change-notes/2024-02-06-threat-models.md b/csharp/ql/src/change-notes/released/0.8.10.md
similarity index 88%
rename from csharp/ql/src/change-notes/2024-02-06-threat-models.md
rename to csharp/ql/src/change-notes/released/0.8.10.md
index 69ac4e4dc17..702161c3d28 100644
--- a/csharp/ql/src/change-notes/2024-02-06-threat-models.md
+++ b/csharp/ql/src/change-notes/released/0.8.10.md
@@ -1,4 +1,5 @@
----
-category: minorAnalysis
----
-* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
\ No newline at end of file
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/csharp/ql/src/codeql-pack.release.yml
+++ b/csharp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml
index 9ee23cc7307..46384094b19 100644
--- a/csharp/ql/src/qlpack.yml
+++ b/csharp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-queries
-version: 0.8.10-dev
+version: 0.8.10
groups:
- csharp
- queries
diff --git a/go/ql/consistency-queries/CHANGELOG.md b/go/ql/consistency-queries/CHANGELOG.md
index fba2a870356..a59e560c415 100644
--- a/go/ql/consistency-queries/CHANGELOG.md
+++ b/go/ql/consistency-queries/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.9
+
+No user-facing changes.
+
## 0.0.8
No user-facing changes.
diff --git a/go/ql/consistency-queries/change-notes/released/0.0.9.md b/go/ql/consistency-queries/change-notes/released/0.0.9.md
new file mode 100644
index 00000000000..c9e17c6d6cf
--- /dev/null
+++ b/go/ql/consistency-queries/change-notes/released/0.0.9.md
@@ -0,0 +1,3 @@
+## 0.0.9
+
+No user-facing changes.
diff --git a/go/ql/consistency-queries/codeql-pack.release.yml b/go/ql/consistency-queries/codeql-pack.release.yml
index 58fdc6b45de..ecdd64fbab8 100644
--- a/go/ql/consistency-queries/codeql-pack.release.yml
+++ b/go/ql/consistency-queries/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.8
+lastReleaseVersion: 0.0.9
diff --git a/go/ql/consistency-queries/qlpack.yml b/go/ql/consistency-queries/qlpack.yml
index b574796b995..d5a2fbee5f1 100644
--- a/go/ql/consistency-queries/qlpack.yml
+++ b/go/ql/consistency-queries/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql-go-consistency-queries
-version: 0.0.9-dev
+version: 0.0.9
groups:
- go
- queries
diff --git a/go/ql/lib/CHANGELOG.md b/go/ql/lib/CHANGELOG.md
index 65a2376217b..fee5fd37a26 100644
--- a/go/ql/lib/CHANGELOG.md
+++ b/go/ql/lib/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 0.7.10
+
+### Major Analysis Improvements
+
+* We have significantly improved the Go autobuilder to understand a greater range of project layouts, which allows Go source files to be analysed that could previously not be processed.
+* Go 1.22 has been included in the range of supported Go versions.
+
+### Bug Fixes
+
+* Fixed dataflow out of a `map` using a `range` statement.
+
## 0.7.9
No user-facing changes.
diff --git a/go/ql/lib/change-notes/2024-02-14-range-map-read.md b/go/ql/lib/change-notes/2024-02-14-range-map-read.md
deleted file mode 100644
index ea45737a72e..00000000000
--- a/go/ql/lib/change-notes/2024-02-14-range-map-read.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: fix
----
-* Fixed dataflow out of a `map` using a `range` statement.
diff --git a/go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md b/go/ql/lib/change-notes/released/0.7.10.md
similarity index 68%
rename from go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md
rename to go/ql/lib/change-notes/released/0.7.10.md
index 0442a571029..55954f8a394 100644
--- a/go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md
+++ b/go/ql/lib/change-notes/released/0.7.10.md
@@ -1,5 +1,10 @@
----
-category: majorAnalysis
----
+## 0.7.10
+
+### Major Analysis Improvements
+
* We have significantly improved the Go autobuilder to understand a greater range of project layouts, which allows Go source files to be analysed that could previously not be processed.
* Go 1.22 has been included in the range of supported Go versions.
+
+### Bug Fixes
+
+* Fixed dataflow out of a `map` using a `range` statement.
diff --git a/go/ql/lib/codeql-pack.release.yml b/go/ql/lib/codeql-pack.release.yml
index 576395f3405..67518567297 100644
--- a/go/ql/lib/codeql-pack.release.yml
+++ b/go/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.9
+lastReleaseVersion: 0.7.10
diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml
index f21e478efa6..8cc190fa880 100644
--- a/go/ql/lib/qlpack.yml
+++ b/go/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/go-all
-version: 0.7.10-dev
+version: 0.7.10
groups: go
dbscheme: go.dbscheme
extractor: go
diff --git a/go/ql/src/CHANGELOG.md b/go/ql/src/CHANGELOG.md
index d95165a3a34..24e38b9890e 100644
--- a/go/ql/src/CHANGELOG.md
+++ b/go/ql/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.7.10
+
+No user-facing changes.
+
## 0.7.9
### New Queries
diff --git a/go/ql/src/change-notes/released/0.7.10.md b/go/ql/src/change-notes/released/0.7.10.md
new file mode 100644
index 00000000000..989c5b8f682
--- /dev/null
+++ b/go/ql/src/change-notes/released/0.7.10.md
@@ -0,0 +1,3 @@
+## 0.7.10
+
+No user-facing changes.
diff --git a/go/ql/src/codeql-pack.release.yml b/go/ql/src/codeql-pack.release.yml
index 576395f3405..67518567297 100644
--- a/go/ql/src/codeql-pack.release.yml
+++ b/go/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.9
+lastReleaseVersion: 0.7.10
diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml
index d91cab59612..4ded3a52f63 100644
--- a/go/ql/src/qlpack.yml
+++ b/go/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/go-queries
-version: 0.7.10-dev
+version: 0.7.10
groups:
- go
- queries
diff --git a/java/ql/automodel/src/CHANGELOG.md b/java/ql/automodel/src/CHANGELOG.md
index 4a3c54adb38..c3282c773a9 100644
--- a/java/ql/automodel/src/CHANGELOG.md
+++ b/java/ql/automodel/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.17
+
+No user-facing changes.
+
## 0.0.16
No user-facing changes.
diff --git a/java/ql/automodel/src/change-notes/released/0.0.17.md b/java/ql/automodel/src/change-notes/released/0.0.17.md
new file mode 100644
index 00000000000..62cc89030a6
--- /dev/null
+++ b/java/ql/automodel/src/change-notes/released/0.0.17.md
@@ -0,0 +1,3 @@
+## 0.0.17
+
+No user-facing changes.
diff --git a/java/ql/automodel/src/codeql-pack.release.yml b/java/ql/automodel/src/codeql-pack.release.yml
index a49f7be4cff..cbc3d3cd493 100644
--- a/java/ql/automodel/src/codeql-pack.release.yml
+++ b/java/ql/automodel/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.16
+lastReleaseVersion: 0.0.17
diff --git a/java/ql/automodel/src/qlpack.yml b/java/ql/automodel/src/qlpack.yml
index 898239be098..59fab0cdcc5 100644
--- a/java/ql/automodel/src/qlpack.yml
+++ b/java/ql/automodel/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-automodel-queries
-version: 0.0.17-dev
+version: 0.0.17
groups:
- java
- automodel
diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md
index d369cbdc931..2a02ccee6ab 100644
--- a/java/ql/lib/CHANGELOG.md
+++ b/java/ql/lib/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
+
+### Bug Fixes
+
+* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
+* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
+
## 0.8.9
### Deprecated APIs
diff --git a/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md b/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
deleted file mode 100644
index eb560fba07d..00000000000
--- a/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: fix
----
-* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
diff --git a/java/ql/lib/change-notes/2024-02-27-error-types.md b/java/ql/lib/change-notes/2024-02-27-error-types.md
deleted file mode 100644
index cdc6d7620aa..00000000000
--- a/java/ql/lib/change-notes/2024-02-27-error-types.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
diff --git a/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md b/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
deleted file mode 100644
index a0227088ae9..00000000000
--- a/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: fix
----
-* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
diff --git a/java/ql/lib/change-notes/released/0.8.10.md b/java/ql/lib/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..b45f14bf347
--- /dev/null
+++ b/java/ql/lib/change-notes/released/0.8.10.md
@@ -0,0 +1,10 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
+
+### Bug Fixes
+
+* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
+* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
diff --git a/java/ql/lib/codeql-pack.release.yml b/java/ql/lib/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/java/ql/lib/codeql-pack.release.yml
+++ b/java/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml
index 15b4982d41e..428eedc75e3 100644
--- a/java/ql/lib/qlpack.yml
+++ b/java/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-all
-version: 0.8.10-dev
+version: 0.8.10
groups: java
dbscheme: config/semmlecode.dbscheme
extractor: java
diff --git a/java/ql/src/CHANGELOG.md b/java/ql/src/CHANGELOG.md
index 5d835351453..c61275f5ed8 100644
--- a/java/ql/src/CHANGELOG.md
+++ b/java/ql/src/CHANGELOG.md
@@ -1,3 +1,13 @@
+## 0.8.10
+
+### New Queries
+
+* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
+
+### Minor Analysis Improvements
+
+* To reduce the number of false positives in the query "Insertion of sensitive information into log files" (`java/sensitive-log`), variables with names that contain "null" (case-insensitively) are no longer considered sources of sensitive information.
+
## 0.8.9
### New Queries
diff --git a/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md b/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
deleted file mode 100644
index 1de07727796..00000000000
--- a/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: newQuery
----
-* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
\ No newline at end of file
diff --git a/java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md b/java/ql/src/change-notes/released/0.8.10.md
similarity index 54%
rename from java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md
rename to java/ql/src/change-notes/released/0.8.10.md
index 0bb4f18f2bd..c5d18ae3379 100644
--- a/java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md
+++ b/java/ql/src/change-notes/released/0.8.10.md
@@ -1,4 +1,9 @@
----
-category: minorAnalysis
----
+## 0.8.10
+
+### New Queries
+
+* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
+
+### Minor Analysis Improvements
+
* To reduce the number of false positives in the query "Insertion of sensitive information into log files" (`java/sensitive-log`), variables with names that contain "null" (case-insensitively) are no longer considered sources of sensitive information.
diff --git a/java/ql/src/codeql-pack.release.yml b/java/ql/src/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/java/ql/src/codeql-pack.release.yml
+++ b/java/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml
index 8f4de528e21..ebbdbeee3b2 100644
--- a/java/ql/src/qlpack.yml
+++ b/java/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-queries
-version: 0.8.10-dev
+version: 0.8.10
groups:
- java
- queries
diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md
index 5b97ebbb22b..d5edcc00513 100644
--- a/javascript/ql/lib/CHANGELOG.md
+++ b/javascript/ql/lib/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.8.10
+
+No user-facing changes.
+
## 0.8.9
### Minor Analysis Improvements
diff --git a/javascript/ql/lib/change-notes/released/0.8.10.md b/javascript/ql/lib/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..777bbd2fded
--- /dev/null
+++ b/javascript/ql/lib/change-notes/released/0.8.10.md
@@ -0,0 +1,3 @@
+## 0.8.10
+
+No user-facing changes.
diff --git a/javascript/ql/lib/codeql-pack.release.yml b/javascript/ql/lib/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/javascript/ql/lib/codeql-pack.release.yml
+++ b/javascript/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml
index ef3ca7521ac..da16493a21c 100644
--- a/javascript/ql/lib/qlpack.yml
+++ b/javascript/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-all
-version: 0.8.10-dev
+version: 0.8.10
groups: javascript
dbscheme: semmlecode.javascript.dbscheme
extractor: javascript
diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md
index 85516e3625d..b9627cac5ee 100644
--- a/javascript/ql/src/CHANGELOG.md
+++ b/javascript/ql/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.8.10
+
+No user-facing changes.
+
## 0.8.9
### Bug Fixes
diff --git a/javascript/ql/src/change-notes/released/0.8.10.md b/javascript/ql/src/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..777bbd2fded
--- /dev/null
+++ b/javascript/ql/src/change-notes/released/0.8.10.md
@@ -0,0 +1,3 @@
+## 0.8.10
+
+No user-facing changes.
diff --git a/javascript/ql/src/codeql-pack.release.yml b/javascript/ql/src/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/javascript/ql/src/codeql-pack.release.yml
+++ b/javascript/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml
index b6181aa30e9..d224952c564 100644
--- a/javascript/ql/src/qlpack.yml
+++ b/javascript/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-queries
-version: 0.8.10-dev
+version: 0.8.10
groups:
- javascript
- queries
diff --git a/misc/suite-helpers/CHANGELOG.md b/misc/suite-helpers/CHANGELOG.md
index 3c06dd69b0f..1c4455b66c4 100644
--- a/misc/suite-helpers/CHANGELOG.md
+++ b/misc/suite-helpers/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.7.10
+
+No user-facing changes.
+
## 0.7.9
No user-facing changes.
diff --git a/misc/suite-helpers/change-notes/released/0.7.10.md b/misc/suite-helpers/change-notes/released/0.7.10.md
new file mode 100644
index 00000000000..989c5b8f682
--- /dev/null
+++ b/misc/suite-helpers/change-notes/released/0.7.10.md
@@ -0,0 +1,3 @@
+## 0.7.10
+
+No user-facing changes.
diff --git a/misc/suite-helpers/codeql-pack.release.yml b/misc/suite-helpers/codeql-pack.release.yml
index 576395f3405..67518567297 100644
--- a/misc/suite-helpers/codeql-pack.release.yml
+++ b/misc/suite-helpers/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.9
+lastReleaseVersion: 0.7.10
diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml
index 49b7a6bda4c..54d978d5efe 100644
--- a/misc/suite-helpers/qlpack.yml
+++ b/misc/suite-helpers/qlpack.yml
@@ -1,4 +1,4 @@
name: codeql/suite-helpers
-version: 0.7.10-dev
+version: 0.7.10
groups: shared
warnOnImplicitThis: true
diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md
index e6f318c51ea..f095607ca1b 100644
--- a/python/ql/lib/CHANGELOG.md
+++ b/python/ql/lib/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.11.10
+
+### Minor Analysis Improvements
+
+* Fixed missing flow for dictionary updates (`d[] = ...`) when `` is a string constant not used in dictionary literals or as name of keyword-argument.
+* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
+
## 0.11.9
### Minor Analysis Improvements
diff --git a/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md b/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
deleted file mode 100644
index 3c47c6ba866..00000000000
--- a/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
diff --git a/python/ql/lib/change-notes/2024-03-01-dict-update-content.md b/python/ql/lib/change-notes/released/0.11.10.md
similarity index 52%
rename from python/ql/lib/change-notes/2024-03-01-dict-update-content.md
rename to python/ql/lib/change-notes/released/0.11.10.md
index dfb8d247fff..ed873724e4f 100644
--- a/python/ql/lib/change-notes/2024-03-01-dict-update-content.md
+++ b/python/ql/lib/change-notes/released/0.11.10.md
@@ -1,4 +1,6 @@
----
-category: minorAnalysis
----
+## 0.11.10
+
+### Minor Analysis Improvements
+
* Fixed missing flow for dictionary updates (`d[] = ...`) when `` is a string constant not used in dictionary literals or as name of keyword-argument.
+* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
diff --git a/python/ql/lib/codeql-pack.release.yml b/python/ql/lib/codeql-pack.release.yml
index b064d1778a1..ddddcbe9193 100644
--- a/python/ql/lib/codeql-pack.release.yml
+++ b/python/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.11.9
+lastReleaseVersion: 0.11.10
diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml
index e9f66e205f2..59a8b4c96d1 100644
--- a/python/ql/lib/qlpack.yml
+++ b/python/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/python-all
-version: 0.11.10-dev
+version: 0.11.10
groups: python
dbscheme: semmlecode.python.dbscheme
extractor: python
diff --git a/python/ql/src/CHANGELOG.md b/python/ql/src/CHANGELOG.md
index 50762bcbf34..d4245aba7a6 100644
--- a/python/ql/src/CHANGELOG.md
+++ b/python/ql/src/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.9.10
+
+### New Queries
+
+* The query `py/nosql-injection` for finding NoSQL injection vulnerabilities is now part of the default security suite.
+
## 0.9.9
No user-facing changes.
diff --git a/python/ql/src/change-notes/2024-03-04-nosql-injection.md b/python/ql/src/change-notes/released/0.9.10.md
similarity index 81%
rename from python/ql/src/change-notes/2024-03-04-nosql-injection.md
rename to python/ql/src/change-notes/released/0.9.10.md
index 6e98540c757..4cbb221b789 100644
--- a/python/ql/src/change-notes/2024-03-04-nosql-injection.md
+++ b/python/ql/src/change-notes/released/0.9.10.md
@@ -1,4 +1,5 @@
----
-category: newQuery
----
+## 0.9.10
+
+### New Queries
+
* The query `py/nosql-injection` for finding NoSQL injection vulnerabilities is now part of the default security suite.
diff --git a/python/ql/src/codeql-pack.release.yml b/python/ql/src/codeql-pack.release.yml
index aabed7c396b..d086ed69541 100644
--- a/python/ql/src/codeql-pack.release.yml
+++ b/python/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.9.9
+lastReleaseVersion: 0.9.10
diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml
index aa18f2d8707..c920f667836 100644
--- a/python/ql/src/qlpack.yml
+++ b/python/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/python-queries
-version: 0.9.10-dev
+version: 0.9.10
groups:
- python
- queries
diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md
index a623a151e89..c61a12e0f4a 100644
--- a/ruby/ql/lib/CHANGELOG.md
+++ b/ruby/ql/lib/CHANGELOG.md
@@ -1,3 +1,12 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
+* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
+* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
+* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
+
## 0.8.9
### Minor Analysis Improvements
diff --git a/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md b/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
deleted file mode 100644
index c2276f284a8..00000000000
--- a/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md b/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
deleted file mode 100644
index 1486c7a472d..00000000000
--- a/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md b/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
deleted file mode 100644
index 6f3a90768ba..00000000000
--- a/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md b/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
deleted file mode 100644
index 350e049b5bf..00000000000
--- a/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/released/0.8.10.md b/ruby/ql/lib/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..666e28f840e
--- /dev/null
+++ b/ruby/ql/lib/change-notes/released/0.8.10.md
@@ -0,0 +1,8 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
+* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
+* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
+* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
diff --git a/ruby/ql/lib/codeql-pack.release.yml b/ruby/ql/lib/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/ruby/ql/lib/codeql-pack.release.yml
+++ b/ruby/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml
index 7d409b83adb..de5b41999fe 100644
--- a/ruby/ql/lib/qlpack.yml
+++ b/ruby/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ruby-all
-version: 0.8.10-dev
+version: 0.8.10
groups: ruby
extractor: ruby
dbscheme: ruby.dbscheme
diff --git a/ruby/ql/src/CHANGELOG.md b/ruby/ql/src/CHANGELOG.md
index 4149c728eff..f875b6d16ad 100644
--- a/ruby/ql/src/CHANGELOG.md
+++ b/ruby/ql/src/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
+* Added additional request sources for Ruby on Rails.
+
## 0.8.9
No user-facing changes.
diff --git a/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md b/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
deleted file mode 100644
index 84ea696dfef..00000000000
--- a/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Added additional request sources for Ruby on Rails.
\ No newline at end of file
diff --git a/ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md b/ruby/ql/src/change-notes/released/0.8.10.md
similarity index 51%
rename from ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md
rename to ruby/ql/src/change-notes/released/0.8.10.md
index 43e40d3fd53..985cdf8d22e 100644
--- a/ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md
+++ b/ruby/ql/src/change-notes/released/0.8.10.md
@@ -1,4 +1,6 @@
----
-category: minorAnalysis
----
-* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
\ No newline at end of file
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
+* Added additional request sources for Ruby on Rails.
diff --git a/ruby/ql/src/codeql-pack.release.yml b/ruby/ql/src/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/ruby/ql/src/codeql-pack.release.yml
+++ b/ruby/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml
index 8af7f9fd797..5e379268234 100644
--- a/ruby/ql/src/qlpack.yml
+++ b/ruby/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ruby-queries
-version: 0.8.10-dev
+version: 0.8.10
groups:
- ruby
- queries
diff --git a/shared/controlflow/CHANGELOG.md b/shared/controlflow/CHANGELOG.md
index dbfa6ef4512..75f2ca53f98 100644
--- a/shared/controlflow/CHANGELOG.md
+++ b/shared/controlflow/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.10
+
+No user-facing changes.
+
## 0.1.9
No user-facing changes.
diff --git a/shared/controlflow/change-notes/released/0.1.10.md b/shared/controlflow/change-notes/released/0.1.10.md
new file mode 100644
index 00000000000..47358eeee93
--- /dev/null
+++ b/shared/controlflow/change-notes/released/0.1.10.md
@@ -0,0 +1,3 @@
+## 0.1.10
+
+No user-facing changes.
diff --git a/shared/controlflow/codeql-pack.release.yml b/shared/controlflow/codeql-pack.release.yml
index 1425c0edf7f..30f5ca88be0 100644
--- a/shared/controlflow/codeql-pack.release.yml
+++ b/shared/controlflow/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.1.9
+lastReleaseVersion: 0.1.10
diff --git a/shared/controlflow/qlpack.yml b/shared/controlflow/qlpack.yml
index 9d35a678276..1d43802be42 100644
--- a/shared/controlflow/qlpack.yml
+++ b/shared/controlflow/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/controlflow
-version: 0.1.10-dev
+version: 0.1.10
groups: shared
library: true
dependencies:
diff --git a/shared/dataflow/CHANGELOG.md b/shared/dataflow/CHANGELOG.md
index 67a5bf589f4..ef80788bded 100644
--- a/shared/dataflow/CHANGELOG.md
+++ b/shared/dataflow/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.1
+
+No user-facing changes.
+
## 0.2.0
### Breaking Changes
diff --git a/shared/dataflow/change-notes/released/0.2.1.md b/shared/dataflow/change-notes/released/0.2.1.md
new file mode 100644
index 00000000000..3dbfc85fe11
--- /dev/null
+++ b/shared/dataflow/change-notes/released/0.2.1.md
@@ -0,0 +1,3 @@
+## 0.2.1
+
+No user-facing changes.
diff --git a/shared/dataflow/codeql-pack.release.yml b/shared/dataflow/codeql-pack.release.yml
index 5274e27ed52..df29a726bcc 100644
--- a/shared/dataflow/codeql-pack.release.yml
+++ b/shared/dataflow/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.0
+lastReleaseVersion: 0.2.1
diff --git a/shared/dataflow/qlpack.yml b/shared/dataflow/qlpack.yml
index 1e7becf71c4..ee422e02ea9 100644
--- a/shared/dataflow/qlpack.yml
+++ b/shared/dataflow/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/dataflow
-version: 0.2.1-dev
+version: 0.2.1
groups: shared
library: true
dependencies:
diff --git a/shared/mad/CHANGELOG.md b/shared/mad/CHANGELOG.md
index 4d09057118c..4730366775e 100644
--- a/shared/mad/CHANGELOG.md
+++ b/shared/mad/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/mad/change-notes/released/0.2.10.md b/shared/mad/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/mad/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/mad/codeql-pack.release.yml b/shared/mad/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/mad/codeql-pack.release.yml
+++ b/shared/mad/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml
index 22c8f271ccc..6d7269ef3da 100644
--- a/shared/mad/qlpack.yml
+++ b/shared/mad/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/mad
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies: null
diff --git a/shared/rangeanalysis/CHANGELOG.md b/shared/rangeanalysis/CHANGELOG.md
index 5b8dbcfab22..9943dcb7972 100644
--- a/shared/rangeanalysis/CHANGELOG.md
+++ b/shared/rangeanalysis/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.9
+
+No user-facing changes.
+
## 0.0.8
No user-facing changes.
diff --git a/shared/rangeanalysis/change-notes/released/0.0.9.md b/shared/rangeanalysis/change-notes/released/0.0.9.md
new file mode 100644
index 00000000000..c9e17c6d6cf
--- /dev/null
+++ b/shared/rangeanalysis/change-notes/released/0.0.9.md
@@ -0,0 +1,3 @@
+## 0.0.9
+
+No user-facing changes.
diff --git a/shared/rangeanalysis/codeql-pack.release.yml b/shared/rangeanalysis/codeql-pack.release.yml
index 58fdc6b45de..ecdd64fbab8 100644
--- a/shared/rangeanalysis/codeql-pack.release.yml
+++ b/shared/rangeanalysis/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.8
+lastReleaseVersion: 0.0.9
diff --git a/shared/rangeanalysis/qlpack.yml b/shared/rangeanalysis/qlpack.yml
index 836fe51ee34..01db5d5734d 100644
--- a/shared/rangeanalysis/qlpack.yml
+++ b/shared/rangeanalysis/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/rangeanalysis
-version: 0.0.9-dev
+version: 0.0.9
groups: shared
library: true
dependencies:
diff --git a/shared/regex/CHANGELOG.md b/shared/regex/CHANGELOG.md
index cd5f91f71ec..c05869c153d 100644
--- a/shared/regex/CHANGELOG.md
+++ b/shared/regex/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/regex/change-notes/released/0.2.10.md b/shared/regex/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/regex/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/regex/codeql-pack.release.yml b/shared/regex/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/regex/codeql-pack.release.yml
+++ b/shared/regex/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml
index ea3f7f9b238..0d4f485312f 100644
--- a/shared/regex/qlpack.yml
+++ b/shared/regex/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/regex
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies:
diff --git a/shared/ssa/CHANGELOG.md b/shared/ssa/CHANGELOG.md
index 01acfae0148..a9161ff578b 100644
--- a/shared/ssa/CHANGELOG.md
+++ b/shared/ssa/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/ssa/change-notes/released/0.2.10.md b/shared/ssa/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/ssa/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/ssa/codeql-pack.release.yml b/shared/ssa/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/ssa/codeql-pack.release.yml
+++ b/shared/ssa/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml
index 19304ad107f..2ad254711a5 100644
--- a/shared/ssa/qlpack.yml
+++ b/shared/ssa/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ssa
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies:
diff --git a/shared/threat-models/CHANGELOG.md b/shared/threat-models/CHANGELOG.md
index fba2a870356..a59e560c415 100644
--- a/shared/threat-models/CHANGELOG.md
+++ b/shared/threat-models/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.9
+
+No user-facing changes.
+
## 0.0.8
No user-facing changes.
diff --git a/shared/threat-models/change-notes/released/0.0.9.md b/shared/threat-models/change-notes/released/0.0.9.md
new file mode 100644
index 00000000000..c9e17c6d6cf
--- /dev/null
+++ b/shared/threat-models/change-notes/released/0.0.9.md
@@ -0,0 +1,3 @@
+## 0.0.9
+
+No user-facing changes.
diff --git a/shared/threat-models/codeql-pack.release.yml b/shared/threat-models/codeql-pack.release.yml
index 58fdc6b45de..ecdd64fbab8 100644
--- a/shared/threat-models/codeql-pack.release.yml
+++ b/shared/threat-models/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.8
+lastReleaseVersion: 0.0.9
diff --git a/shared/threat-models/qlpack.yml b/shared/threat-models/qlpack.yml
index d0ed9a913b2..60cbbc56fcb 100644
--- a/shared/threat-models/qlpack.yml
+++ b/shared/threat-models/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/threat-models
-version: 0.0.9-dev
+version: 0.0.9
library: true
groups: shared
dataExtensions:
diff --git a/shared/tutorial/CHANGELOG.md b/shared/tutorial/CHANGELOG.md
index 1db3a01af0b..560ad058d5b 100644
--- a/shared/tutorial/CHANGELOG.md
+++ b/shared/tutorial/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/tutorial/change-notes/released/0.2.10.md b/shared/tutorial/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/tutorial/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/tutorial/codeql-pack.release.yml b/shared/tutorial/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/tutorial/codeql-pack.release.yml
+++ b/shared/tutorial/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml
index b595ae9ee70..69116705c1b 100644
--- a/shared/tutorial/qlpack.yml
+++ b/shared/tutorial/qlpack.yml
@@ -1,7 +1,7 @@
name: codeql/tutorial
description: Library for the CodeQL detective tutorials, helping new users learn to
write CodeQL queries.
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/shared/typetracking/CHANGELOG.md b/shared/typetracking/CHANGELOG.md
index afc857bc6bc..350f9ecbeae 100644
--- a/shared/typetracking/CHANGELOG.md
+++ b/shared/typetracking/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/typetracking/change-notes/released/0.2.10.md b/shared/typetracking/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/typetracking/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/typetracking/codeql-pack.release.yml b/shared/typetracking/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/typetracking/codeql-pack.release.yml
+++ b/shared/typetracking/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml
index b55927f59bb..fbbdcf5162a 100644
--- a/shared/typetracking/qlpack.yml
+++ b/shared/typetracking/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/typetracking
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies:
diff --git a/shared/typos/CHANGELOG.md b/shared/typos/CHANGELOG.md
index 66c5871d982..54b1eaa4d58 100644
--- a/shared/typos/CHANGELOG.md
+++ b/shared/typos/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/typos/change-notes/released/0.2.10.md b/shared/typos/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/typos/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/typos/codeql-pack.release.yml b/shared/typos/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/typos/codeql-pack.release.yml
+++ b/shared/typos/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml
index 644bfe11bff..4d59d9b3c34 100644
--- a/shared/typos/qlpack.yml
+++ b/shared/typos/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/typos
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/shared/util/CHANGELOG.md b/shared/util/CHANGELOG.md
index 63832e927fa..1ca1f71bcbc 100644
--- a/shared/util/CHANGELOG.md
+++ b/shared/util/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/util/change-notes/released/0.2.10.md b/shared/util/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/util/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/util/codeql-pack.release.yml b/shared/util/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/util/codeql-pack.release.yml
+++ b/shared/util/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml
index ca1a866a53d..28ed738a93d 100644
--- a/shared/util/qlpack.yml
+++ b/shared/util/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/util
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies: null
diff --git a/shared/yaml/CHANGELOG.md b/shared/yaml/CHANGELOG.md
index e5495abcd50..9fd5ebc26ab 100644
--- a/shared/yaml/CHANGELOG.md
+++ b/shared/yaml/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/yaml/change-notes/released/0.2.10.md b/shared/yaml/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/yaml/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/yaml/codeql-pack.release.yml b/shared/yaml/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/yaml/codeql-pack.release.yml
+++ b/shared/yaml/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml
index de5b47e120a..9643ffcec66 100644
--- a/shared/yaml/qlpack.yml
+++ b/shared/yaml/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/yaml
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/swift/ql/lib/CHANGELOG.md b/swift/ql/lib/CHANGELOG.md
index e88cd0259cc..8f14bfcedc9 100644
--- a/swift/ql/lib/CHANGELOG.md
+++ b/swift/ql/lib/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.3.10
+
+### Bug Fixes
+
+* Fixed an issue where `TypeDecl.getFullName` would get stuck in an loop and fail when minor database inconsistencies are present.
+
## 0.3.9
### Minor Analysis Improvements
diff --git a/swift/ql/lib/change-notes/2024-02-22-extension-patch.md b/swift/ql/lib/change-notes/released/0.3.10.md
similarity index 83%
rename from swift/ql/lib/change-notes/2024-02-22-extension-patch.md
rename to swift/ql/lib/change-notes/released/0.3.10.md
index 7bd78f3b785..9d6286ff58a 100644
--- a/swift/ql/lib/change-notes/2024-02-22-extension-patch.md
+++ b/swift/ql/lib/change-notes/released/0.3.10.md
@@ -1,4 +1,5 @@
----
-category: fix
----
+## 0.3.10
+
+### Bug Fixes
+
* Fixed an issue where `TypeDecl.getFullName` would get stuck in an loop and fail when minor database inconsistencies are present.
diff --git a/swift/ql/lib/codeql-pack.release.yml b/swift/ql/lib/codeql-pack.release.yml
index 3fa5180bcb4..76ca0ac8ba7 100644
--- a/swift/ql/lib/codeql-pack.release.yml
+++ b/swift/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.3.9
+lastReleaseVersion: 0.3.10
diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml
index a37a4cb3d58..70ec4798ea8 100644
--- a/swift/ql/lib/qlpack.yml
+++ b/swift/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/swift-all
-version: 0.3.10-dev
+version: 0.3.10
groups: swift
extractor: swift
dbscheme: swift.dbscheme
diff --git a/swift/ql/src/CHANGELOG.md b/swift/ql/src/CHANGELOG.md
index 96615d06972..bda9834c9bc 100644
--- a/swift/ql/src/CHANGELOG.md
+++ b/swift/ql/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.3.10
+
+No user-facing changes.
+
## 0.3.9
### New Queries
diff --git a/swift/ql/src/change-notes/released/0.3.10.md b/swift/ql/src/change-notes/released/0.3.10.md
new file mode 100644
index 00000000000..925a48fc52e
--- /dev/null
+++ b/swift/ql/src/change-notes/released/0.3.10.md
@@ -0,0 +1,3 @@
+## 0.3.10
+
+No user-facing changes.
diff --git a/swift/ql/src/codeql-pack.release.yml b/swift/ql/src/codeql-pack.release.yml
index 3fa5180bcb4..76ca0ac8ba7 100644
--- a/swift/ql/src/codeql-pack.release.yml
+++ b/swift/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.3.9
+lastReleaseVersion: 0.3.10
diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml
index e3ead42c98b..ba66b065529 100644
--- a/swift/ql/src/qlpack.yml
+++ b/swift/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/swift-queries
-version: 0.3.10-dev
+version: 0.3.10
groups:
- swift
- queries
From ce31f8641a4c4f83c8665bdf48de524862aa15c7 Mon Sep 17 00:00:00 2001
From: Angela P Wen
Date: Wed, 6 Mar 2024 12:07:33 -0800
Subject: [PATCH 030/497] Revert "Release preparation for version 2.16.4"
---
cpp/ql/lib/CHANGELOG.md | 6 ------
....12.7.md => 2024-02-26-ir-named-destructors.md} | 9 ++++-----
cpp/ql/lib/codeql-pack.release.yml | 2 +-
cpp/ql/lib/qlpack.yml | 2 +-
cpp/ql/src/CHANGELOG.md | 7 -------
...=> 2024-02-16-modelled-functions-block-flow.md} | 8 +++-----
.../2024-02-29-non-constant-format-path-query.md | 4 ++++
cpp/ql/src/codeql-pack.release.yml | 2 +-
cpp/ql/src/qlpack.yml | 2 +-
csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md | 4 ----
.../Solorigate/lib/change-notes/released/1.7.10.md | 3 ---
.../Solorigate/lib/codeql-pack.release.yml | 2 +-
csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +-
csharp/ql/campaigns/Solorigate/src/CHANGELOG.md | 4 ----
.../Solorigate/src/change-notes/released/1.7.10.md | 3 ---
.../Solorigate/src/codeql-pack.release.yml | 2 +-
csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +-
csharp/ql/lib/CHANGELOG.md | 14 --------------
.../change-notes/2024-02-21-getonly-properties.md | 4 ++++
.../ql/lib/change-notes/2024-02-22-no-db-stats.md | 4 ++++
.../change-notes/2024-02-23-compiler-generated.md | 4 ++++
.../2024-02-26-variable-capture-flow.md | 4 ++++
.../2024-02-28-experimental-attribute.md | 4 ++++
.../2024-02-28-refreadonly-parameter.md | 4 ++++
csharp/ql/lib/change-notes/released/0.8.10.md | 13 -------------
csharp/ql/lib/codeql-pack.release.yml | 2 +-
csharp/ql/lib/qlpack.yml | 2 +-
csharp/ql/src/CHANGELOG.md | 6 ------
.../0.8.10.md => 2024-02-06-threat-models.md} | 9 ++++-----
csharp/ql/src/codeql-pack.release.yml | 2 +-
csharp/ql/src/qlpack.yml | 2 +-
go/ql/consistency-queries/CHANGELOG.md | 4 ----
.../change-notes/released/0.0.9.md | 3 ---
go/ql/consistency-queries/codeql-pack.release.yml | 2 +-
go/ql/consistency-queries/qlpack.yml | 2 +-
go/ql/lib/CHANGELOG.md | 11 -----------
.../lib/change-notes/2024-02-14-range-map-read.md | 4 ++++
...0.7.10.md => 2024-03-04-autobuilder-changes.md} | 11 +++--------
go/ql/lib/codeql-pack.release.yml | 2 +-
go/ql/lib/qlpack.yml | 2 +-
go/ql/src/CHANGELOG.md | 4 ----
go/ql/src/change-notes/released/0.7.10.md | 3 ---
go/ql/src/codeql-pack.release.yml | 2 +-
go/ql/src/qlpack.yml | 2 +-
java/ql/automodel/src/CHANGELOG.md | 4 ----
.../automodel/src/change-notes/released/0.0.17.md | 3 ---
java/ql/automodel/src/codeql-pack.release.yml | 2 +-
java/ql/automodel/src/qlpack.yml | 2 +-
java/ql/lib/CHANGELOG.md | 11 -----------
.../change-notes/2024-02-23-widget-flowsteps.md | 4 ++++
java/ql/lib/change-notes/2024-02-27-error-types.md | 4 ++++
.../lib/change-notes/2024-02-27-mvnw-versions.md | 4 ++++
java/ql/lib/change-notes/released/0.8.10.md | 10 ----------
java/ql/lib/codeql-pack.release.yml | 2 +-
java/ql/lib/qlpack.yml | 2 +-
java/ql/src/CHANGELOG.md | 10 ----------
.../2024-02-12-android-insecure-keys.md | 4 ++++
...3-04-sensitive-log-remove-null-from-sources.md} | 11 +++--------
java/ql/src/codeql-pack.release.yml | 2 +-
java/ql/src/qlpack.yml | 2 +-
javascript/ql/lib/CHANGELOG.md | 4 ----
javascript/ql/lib/change-notes/released/0.8.10.md | 3 ---
javascript/ql/lib/codeql-pack.release.yml | 2 +-
javascript/ql/lib/qlpack.yml | 2 +-
javascript/ql/src/CHANGELOG.md | 4 ----
javascript/ql/src/change-notes/released/0.8.10.md | 3 ---
javascript/ql/src/codeql-pack.release.yml | 2 +-
javascript/ql/src/qlpack.yml | 2 +-
misc/suite-helpers/CHANGELOG.md | 4 ----
misc/suite-helpers/change-notes/released/0.7.10.md | 3 ---
misc/suite-helpers/codeql-pack.release.yml | 2 +-
misc/suite-helpers/qlpack.yml | 2 +-
python/ql/lib/CHANGELOG.md | 7 -------
.../2024-02-28-iterable-unpacking-module-scope.md | 4 ++++
....11.10.md => 2024-03-01-dict-update-content.md} | 8 +++-----
python/ql/lib/codeql-pack.release.yml | 2 +-
python/ql/lib/qlpack.yml | 2 +-
python/ql/src/CHANGELOG.md | 6 ------
.../0.9.10.md => 2024-03-04-nosql-injection.md} | 7 +++----
python/ql/src/codeql-pack.release.yml | 2 +-
python/ql/src/qlpack.yml | 2 +-
ruby/ql/lib/CHANGELOG.md | 9 ---------
...2024-02-15-activerecord_connection_sql_sinks.md | 4 ++++
.../2024-02-20-activerecord-sql-sink-arguments.md | 4 ++++
.../lib/change-notes/2024-02-26-arel-sqlliteral.md | 4 ++++
.../lib/change-notes/2024-02-29-i18n-translate.md | 4 ++++
ruby/ql/lib/change-notes/released/0.8.10.md | 8 --------
ruby/ql/lib/codeql-pack.release.yml | 2 +-
ruby/ql/lib/qlpack.yml | 2 +-
ruby/ql/src/CHANGELOG.md | 7 -------
.../2024-02-13-rails-more-request-sources.md | 4 ++++
...d => 2024-03-01-method-code-injection-sinks.md} | 10 ++++------
ruby/ql/src/codeql-pack.release.yml | 2 +-
ruby/ql/src/qlpack.yml | 2 +-
shared/controlflow/CHANGELOG.md | 4 ----
shared/controlflow/change-notes/released/0.1.10.md | 3 ---
shared/controlflow/codeql-pack.release.yml | 2 +-
shared/controlflow/qlpack.yml | 2 +-
shared/dataflow/CHANGELOG.md | 4 ----
shared/dataflow/change-notes/released/0.2.1.md | 3 ---
shared/dataflow/codeql-pack.release.yml | 2 +-
shared/dataflow/qlpack.yml | 2 +-
shared/mad/CHANGELOG.md | 4 ----
shared/mad/change-notes/released/0.2.10.md | 3 ---
shared/mad/codeql-pack.release.yml | 2 +-
shared/mad/qlpack.yml | 2 +-
shared/rangeanalysis/CHANGELOG.md | 4 ----
.../rangeanalysis/change-notes/released/0.0.9.md | 3 ---
shared/rangeanalysis/codeql-pack.release.yml | 2 +-
shared/rangeanalysis/qlpack.yml | 2 +-
shared/regex/CHANGELOG.md | 4 ----
shared/regex/change-notes/released/0.2.10.md | 3 ---
shared/regex/codeql-pack.release.yml | 2 +-
shared/regex/qlpack.yml | 2 +-
shared/ssa/CHANGELOG.md | 4 ----
shared/ssa/change-notes/released/0.2.10.md | 3 ---
shared/ssa/codeql-pack.release.yml | 2 +-
shared/ssa/qlpack.yml | 2 +-
shared/threat-models/CHANGELOG.md | 4 ----
.../threat-models/change-notes/released/0.0.9.md | 3 ---
shared/threat-models/codeql-pack.release.yml | 2 +-
shared/threat-models/qlpack.yml | 2 +-
shared/tutorial/CHANGELOG.md | 4 ----
shared/tutorial/change-notes/released/0.2.10.md | 3 ---
shared/tutorial/codeql-pack.release.yml | 2 +-
shared/tutorial/qlpack.yml | 2 +-
shared/typetracking/CHANGELOG.md | 4 ----
.../typetracking/change-notes/released/0.2.10.md | 3 ---
shared/typetracking/codeql-pack.release.yml | 2 +-
shared/typetracking/qlpack.yml | 2 +-
shared/typos/CHANGELOG.md | 4 ----
shared/typos/change-notes/released/0.2.10.md | 3 ---
shared/typos/codeql-pack.release.yml | 2 +-
shared/typos/qlpack.yml | 2 +-
shared/util/CHANGELOG.md | 4 ----
shared/util/change-notes/released/0.2.10.md | 3 ---
shared/util/codeql-pack.release.yml | 2 +-
shared/util/qlpack.yml | 2 +-
shared/yaml/CHANGELOG.md | 4 ----
shared/yaml/change-notes/released/0.2.10.md | 3 ---
shared/yaml/codeql-pack.release.yml | 2 +-
shared/yaml/qlpack.yml | 2 +-
swift/ql/lib/CHANGELOG.md | 6 ------
.../0.3.10.md => 2024-02-22-extension-patch.md} | 7 +++----
swift/ql/lib/codeql-pack.release.yml | 2 +-
swift/ql/lib/qlpack.yml | 2 +-
swift/ql/src/CHANGELOG.md | 4 ----
swift/ql/src/change-notes/released/0.3.10.md | 3 ---
swift/ql/src/codeql-pack.release.yml | 2 +-
swift/ql/src/qlpack.yml | 2 +-
150 files changed, 168 insertions(+), 394 deletions(-)
rename cpp/ql/lib/change-notes/{released/0.12.7.md => 2024-02-26-ir-named-destructors.md} (54%)
rename cpp/ql/src/change-notes/{released/0.9.6.md => 2024-02-16-modelled-functions-block-flow.md} (77%)
create mode 100644 cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
delete mode 100644 csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
delete mode 100644 csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
create mode 100644 csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
create mode 100644 csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
create mode 100644 csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
create mode 100644 csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
create mode 100644 csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
create mode 100644 csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
delete mode 100644 csharp/ql/lib/change-notes/released/0.8.10.md
rename csharp/ql/src/change-notes/{released/0.8.10.md => 2024-02-06-threat-models.md} (88%)
delete mode 100644 go/ql/consistency-queries/change-notes/released/0.0.9.md
create mode 100644 go/ql/lib/change-notes/2024-02-14-range-map-read.md
rename go/ql/lib/change-notes/{released/0.7.10.md => 2024-03-04-autobuilder-changes.md} (68%)
delete mode 100644 go/ql/src/change-notes/released/0.7.10.md
delete mode 100644 java/ql/automodel/src/change-notes/released/0.0.17.md
create mode 100644 java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
create mode 100644 java/ql/lib/change-notes/2024-02-27-error-types.md
create mode 100644 java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
delete mode 100644 java/ql/lib/change-notes/released/0.8.10.md
create mode 100644 java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
rename java/ql/src/change-notes/{released/0.8.10.md => 2024-03-04-sensitive-log-remove-null-from-sources.md} (54%)
delete mode 100644 javascript/ql/lib/change-notes/released/0.8.10.md
delete mode 100644 javascript/ql/src/change-notes/released/0.8.10.md
delete mode 100644 misc/suite-helpers/change-notes/released/0.7.10.md
create mode 100644 python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
rename python/ql/lib/change-notes/{released/0.11.10.md => 2024-03-01-dict-update-content.md} (52%)
rename python/ql/src/change-notes/{released/0.9.10.md => 2024-03-04-nosql-injection.md} (81%)
create mode 100644 ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
create mode 100644 ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
create mode 100644 ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
create mode 100644 ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
delete mode 100644 ruby/ql/lib/change-notes/released/0.8.10.md
create mode 100644 ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
rename ruby/ql/src/change-notes/{released/0.8.10.md => 2024-03-01-method-code-injection-sinks.md} (51%)
delete mode 100644 shared/controlflow/change-notes/released/0.1.10.md
delete mode 100644 shared/dataflow/change-notes/released/0.2.1.md
delete mode 100644 shared/mad/change-notes/released/0.2.10.md
delete mode 100644 shared/rangeanalysis/change-notes/released/0.0.9.md
delete mode 100644 shared/regex/change-notes/released/0.2.10.md
delete mode 100644 shared/ssa/change-notes/released/0.2.10.md
delete mode 100644 shared/threat-models/change-notes/released/0.0.9.md
delete mode 100644 shared/tutorial/change-notes/released/0.2.10.md
delete mode 100644 shared/typetracking/change-notes/released/0.2.10.md
delete mode 100644 shared/typos/change-notes/released/0.2.10.md
delete mode 100644 shared/util/change-notes/released/0.2.10.md
delete mode 100644 shared/yaml/change-notes/released/0.2.10.md
rename swift/ql/lib/change-notes/{released/0.3.10.md => 2024-02-22-extension-patch.md} (83%)
delete mode 100644 swift/ql/src/change-notes/released/0.3.10.md
diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md
index e1c0dfbecd9..b3091ec37d8 100644
--- a/cpp/ql/lib/CHANGELOG.md
+++ b/cpp/ql/lib/CHANGELOG.md
@@ -1,9 +1,3 @@
-## 0.12.7
-
-### Minor Analysis Improvements
-
-* Added destructors for named objects to the intermediate representation.
-
## 0.12.6
### New Features
diff --git a/cpp/ql/lib/change-notes/released/0.12.7.md b/cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md
similarity index 54%
rename from cpp/ql/lib/change-notes/released/0.12.7.md
rename to cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md
index 856a8b665c7..4e35decaf8e 100644
--- a/cpp/ql/lib/change-notes/released/0.12.7.md
+++ b/cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md
@@ -1,5 +1,4 @@
-## 0.12.7
-
-### Minor Analysis Improvements
-
-* Added destructors for named objects to the intermediate representation.
+---
+category: minorAnalysis
+---
+* Added destructors for named objects to the intermediate representation.
\ No newline at end of file
diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml
index 20419e9c610..170a312c104 100644
--- a/cpp/ql/lib/codeql-pack.release.yml
+++ b/cpp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.12.7
+lastReleaseVersion: 0.12.6
diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml
index 3bb9229bf94..8e201fff594 100644
--- a/cpp/ql/lib/qlpack.yml
+++ b/cpp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-all
-version: 0.12.7
+version: 0.12.7-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md
index f6acd424bb0..ffcd73ff5d7 100644
--- a/cpp/ql/src/CHANGELOG.md
+++ b/cpp/ql/src/CHANGELOG.md
@@ -1,10 +1,3 @@
-## 0.9.6
-
-### Minor Analysis Improvements
-
-* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
-* The new C/C++ dataflow and taint-tracking libraries (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`) now implicitly assume that dataflow and taint modelled via `DataFlowFunction` and `TaintFunction` always fully overwrite their buffers and thus act as flow barriers. As a result, many dataflow and taint-tracking queries now produce fewer false positives. To remove this assumption and go back to the previous behavior for a given model, one can override the new `isPartialWrite` predicate.
-
## 0.9.5
### Minor Analysis Improvements
diff --git a/cpp/ql/src/change-notes/released/0.9.6.md b/cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md
similarity index 77%
rename from cpp/ql/src/change-notes/released/0.9.6.md
rename to cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md
index 0c85f3f9f0f..d6ef3c3e056 100644
--- a/cpp/ql/src/change-notes/released/0.9.6.md
+++ b/cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md
@@ -1,6 +1,4 @@
-## 0.9.6
-
-### Minor Analysis Improvements
-
-* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
+---
+category: minorAnalysis
+---
* The new C/C++ dataflow and taint-tracking libraries (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`) now implicitly assume that dataflow and taint modelled via `DataFlowFunction` and `TaintFunction` always fully overwrite their buffers and thus act as flow barriers. As a result, many dataflow and taint-tracking queries now produce fewer false positives. To remove this assumption and go back to the previous behavior for a given model, one can override the new `isPartialWrite` predicate.
diff --git a/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md b/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
new file mode 100644
index 00000000000..2e5933a61e8
--- /dev/null
+++ b/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
\ No newline at end of file
diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml
index 19139c132b2..460240feaff 100644
--- a/cpp/ql/src/codeql-pack.release.yml
+++ b/cpp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.9.6
+lastReleaseVersion: 0.9.5
diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml
index 4052647bb97..31bd20166b2 100644
--- a/cpp/ql/src/qlpack.yml
+++ b/cpp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-queries
-version: 0.9.6
+version: 0.9.6-dev
groups:
- cpp
- queries
diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
index 82eacfc84f7..190b83b0f25 100644
--- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
+++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 1.7.10
-
-No user-facing changes.
-
## 1.7.9
No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
deleted file mode 100644
index 8e8007d8475..00000000000
--- a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 1.7.10
-
-No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
index 31c7fe07020..678da6bc37e 100644
--- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
+++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.7.10
+lastReleaseVersion: 1.7.9
diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
index ee993bed0c9..7e643b0fac3 100644
--- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
-version: 1.7.10
+version: 1.7.10-dev
groups:
- csharp
- solorigate
diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
index 82eacfc84f7..190b83b0f25 100644
--- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
+++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 1.7.10
-
-No user-facing changes.
-
## 1.7.9
No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
deleted file mode 100644
index 8e8007d8475..00000000000
--- a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 1.7.10
-
-No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
index 31c7fe07020..678da6bc37e 100644
--- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
+++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.7.10
+lastReleaseVersion: 1.7.9
diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
index 1f421754fc8..8654bbfd031 100644
--- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
-version: 1.7.10
+version: 1.7.10-dev
groups:
- csharp
- solorigate
diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md
index 16cc14259e1..95fd64c5270 100644
--- a/csharp/ql/lib/CHANGELOG.md
+++ b/csharp/ql/lib/CHANGELOG.md
@@ -1,17 +1,3 @@
-## 0.8.10
-
-### Major Analysis Improvements
-
-* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
-* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
-
-### Minor Analysis Improvements
-
-* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
-* C# 12: Add extractor and QL library support for `ref readonly` parameters.
-* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
-* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
-
## 0.8.9
### Minor Analysis Improvements
diff --git a/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md b/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
new file mode 100644
index 00000000000..6bb8e99c71e
--- /dev/null
+++ b/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
diff --git a/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md b/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
new file mode 100644
index 00000000000..d6ffbd523ac
--- /dev/null
+++ b/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
@@ -0,0 +1,4 @@
+---
+category: majorAnalysis
+---
+* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
diff --git a/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md b/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
new file mode 100644
index 00000000000..9b1739b9b6d
--- /dev/null
+++ b/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
diff --git a/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md b/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
new file mode 100644
index 00000000000..66ab65083dc
--- /dev/null
+++ b/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
@@ -0,0 +1,4 @@
+---
+category: majorAnalysis
+---
+* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
\ No newline at end of file
diff --git a/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md b/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
new file mode 100644
index 00000000000..8749c790954
--- /dev/null
+++ b/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
diff --git a/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md b/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
new file mode 100644
index 00000000000..586b5341d29
--- /dev/null
+++ b/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* C# 12: Add extractor and QL library support for `ref readonly` parameters.
diff --git a/csharp/ql/lib/change-notes/released/0.8.10.md b/csharp/ql/lib/change-notes/released/0.8.10.md
deleted file mode 100644
index f591ddc5b21..00000000000
--- a/csharp/ql/lib/change-notes/released/0.8.10.md
+++ /dev/null
@@ -1,13 +0,0 @@
-## 0.8.10
-
-### Major Analysis Improvements
-
-* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
-* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
-
-### Minor Analysis Improvements
-
-* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
-* C# 12: Add extractor and QL library support for `ref readonly` parameters.
-* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
-* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/csharp/ql/lib/codeql-pack.release.yml
+++ b/csharp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml
index 93c5c1120a2..d75ea3c6320 100644
--- a/csharp/ql/lib/qlpack.yml
+++ b/csharp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-all
-version: 0.8.10
+version: 0.8.10-dev
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp
diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md
index 46c939e5cee..9fe1609363f 100644
--- a/csharp/ql/src/CHANGELOG.md
+++ b/csharp/ql/src/CHANGELOG.md
@@ -1,9 +1,3 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
-
## 0.8.9
### Minor Analysis Improvements
diff --git a/csharp/ql/src/change-notes/released/0.8.10.md b/csharp/ql/src/change-notes/2024-02-06-threat-models.md
similarity index 88%
rename from csharp/ql/src/change-notes/released/0.8.10.md
rename to csharp/ql/src/change-notes/2024-02-06-threat-models.md
index 702161c3d28..69ac4e4dc17 100644
--- a/csharp/ql/src/change-notes/released/0.8.10.md
+++ b/csharp/ql/src/change-notes/2024-02-06-threat-models.md
@@ -1,5 +1,4 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
+---
+category: minorAnalysis
+---
+* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
\ No newline at end of file
diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/csharp/ql/src/codeql-pack.release.yml
+++ b/csharp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml
index 46384094b19..9ee23cc7307 100644
--- a/csharp/ql/src/qlpack.yml
+++ b/csharp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-queries
-version: 0.8.10
+version: 0.8.10-dev
groups:
- csharp
- queries
diff --git a/go/ql/consistency-queries/CHANGELOG.md b/go/ql/consistency-queries/CHANGELOG.md
index a59e560c415..fba2a870356 100644
--- a/go/ql/consistency-queries/CHANGELOG.md
+++ b/go/ql/consistency-queries/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.0.9
-
-No user-facing changes.
-
## 0.0.8
No user-facing changes.
diff --git a/go/ql/consistency-queries/change-notes/released/0.0.9.md b/go/ql/consistency-queries/change-notes/released/0.0.9.md
deleted file mode 100644
index c9e17c6d6cf..00000000000
--- a/go/ql/consistency-queries/change-notes/released/0.0.9.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.0.9
-
-No user-facing changes.
diff --git a/go/ql/consistency-queries/codeql-pack.release.yml b/go/ql/consistency-queries/codeql-pack.release.yml
index ecdd64fbab8..58fdc6b45de 100644
--- a/go/ql/consistency-queries/codeql-pack.release.yml
+++ b/go/ql/consistency-queries/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.9
+lastReleaseVersion: 0.0.8
diff --git a/go/ql/consistency-queries/qlpack.yml b/go/ql/consistency-queries/qlpack.yml
index d5a2fbee5f1..b574796b995 100644
--- a/go/ql/consistency-queries/qlpack.yml
+++ b/go/ql/consistency-queries/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql-go-consistency-queries
-version: 0.0.9
+version: 0.0.9-dev
groups:
- go
- queries
diff --git a/go/ql/lib/CHANGELOG.md b/go/ql/lib/CHANGELOG.md
index fee5fd37a26..65a2376217b 100644
--- a/go/ql/lib/CHANGELOG.md
+++ b/go/ql/lib/CHANGELOG.md
@@ -1,14 +1,3 @@
-## 0.7.10
-
-### Major Analysis Improvements
-
-* We have significantly improved the Go autobuilder to understand a greater range of project layouts, which allows Go source files to be analysed that could previously not be processed.
-* Go 1.22 has been included in the range of supported Go versions.
-
-### Bug Fixes
-
-* Fixed dataflow out of a `map` using a `range` statement.
-
## 0.7.9
No user-facing changes.
diff --git a/go/ql/lib/change-notes/2024-02-14-range-map-read.md b/go/ql/lib/change-notes/2024-02-14-range-map-read.md
new file mode 100644
index 00000000000..ea45737a72e
--- /dev/null
+++ b/go/ql/lib/change-notes/2024-02-14-range-map-read.md
@@ -0,0 +1,4 @@
+---
+category: fix
+---
+* Fixed dataflow out of a `map` using a `range` statement.
diff --git a/go/ql/lib/change-notes/released/0.7.10.md b/go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md
similarity index 68%
rename from go/ql/lib/change-notes/released/0.7.10.md
rename to go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md
index 55954f8a394..0442a571029 100644
--- a/go/ql/lib/change-notes/released/0.7.10.md
+++ b/go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md
@@ -1,10 +1,5 @@
-## 0.7.10
-
-### Major Analysis Improvements
-
+---
+category: majorAnalysis
+---
* We have significantly improved the Go autobuilder to understand a greater range of project layouts, which allows Go source files to be analysed that could previously not be processed.
* Go 1.22 has been included in the range of supported Go versions.
-
-### Bug Fixes
-
-* Fixed dataflow out of a `map` using a `range` statement.
diff --git a/go/ql/lib/codeql-pack.release.yml b/go/ql/lib/codeql-pack.release.yml
index 67518567297..576395f3405 100644
--- a/go/ql/lib/codeql-pack.release.yml
+++ b/go/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.10
+lastReleaseVersion: 0.7.9
diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml
index 8cc190fa880..f21e478efa6 100644
--- a/go/ql/lib/qlpack.yml
+++ b/go/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/go-all
-version: 0.7.10
+version: 0.7.10-dev
groups: go
dbscheme: go.dbscheme
extractor: go
diff --git a/go/ql/src/CHANGELOG.md b/go/ql/src/CHANGELOG.md
index 24e38b9890e..d95165a3a34 100644
--- a/go/ql/src/CHANGELOG.md
+++ b/go/ql/src/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.7.10
-
-No user-facing changes.
-
## 0.7.9
### New Queries
diff --git a/go/ql/src/change-notes/released/0.7.10.md b/go/ql/src/change-notes/released/0.7.10.md
deleted file mode 100644
index 989c5b8f682..00000000000
--- a/go/ql/src/change-notes/released/0.7.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.7.10
-
-No user-facing changes.
diff --git a/go/ql/src/codeql-pack.release.yml b/go/ql/src/codeql-pack.release.yml
index 67518567297..576395f3405 100644
--- a/go/ql/src/codeql-pack.release.yml
+++ b/go/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.10
+lastReleaseVersion: 0.7.9
diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml
index 4ded3a52f63..d91cab59612 100644
--- a/go/ql/src/qlpack.yml
+++ b/go/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/go-queries
-version: 0.7.10
+version: 0.7.10-dev
groups:
- go
- queries
diff --git a/java/ql/automodel/src/CHANGELOG.md b/java/ql/automodel/src/CHANGELOG.md
index c3282c773a9..4a3c54adb38 100644
--- a/java/ql/automodel/src/CHANGELOG.md
+++ b/java/ql/automodel/src/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.0.17
-
-No user-facing changes.
-
## 0.0.16
No user-facing changes.
diff --git a/java/ql/automodel/src/change-notes/released/0.0.17.md b/java/ql/automodel/src/change-notes/released/0.0.17.md
deleted file mode 100644
index 62cc89030a6..00000000000
--- a/java/ql/automodel/src/change-notes/released/0.0.17.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.0.17
-
-No user-facing changes.
diff --git a/java/ql/automodel/src/codeql-pack.release.yml b/java/ql/automodel/src/codeql-pack.release.yml
index cbc3d3cd493..a49f7be4cff 100644
--- a/java/ql/automodel/src/codeql-pack.release.yml
+++ b/java/ql/automodel/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.17
+lastReleaseVersion: 0.0.16
diff --git a/java/ql/automodel/src/qlpack.yml b/java/ql/automodel/src/qlpack.yml
index 59fab0cdcc5..898239be098 100644
--- a/java/ql/automodel/src/qlpack.yml
+++ b/java/ql/automodel/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-automodel-queries
-version: 0.0.17
+version: 0.0.17-dev
groups:
- java
- automodel
diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md
index 2a02ccee6ab..d369cbdc931 100644
--- a/java/ql/lib/CHANGELOG.md
+++ b/java/ql/lib/CHANGELOG.md
@@ -1,14 +1,3 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
-
-### Bug Fixes
-
-* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
-* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
-
## 0.8.9
### Deprecated APIs
diff --git a/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md b/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
new file mode 100644
index 00000000000..eb560fba07d
--- /dev/null
+++ b/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
@@ -0,0 +1,4 @@
+---
+category: fix
+---
+* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
diff --git a/java/ql/lib/change-notes/2024-02-27-error-types.md b/java/ql/lib/change-notes/2024-02-27-error-types.md
new file mode 100644
index 00000000000..cdc6d7620aa
--- /dev/null
+++ b/java/ql/lib/change-notes/2024-02-27-error-types.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
diff --git a/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md b/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
new file mode 100644
index 00000000000..a0227088ae9
--- /dev/null
+++ b/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
@@ -0,0 +1,4 @@
+---
+category: fix
+---
+* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
diff --git a/java/ql/lib/change-notes/released/0.8.10.md b/java/ql/lib/change-notes/released/0.8.10.md
deleted file mode 100644
index b45f14bf347..00000000000
--- a/java/ql/lib/change-notes/released/0.8.10.md
+++ /dev/null
@@ -1,10 +0,0 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
-
-### Bug Fixes
-
-* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
-* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
diff --git a/java/ql/lib/codeql-pack.release.yml b/java/ql/lib/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/java/ql/lib/codeql-pack.release.yml
+++ b/java/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml
index 428eedc75e3..15b4982d41e 100644
--- a/java/ql/lib/qlpack.yml
+++ b/java/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-all
-version: 0.8.10
+version: 0.8.10-dev
groups: java
dbscheme: config/semmlecode.dbscheme
extractor: java
diff --git a/java/ql/src/CHANGELOG.md b/java/ql/src/CHANGELOG.md
index c61275f5ed8..5d835351453 100644
--- a/java/ql/src/CHANGELOG.md
+++ b/java/ql/src/CHANGELOG.md
@@ -1,13 +1,3 @@
-## 0.8.10
-
-### New Queries
-
-* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
-
-### Minor Analysis Improvements
-
-* To reduce the number of false positives in the query "Insertion of sensitive information into log files" (`java/sensitive-log`), variables with names that contain "null" (case-insensitively) are no longer considered sources of sensitive information.
-
## 0.8.9
### New Queries
diff --git a/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md b/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
new file mode 100644
index 00000000000..1de07727796
--- /dev/null
+++ b/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
@@ -0,0 +1,4 @@
+---
+category: newQuery
+---
+* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
\ No newline at end of file
diff --git a/java/ql/src/change-notes/released/0.8.10.md b/java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md
similarity index 54%
rename from java/ql/src/change-notes/released/0.8.10.md
rename to java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md
index c5d18ae3379..0bb4f18f2bd 100644
--- a/java/ql/src/change-notes/released/0.8.10.md
+++ b/java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md
@@ -1,9 +1,4 @@
-## 0.8.10
-
-### New Queries
-
-* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
-
-### Minor Analysis Improvements
-
+---
+category: minorAnalysis
+---
* To reduce the number of false positives in the query "Insertion of sensitive information into log files" (`java/sensitive-log`), variables with names that contain "null" (case-insensitively) are no longer considered sources of sensitive information.
diff --git a/java/ql/src/codeql-pack.release.yml b/java/ql/src/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/java/ql/src/codeql-pack.release.yml
+++ b/java/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml
index ebbdbeee3b2..8f4de528e21 100644
--- a/java/ql/src/qlpack.yml
+++ b/java/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-queries
-version: 0.8.10
+version: 0.8.10-dev
groups:
- java
- queries
diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md
index d5edcc00513..5b97ebbb22b 100644
--- a/javascript/ql/lib/CHANGELOG.md
+++ b/javascript/ql/lib/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.8.10
-
-No user-facing changes.
-
## 0.8.9
### Minor Analysis Improvements
diff --git a/javascript/ql/lib/change-notes/released/0.8.10.md b/javascript/ql/lib/change-notes/released/0.8.10.md
deleted file mode 100644
index 777bbd2fded..00000000000
--- a/javascript/ql/lib/change-notes/released/0.8.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.8.10
-
-No user-facing changes.
diff --git a/javascript/ql/lib/codeql-pack.release.yml b/javascript/ql/lib/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/javascript/ql/lib/codeql-pack.release.yml
+++ b/javascript/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml
index da16493a21c..ef3ca7521ac 100644
--- a/javascript/ql/lib/qlpack.yml
+++ b/javascript/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-all
-version: 0.8.10
+version: 0.8.10-dev
groups: javascript
dbscheme: semmlecode.javascript.dbscheme
extractor: javascript
diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md
index b9627cac5ee..85516e3625d 100644
--- a/javascript/ql/src/CHANGELOG.md
+++ b/javascript/ql/src/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.8.10
-
-No user-facing changes.
-
## 0.8.9
### Bug Fixes
diff --git a/javascript/ql/src/change-notes/released/0.8.10.md b/javascript/ql/src/change-notes/released/0.8.10.md
deleted file mode 100644
index 777bbd2fded..00000000000
--- a/javascript/ql/src/change-notes/released/0.8.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.8.10
-
-No user-facing changes.
diff --git a/javascript/ql/src/codeql-pack.release.yml b/javascript/ql/src/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/javascript/ql/src/codeql-pack.release.yml
+++ b/javascript/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml
index d224952c564..b6181aa30e9 100644
--- a/javascript/ql/src/qlpack.yml
+++ b/javascript/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-queries
-version: 0.8.10
+version: 0.8.10-dev
groups:
- javascript
- queries
diff --git a/misc/suite-helpers/CHANGELOG.md b/misc/suite-helpers/CHANGELOG.md
index 1c4455b66c4..3c06dd69b0f 100644
--- a/misc/suite-helpers/CHANGELOG.md
+++ b/misc/suite-helpers/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.7.10
-
-No user-facing changes.
-
## 0.7.9
No user-facing changes.
diff --git a/misc/suite-helpers/change-notes/released/0.7.10.md b/misc/suite-helpers/change-notes/released/0.7.10.md
deleted file mode 100644
index 989c5b8f682..00000000000
--- a/misc/suite-helpers/change-notes/released/0.7.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.7.10
-
-No user-facing changes.
diff --git a/misc/suite-helpers/codeql-pack.release.yml b/misc/suite-helpers/codeql-pack.release.yml
index 67518567297..576395f3405 100644
--- a/misc/suite-helpers/codeql-pack.release.yml
+++ b/misc/suite-helpers/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.10
+lastReleaseVersion: 0.7.9
diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml
index 54d978d5efe..49b7a6bda4c 100644
--- a/misc/suite-helpers/qlpack.yml
+++ b/misc/suite-helpers/qlpack.yml
@@ -1,4 +1,4 @@
name: codeql/suite-helpers
-version: 0.7.10
+version: 0.7.10-dev
groups: shared
warnOnImplicitThis: true
diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md
index f095607ca1b..e6f318c51ea 100644
--- a/python/ql/lib/CHANGELOG.md
+++ b/python/ql/lib/CHANGELOG.md
@@ -1,10 +1,3 @@
-## 0.11.10
-
-### Minor Analysis Improvements
-
-* Fixed missing flow for dictionary updates (`d[] = ...`) when `` is a string constant not used in dictionary literals or as name of keyword-argument.
-* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
-
## 0.11.9
### Minor Analysis Improvements
diff --git a/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md b/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
new file mode 100644
index 00000000000..3c47c6ba866
--- /dev/null
+++ b/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
diff --git a/python/ql/lib/change-notes/released/0.11.10.md b/python/ql/lib/change-notes/2024-03-01-dict-update-content.md
similarity index 52%
rename from python/ql/lib/change-notes/released/0.11.10.md
rename to python/ql/lib/change-notes/2024-03-01-dict-update-content.md
index ed873724e4f..dfb8d247fff 100644
--- a/python/ql/lib/change-notes/released/0.11.10.md
+++ b/python/ql/lib/change-notes/2024-03-01-dict-update-content.md
@@ -1,6 +1,4 @@
-## 0.11.10
-
-### Minor Analysis Improvements
-
+---
+category: minorAnalysis
+---
* Fixed missing flow for dictionary updates (`d[] = ...`) when `` is a string constant not used in dictionary literals or as name of keyword-argument.
-* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
diff --git a/python/ql/lib/codeql-pack.release.yml b/python/ql/lib/codeql-pack.release.yml
index ddddcbe9193..b064d1778a1 100644
--- a/python/ql/lib/codeql-pack.release.yml
+++ b/python/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.11.10
+lastReleaseVersion: 0.11.9
diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml
index 59a8b4c96d1..e9f66e205f2 100644
--- a/python/ql/lib/qlpack.yml
+++ b/python/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/python-all
-version: 0.11.10
+version: 0.11.10-dev
groups: python
dbscheme: semmlecode.python.dbscheme
extractor: python
diff --git a/python/ql/src/CHANGELOG.md b/python/ql/src/CHANGELOG.md
index d4245aba7a6..50762bcbf34 100644
--- a/python/ql/src/CHANGELOG.md
+++ b/python/ql/src/CHANGELOG.md
@@ -1,9 +1,3 @@
-## 0.9.10
-
-### New Queries
-
-* The query `py/nosql-injection` for finding NoSQL injection vulnerabilities is now part of the default security suite.
-
## 0.9.9
No user-facing changes.
diff --git a/python/ql/src/change-notes/released/0.9.10.md b/python/ql/src/change-notes/2024-03-04-nosql-injection.md
similarity index 81%
rename from python/ql/src/change-notes/released/0.9.10.md
rename to python/ql/src/change-notes/2024-03-04-nosql-injection.md
index 4cbb221b789..6e98540c757 100644
--- a/python/ql/src/change-notes/released/0.9.10.md
+++ b/python/ql/src/change-notes/2024-03-04-nosql-injection.md
@@ -1,5 +1,4 @@
-## 0.9.10
-
-### New Queries
-
+---
+category: newQuery
+---
* The query `py/nosql-injection` for finding NoSQL injection vulnerabilities is now part of the default security suite.
diff --git a/python/ql/src/codeql-pack.release.yml b/python/ql/src/codeql-pack.release.yml
index d086ed69541..aabed7c396b 100644
--- a/python/ql/src/codeql-pack.release.yml
+++ b/python/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.9.10
+lastReleaseVersion: 0.9.9
diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml
index c920f667836..aa18f2d8707 100644
--- a/python/ql/src/qlpack.yml
+++ b/python/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/python-queries
-version: 0.9.10
+version: 0.9.10-dev
groups:
- python
- queries
diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md
index c61a12e0f4a..a623a151e89 100644
--- a/ruby/ql/lib/CHANGELOG.md
+++ b/ruby/ql/lib/CHANGELOG.md
@@ -1,12 +1,3 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
-* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
-* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
-* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
-
## 0.8.9
### Minor Analysis Improvements
diff --git a/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md b/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
new file mode 100644
index 00000000000..c2276f284a8
--- /dev/null
+++ b/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md b/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
new file mode 100644
index 00000000000..1486c7a472d
--- /dev/null
+++ b/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md b/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
new file mode 100644
index 00000000000..6f3a90768ba
--- /dev/null
+++ b/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md b/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
new file mode 100644
index 00000000000..350e049b5bf
--- /dev/null
+++ b/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/released/0.8.10.md b/ruby/ql/lib/change-notes/released/0.8.10.md
deleted file mode 100644
index 666e28f840e..00000000000
--- a/ruby/ql/lib/change-notes/released/0.8.10.md
+++ /dev/null
@@ -1,8 +0,0 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
-* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
-* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
-* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
diff --git a/ruby/ql/lib/codeql-pack.release.yml b/ruby/ql/lib/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/ruby/ql/lib/codeql-pack.release.yml
+++ b/ruby/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml
index de5b41999fe..7d409b83adb 100644
--- a/ruby/ql/lib/qlpack.yml
+++ b/ruby/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ruby-all
-version: 0.8.10
+version: 0.8.10-dev
groups: ruby
extractor: ruby
dbscheme: ruby.dbscheme
diff --git a/ruby/ql/src/CHANGELOG.md b/ruby/ql/src/CHANGELOG.md
index f875b6d16ad..4149c728eff 100644
--- a/ruby/ql/src/CHANGELOG.md
+++ b/ruby/ql/src/CHANGELOG.md
@@ -1,10 +1,3 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
-* Added additional request sources for Ruby on Rails.
-
## 0.8.9
No user-facing changes.
diff --git a/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md b/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
new file mode 100644
index 00000000000..84ea696dfef
--- /dev/null
+++ b/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Added additional request sources for Ruby on Rails.
\ No newline at end of file
diff --git a/ruby/ql/src/change-notes/released/0.8.10.md b/ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md
similarity index 51%
rename from ruby/ql/src/change-notes/released/0.8.10.md
rename to ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md
index 985cdf8d22e..43e40d3fd53 100644
--- a/ruby/ql/src/change-notes/released/0.8.10.md
+++ b/ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md
@@ -1,6 +1,4 @@
-## 0.8.10
-
-### Minor Analysis Improvements
-
-* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
-* Added additional request sources for Ruby on Rails.
+---
+category: minorAnalysis
+---
+* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
\ No newline at end of file
diff --git a/ruby/ql/src/codeql-pack.release.yml b/ruby/ql/src/codeql-pack.release.yml
index 0521f0f75fa..5290c29b7fe 100644
--- a/ruby/ql/src/codeql-pack.release.yml
+++ b/ruby/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.10
+lastReleaseVersion: 0.8.9
diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml
index 5e379268234..8af7f9fd797 100644
--- a/ruby/ql/src/qlpack.yml
+++ b/ruby/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ruby-queries
-version: 0.8.10
+version: 0.8.10-dev
groups:
- ruby
- queries
diff --git a/shared/controlflow/CHANGELOG.md b/shared/controlflow/CHANGELOG.md
index 75f2ca53f98..dbfa6ef4512 100644
--- a/shared/controlflow/CHANGELOG.md
+++ b/shared/controlflow/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.1.10
-
-No user-facing changes.
-
## 0.1.9
No user-facing changes.
diff --git a/shared/controlflow/change-notes/released/0.1.10.md b/shared/controlflow/change-notes/released/0.1.10.md
deleted file mode 100644
index 47358eeee93..00000000000
--- a/shared/controlflow/change-notes/released/0.1.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.1.10
-
-No user-facing changes.
diff --git a/shared/controlflow/codeql-pack.release.yml b/shared/controlflow/codeql-pack.release.yml
index 30f5ca88be0..1425c0edf7f 100644
--- a/shared/controlflow/codeql-pack.release.yml
+++ b/shared/controlflow/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.1.10
+lastReleaseVersion: 0.1.9
diff --git a/shared/controlflow/qlpack.yml b/shared/controlflow/qlpack.yml
index 1d43802be42..9d35a678276 100644
--- a/shared/controlflow/qlpack.yml
+++ b/shared/controlflow/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/controlflow
-version: 0.1.10
+version: 0.1.10-dev
groups: shared
library: true
dependencies:
diff --git a/shared/dataflow/CHANGELOG.md b/shared/dataflow/CHANGELOG.md
index ef80788bded..67a5bf589f4 100644
--- a/shared/dataflow/CHANGELOG.md
+++ b/shared/dataflow/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.1
-
-No user-facing changes.
-
## 0.2.0
### Breaking Changes
diff --git a/shared/dataflow/change-notes/released/0.2.1.md b/shared/dataflow/change-notes/released/0.2.1.md
deleted file mode 100644
index 3dbfc85fe11..00000000000
--- a/shared/dataflow/change-notes/released/0.2.1.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.1
-
-No user-facing changes.
diff --git a/shared/dataflow/codeql-pack.release.yml b/shared/dataflow/codeql-pack.release.yml
index df29a726bcc..5274e27ed52 100644
--- a/shared/dataflow/codeql-pack.release.yml
+++ b/shared/dataflow/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.1
+lastReleaseVersion: 0.2.0
diff --git a/shared/dataflow/qlpack.yml b/shared/dataflow/qlpack.yml
index ee422e02ea9..1e7becf71c4 100644
--- a/shared/dataflow/qlpack.yml
+++ b/shared/dataflow/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/dataflow
-version: 0.2.1
+version: 0.2.1-dev
groups: shared
library: true
dependencies:
diff --git a/shared/mad/CHANGELOG.md b/shared/mad/CHANGELOG.md
index 4730366775e..4d09057118c 100644
--- a/shared/mad/CHANGELOG.md
+++ b/shared/mad/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/mad/change-notes/released/0.2.10.md b/shared/mad/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/mad/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/mad/codeql-pack.release.yml b/shared/mad/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/mad/codeql-pack.release.yml
+++ b/shared/mad/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml
index 6d7269ef3da..22c8f271ccc 100644
--- a/shared/mad/qlpack.yml
+++ b/shared/mad/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/mad
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
dependencies: null
diff --git a/shared/rangeanalysis/CHANGELOG.md b/shared/rangeanalysis/CHANGELOG.md
index 9943dcb7972..5b8dbcfab22 100644
--- a/shared/rangeanalysis/CHANGELOG.md
+++ b/shared/rangeanalysis/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.0.9
-
-No user-facing changes.
-
## 0.0.8
No user-facing changes.
diff --git a/shared/rangeanalysis/change-notes/released/0.0.9.md b/shared/rangeanalysis/change-notes/released/0.0.9.md
deleted file mode 100644
index c9e17c6d6cf..00000000000
--- a/shared/rangeanalysis/change-notes/released/0.0.9.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.0.9
-
-No user-facing changes.
diff --git a/shared/rangeanalysis/codeql-pack.release.yml b/shared/rangeanalysis/codeql-pack.release.yml
index ecdd64fbab8..58fdc6b45de 100644
--- a/shared/rangeanalysis/codeql-pack.release.yml
+++ b/shared/rangeanalysis/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.9
+lastReleaseVersion: 0.0.8
diff --git a/shared/rangeanalysis/qlpack.yml b/shared/rangeanalysis/qlpack.yml
index 01db5d5734d..836fe51ee34 100644
--- a/shared/rangeanalysis/qlpack.yml
+++ b/shared/rangeanalysis/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/rangeanalysis
-version: 0.0.9
+version: 0.0.9-dev
groups: shared
library: true
dependencies:
diff --git a/shared/regex/CHANGELOG.md b/shared/regex/CHANGELOG.md
index c05869c153d..cd5f91f71ec 100644
--- a/shared/regex/CHANGELOG.md
+++ b/shared/regex/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/regex/change-notes/released/0.2.10.md b/shared/regex/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/regex/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/regex/codeql-pack.release.yml b/shared/regex/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/regex/codeql-pack.release.yml
+++ b/shared/regex/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml
index 0d4f485312f..ea3f7f9b238 100644
--- a/shared/regex/qlpack.yml
+++ b/shared/regex/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/regex
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
dependencies:
diff --git a/shared/ssa/CHANGELOG.md b/shared/ssa/CHANGELOG.md
index a9161ff578b..01acfae0148 100644
--- a/shared/ssa/CHANGELOG.md
+++ b/shared/ssa/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/ssa/change-notes/released/0.2.10.md b/shared/ssa/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/ssa/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/ssa/codeql-pack.release.yml b/shared/ssa/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/ssa/codeql-pack.release.yml
+++ b/shared/ssa/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml
index 2ad254711a5..19304ad107f 100644
--- a/shared/ssa/qlpack.yml
+++ b/shared/ssa/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ssa
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
dependencies:
diff --git a/shared/threat-models/CHANGELOG.md b/shared/threat-models/CHANGELOG.md
index a59e560c415..fba2a870356 100644
--- a/shared/threat-models/CHANGELOG.md
+++ b/shared/threat-models/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.0.9
-
-No user-facing changes.
-
## 0.0.8
No user-facing changes.
diff --git a/shared/threat-models/change-notes/released/0.0.9.md b/shared/threat-models/change-notes/released/0.0.9.md
deleted file mode 100644
index c9e17c6d6cf..00000000000
--- a/shared/threat-models/change-notes/released/0.0.9.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.0.9
-
-No user-facing changes.
diff --git a/shared/threat-models/codeql-pack.release.yml b/shared/threat-models/codeql-pack.release.yml
index ecdd64fbab8..58fdc6b45de 100644
--- a/shared/threat-models/codeql-pack.release.yml
+++ b/shared/threat-models/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.9
+lastReleaseVersion: 0.0.8
diff --git a/shared/threat-models/qlpack.yml b/shared/threat-models/qlpack.yml
index 60cbbc56fcb..d0ed9a913b2 100644
--- a/shared/threat-models/qlpack.yml
+++ b/shared/threat-models/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/threat-models
-version: 0.0.9
+version: 0.0.9-dev
library: true
groups: shared
dataExtensions:
diff --git a/shared/tutorial/CHANGELOG.md b/shared/tutorial/CHANGELOG.md
index 560ad058d5b..1db3a01af0b 100644
--- a/shared/tutorial/CHANGELOG.md
+++ b/shared/tutorial/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/tutorial/change-notes/released/0.2.10.md b/shared/tutorial/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/tutorial/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/tutorial/codeql-pack.release.yml b/shared/tutorial/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/tutorial/codeql-pack.release.yml
+++ b/shared/tutorial/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml
index 69116705c1b..b595ae9ee70 100644
--- a/shared/tutorial/qlpack.yml
+++ b/shared/tutorial/qlpack.yml
@@ -1,7 +1,7 @@
name: codeql/tutorial
description: Library for the CodeQL detective tutorials, helping new users learn to
write CodeQL queries.
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/shared/typetracking/CHANGELOG.md b/shared/typetracking/CHANGELOG.md
index 350f9ecbeae..afc857bc6bc 100644
--- a/shared/typetracking/CHANGELOG.md
+++ b/shared/typetracking/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/typetracking/change-notes/released/0.2.10.md b/shared/typetracking/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/typetracking/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/typetracking/codeql-pack.release.yml b/shared/typetracking/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/typetracking/codeql-pack.release.yml
+++ b/shared/typetracking/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml
index fbbdcf5162a..b55927f59bb 100644
--- a/shared/typetracking/qlpack.yml
+++ b/shared/typetracking/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/typetracking
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
dependencies:
diff --git a/shared/typos/CHANGELOG.md b/shared/typos/CHANGELOG.md
index 54b1eaa4d58..66c5871d982 100644
--- a/shared/typos/CHANGELOG.md
+++ b/shared/typos/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/typos/change-notes/released/0.2.10.md b/shared/typos/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/typos/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/typos/codeql-pack.release.yml b/shared/typos/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/typos/codeql-pack.release.yml
+++ b/shared/typos/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml
index 4d59d9b3c34..644bfe11bff 100644
--- a/shared/typos/qlpack.yml
+++ b/shared/typos/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/typos
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/shared/util/CHANGELOG.md b/shared/util/CHANGELOG.md
index 1ca1f71bcbc..63832e927fa 100644
--- a/shared/util/CHANGELOG.md
+++ b/shared/util/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/util/change-notes/released/0.2.10.md b/shared/util/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/util/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/util/codeql-pack.release.yml b/shared/util/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/util/codeql-pack.release.yml
+++ b/shared/util/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml
index 28ed738a93d..ca1a866a53d 100644
--- a/shared/util/qlpack.yml
+++ b/shared/util/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/util
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
dependencies: null
diff --git a/shared/yaml/CHANGELOG.md b/shared/yaml/CHANGELOG.md
index 9fd5ebc26ab..e5495abcd50 100644
--- a/shared/yaml/CHANGELOG.md
+++ b/shared/yaml/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.2.10
-
-No user-facing changes.
-
## 0.2.9
No user-facing changes.
diff --git a/shared/yaml/change-notes/released/0.2.10.md b/shared/yaml/change-notes/released/0.2.10.md
deleted file mode 100644
index 81c9722b19f..00000000000
--- a/shared/yaml/change-notes/released/0.2.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.2.10
-
-No user-facing changes.
diff --git a/shared/yaml/codeql-pack.release.yml b/shared/yaml/codeql-pack.release.yml
index a71167814cb..d021cf0a6be 100644
--- a/shared/yaml/codeql-pack.release.yml
+++ b/shared/yaml/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.10
+lastReleaseVersion: 0.2.9
diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml
index 9643ffcec66..de5b47e120a 100644
--- a/shared/yaml/qlpack.yml
+++ b/shared/yaml/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/yaml
-version: 0.2.10
+version: 0.2.10-dev
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/swift/ql/lib/CHANGELOG.md b/swift/ql/lib/CHANGELOG.md
index 8f14bfcedc9..e88cd0259cc 100644
--- a/swift/ql/lib/CHANGELOG.md
+++ b/swift/ql/lib/CHANGELOG.md
@@ -1,9 +1,3 @@
-## 0.3.10
-
-### Bug Fixes
-
-* Fixed an issue where `TypeDecl.getFullName` would get stuck in an loop and fail when minor database inconsistencies are present.
-
## 0.3.9
### Minor Analysis Improvements
diff --git a/swift/ql/lib/change-notes/released/0.3.10.md b/swift/ql/lib/change-notes/2024-02-22-extension-patch.md
similarity index 83%
rename from swift/ql/lib/change-notes/released/0.3.10.md
rename to swift/ql/lib/change-notes/2024-02-22-extension-patch.md
index 9d6286ff58a..7bd78f3b785 100644
--- a/swift/ql/lib/change-notes/released/0.3.10.md
+++ b/swift/ql/lib/change-notes/2024-02-22-extension-patch.md
@@ -1,5 +1,4 @@
-## 0.3.10
-
-### Bug Fixes
-
+---
+category: fix
+---
* Fixed an issue where `TypeDecl.getFullName` would get stuck in an loop and fail when minor database inconsistencies are present.
diff --git a/swift/ql/lib/codeql-pack.release.yml b/swift/ql/lib/codeql-pack.release.yml
index 76ca0ac8ba7..3fa5180bcb4 100644
--- a/swift/ql/lib/codeql-pack.release.yml
+++ b/swift/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.3.10
+lastReleaseVersion: 0.3.9
diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml
index 70ec4798ea8..a37a4cb3d58 100644
--- a/swift/ql/lib/qlpack.yml
+++ b/swift/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/swift-all
-version: 0.3.10
+version: 0.3.10-dev
groups: swift
extractor: swift
dbscheme: swift.dbscheme
diff --git a/swift/ql/src/CHANGELOG.md b/swift/ql/src/CHANGELOG.md
index bda9834c9bc..96615d06972 100644
--- a/swift/ql/src/CHANGELOG.md
+++ b/swift/ql/src/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.3.10
-
-No user-facing changes.
-
## 0.3.9
### New Queries
diff --git a/swift/ql/src/change-notes/released/0.3.10.md b/swift/ql/src/change-notes/released/0.3.10.md
deleted file mode 100644
index 925a48fc52e..00000000000
--- a/swift/ql/src/change-notes/released/0.3.10.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## 0.3.10
-
-No user-facing changes.
diff --git a/swift/ql/src/codeql-pack.release.yml b/swift/ql/src/codeql-pack.release.yml
index 76ca0ac8ba7..3fa5180bcb4 100644
--- a/swift/ql/src/codeql-pack.release.yml
+++ b/swift/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.3.10
+lastReleaseVersion: 0.3.9
diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml
index ba66b065529..e3ead42c98b 100644
--- a/swift/ql/src/qlpack.yml
+++ b/swift/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/swift-queries
-version: 0.3.10
+version: 0.3.10-dev
groups:
- swift
- queries
From 2f058ffb4d0bc7486717a95744c240b9eef87fe6 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Wed, 6 Mar 2024 20:56:51 +0000
Subject: [PATCH 031/497] Release preparation for version 2.16.4
---
cpp/ql/lib/CHANGELOG.md | 6 ++++++
.../0.12.7.md} | 9 +++++----
cpp/ql/lib/codeql-pack.release.yml | 2 +-
cpp/ql/lib/qlpack.yml | 2 +-
cpp/ql/src/CHANGELOG.md | 7 +++++++
.../2024-02-29-non-constant-format-path-query.md | 4 ----
.../0.9.6.md} | 8 +++++---
cpp/ql/src/codeql-pack.release.yml | 2 +-
cpp/ql/src/qlpack.yml | 2 +-
csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md | 4 ++++
.../Solorigate/lib/change-notes/released/1.7.10.md | 3 +++
.../Solorigate/lib/codeql-pack.release.yml | 2 +-
csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +-
csharp/ql/campaigns/Solorigate/src/CHANGELOG.md | 4 ++++
.../Solorigate/src/change-notes/released/1.7.10.md | 3 +++
.../Solorigate/src/codeql-pack.release.yml | 2 +-
csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +-
csharp/ql/lib/CHANGELOG.md | 14 ++++++++++++++
.../change-notes/2024-02-21-getonly-properties.md | 4 ----
.../ql/lib/change-notes/2024-02-22-no-db-stats.md | 4 ----
.../change-notes/2024-02-23-compiler-generated.md | 4 ----
.../2024-02-26-variable-capture-flow.md | 4 ----
.../2024-02-28-experimental-attribute.md | 4 ----
.../2024-02-28-refreadonly-parameter.md | 4 ----
csharp/ql/lib/change-notes/released/0.8.10.md | 13 +++++++++++++
csharp/ql/lib/codeql-pack.release.yml | 2 +-
csharp/ql/lib/qlpack.yml | 2 +-
csharp/ql/src/CHANGELOG.md | 6 ++++++
.../0.8.10.md} | 9 +++++----
csharp/ql/src/codeql-pack.release.yml | 2 +-
csharp/ql/src/qlpack.yml | 2 +-
go/ql/consistency-queries/CHANGELOG.md | 4 ++++
.../change-notes/released/0.0.9.md | 3 +++
go/ql/consistency-queries/codeql-pack.release.yml | 2 +-
go/ql/consistency-queries/qlpack.yml | 2 +-
go/ql/lib/CHANGELOG.md | 11 +++++++++++
.../lib/change-notes/2024-02-14-range-map-read.md | 4 ----
.../0.7.10.md} | 11 ++++++++---
go/ql/lib/codeql-pack.release.yml | 2 +-
go/ql/lib/qlpack.yml | 2 +-
go/ql/src/CHANGELOG.md | 4 ++++
go/ql/src/change-notes/released/0.7.10.md | 3 +++
go/ql/src/codeql-pack.release.yml | 2 +-
go/ql/src/qlpack.yml | 2 +-
java/ql/automodel/src/CHANGELOG.md | 4 ++++
.../automodel/src/change-notes/released/0.0.17.md | 3 +++
java/ql/automodel/src/codeql-pack.release.yml | 2 +-
java/ql/automodel/src/qlpack.yml | 2 +-
java/ql/lib/CHANGELOG.md | 11 +++++++++++
.../change-notes/2024-02-23-widget-flowsteps.md | 4 ----
java/ql/lib/change-notes/2024-02-27-error-types.md | 4 ----
.../lib/change-notes/2024-02-27-mvnw-versions.md | 4 ----
java/ql/lib/change-notes/released/0.8.10.md | 10 ++++++++++
java/ql/lib/codeql-pack.release.yml | 2 +-
java/ql/lib/qlpack.yml | 2 +-
java/ql/src/CHANGELOG.md | 10 ++++++++++
.../2024-02-12-android-insecure-keys.md | 4 ----
.../0.8.10.md} | 11 ++++++++---
java/ql/src/codeql-pack.release.yml | 2 +-
java/ql/src/qlpack.yml | 2 +-
javascript/ql/lib/CHANGELOG.md | 4 ++++
javascript/ql/lib/change-notes/released/0.8.10.md | 3 +++
javascript/ql/lib/codeql-pack.release.yml | 2 +-
javascript/ql/lib/qlpack.yml | 2 +-
javascript/ql/src/CHANGELOG.md | 4 ++++
javascript/ql/src/change-notes/released/0.8.10.md | 3 +++
javascript/ql/src/codeql-pack.release.yml | 2 +-
javascript/ql/src/qlpack.yml | 2 +-
misc/suite-helpers/CHANGELOG.md | 4 ++++
misc/suite-helpers/change-notes/released/0.7.10.md | 3 +++
misc/suite-helpers/codeql-pack.release.yml | 2 +-
misc/suite-helpers/qlpack.yml | 2 +-
python/ql/lib/CHANGELOG.md | 7 +++++++
.../2024-02-28-iterable-unpacking-module-scope.md | 4 ----
.../0.11.10.md} | 8 +++++---
python/ql/lib/codeql-pack.release.yml | 2 +-
python/ql/lib/qlpack.yml | 2 +-
python/ql/src/CHANGELOG.md | 6 ++++++
.../0.9.10.md} | 7 ++++---
python/ql/src/codeql-pack.release.yml | 2 +-
python/ql/src/qlpack.yml | 2 +-
ruby/ql/lib/CHANGELOG.md | 9 +++++++++
...2024-02-15-activerecord_connection_sql_sinks.md | 4 ----
.../2024-02-20-activerecord-sql-sink-arguments.md | 4 ----
.../lib/change-notes/2024-02-26-arel-sqlliteral.md | 4 ----
.../lib/change-notes/2024-02-29-i18n-translate.md | 4 ----
ruby/ql/lib/change-notes/released/0.8.10.md | 8 ++++++++
ruby/ql/lib/codeql-pack.release.yml | 2 +-
ruby/ql/lib/qlpack.yml | 2 +-
ruby/ql/src/CHANGELOG.md | 7 +++++++
.../2024-02-13-rails-more-request-sources.md | 4 ----
.../0.8.10.md} | 10 ++++++----
ruby/ql/src/codeql-pack.release.yml | 2 +-
ruby/ql/src/qlpack.yml | 2 +-
shared/controlflow/CHANGELOG.md | 4 ++++
shared/controlflow/change-notes/released/0.1.10.md | 3 +++
shared/controlflow/codeql-pack.release.yml | 2 +-
shared/controlflow/qlpack.yml | 2 +-
shared/dataflow/CHANGELOG.md | 4 ++++
shared/dataflow/change-notes/released/0.2.1.md | 3 +++
shared/dataflow/codeql-pack.release.yml | 2 +-
shared/dataflow/qlpack.yml | 2 +-
shared/mad/CHANGELOG.md | 4 ++++
shared/mad/change-notes/released/0.2.10.md | 3 +++
shared/mad/codeql-pack.release.yml | 2 +-
shared/mad/qlpack.yml | 2 +-
shared/rangeanalysis/CHANGELOG.md | 4 ++++
.../rangeanalysis/change-notes/released/0.0.9.md | 3 +++
shared/rangeanalysis/codeql-pack.release.yml | 2 +-
shared/rangeanalysis/qlpack.yml | 2 +-
shared/regex/CHANGELOG.md | 4 ++++
shared/regex/change-notes/released/0.2.10.md | 3 +++
shared/regex/codeql-pack.release.yml | 2 +-
shared/regex/qlpack.yml | 2 +-
shared/ssa/CHANGELOG.md | 4 ++++
shared/ssa/change-notes/released/0.2.10.md | 3 +++
shared/ssa/codeql-pack.release.yml | 2 +-
shared/ssa/qlpack.yml | 2 +-
shared/threat-models/CHANGELOG.md | 4 ++++
.../threat-models/change-notes/released/0.0.9.md | 3 +++
shared/threat-models/codeql-pack.release.yml | 2 +-
shared/threat-models/qlpack.yml | 2 +-
shared/tutorial/CHANGELOG.md | 4 ++++
shared/tutorial/change-notes/released/0.2.10.md | 3 +++
shared/tutorial/codeql-pack.release.yml | 2 +-
shared/tutorial/qlpack.yml | 2 +-
shared/typetracking/CHANGELOG.md | 4 ++++
.../typetracking/change-notes/released/0.2.10.md | 3 +++
shared/typetracking/codeql-pack.release.yml | 2 +-
shared/typetracking/qlpack.yml | 2 +-
shared/typos/CHANGELOG.md | 4 ++++
shared/typos/change-notes/released/0.2.10.md | 3 +++
shared/typos/codeql-pack.release.yml | 2 +-
shared/typos/qlpack.yml | 2 +-
shared/util/CHANGELOG.md | 4 ++++
shared/util/change-notes/released/0.2.10.md | 3 +++
shared/util/codeql-pack.release.yml | 2 +-
shared/util/qlpack.yml | 2 +-
shared/yaml/CHANGELOG.md | 4 ++++
shared/yaml/change-notes/released/0.2.10.md | 3 +++
shared/yaml/codeql-pack.release.yml | 2 +-
shared/yaml/qlpack.yml | 2 +-
swift/ql/lib/CHANGELOG.md | 6 ++++++
.../0.3.10.md} | 7 ++++---
swift/ql/lib/codeql-pack.release.yml | 2 +-
swift/ql/lib/qlpack.yml | 2 +-
swift/ql/src/CHANGELOG.md | 4 ++++
swift/ql/src/change-notes/released/0.3.10.md | 3 +++
swift/ql/src/codeql-pack.release.yml | 2 +-
swift/ql/src/qlpack.yml | 2 +-
150 files changed, 394 insertions(+), 168 deletions(-)
rename cpp/ql/lib/change-notes/{2024-02-26-ir-named-destructors.md => released/0.12.7.md} (54%)
delete mode 100644 cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
rename cpp/ql/src/change-notes/{2024-02-16-modelled-functions-block-flow.md => released/0.9.6.md} (77%)
create mode 100644 csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
create mode 100644 csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
delete mode 100644 csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
create mode 100644 csharp/ql/lib/change-notes/released/0.8.10.md
rename csharp/ql/src/change-notes/{2024-02-06-threat-models.md => released/0.8.10.md} (88%)
create mode 100644 go/ql/consistency-queries/change-notes/released/0.0.9.md
delete mode 100644 go/ql/lib/change-notes/2024-02-14-range-map-read.md
rename go/ql/lib/change-notes/{2024-03-04-autobuilder-changes.md => released/0.7.10.md} (68%)
create mode 100644 go/ql/src/change-notes/released/0.7.10.md
create mode 100644 java/ql/automodel/src/change-notes/released/0.0.17.md
delete mode 100644 java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
delete mode 100644 java/ql/lib/change-notes/2024-02-27-error-types.md
delete mode 100644 java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
create mode 100644 java/ql/lib/change-notes/released/0.8.10.md
delete mode 100644 java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
rename java/ql/src/change-notes/{2024-03-04-sensitive-log-remove-null-from-sources.md => released/0.8.10.md} (54%)
create mode 100644 javascript/ql/lib/change-notes/released/0.8.10.md
create mode 100644 javascript/ql/src/change-notes/released/0.8.10.md
create mode 100644 misc/suite-helpers/change-notes/released/0.7.10.md
delete mode 100644 python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
rename python/ql/lib/change-notes/{2024-03-01-dict-update-content.md => released/0.11.10.md} (52%)
rename python/ql/src/change-notes/{2024-03-04-nosql-injection.md => released/0.9.10.md} (81%)
delete mode 100644 ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
delete mode 100644 ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
delete mode 100644 ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
delete mode 100644 ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
create mode 100644 ruby/ql/lib/change-notes/released/0.8.10.md
delete mode 100644 ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
rename ruby/ql/src/change-notes/{2024-03-01-method-code-injection-sinks.md => released/0.8.10.md} (51%)
create mode 100644 shared/controlflow/change-notes/released/0.1.10.md
create mode 100644 shared/dataflow/change-notes/released/0.2.1.md
create mode 100644 shared/mad/change-notes/released/0.2.10.md
create mode 100644 shared/rangeanalysis/change-notes/released/0.0.9.md
create mode 100644 shared/regex/change-notes/released/0.2.10.md
create mode 100644 shared/ssa/change-notes/released/0.2.10.md
create mode 100644 shared/threat-models/change-notes/released/0.0.9.md
create mode 100644 shared/tutorial/change-notes/released/0.2.10.md
create mode 100644 shared/typetracking/change-notes/released/0.2.10.md
create mode 100644 shared/typos/change-notes/released/0.2.10.md
create mode 100644 shared/util/change-notes/released/0.2.10.md
create mode 100644 shared/yaml/change-notes/released/0.2.10.md
rename swift/ql/lib/change-notes/{2024-02-22-extension-patch.md => released/0.3.10.md} (83%)
create mode 100644 swift/ql/src/change-notes/released/0.3.10.md
diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md
index b3091ec37d8..e1c0dfbecd9 100644
--- a/cpp/ql/lib/CHANGELOG.md
+++ b/cpp/ql/lib/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.12.7
+
+### Minor Analysis Improvements
+
+* Added destructors for named objects to the intermediate representation.
+
## 0.12.6
### New Features
diff --git a/cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md b/cpp/ql/lib/change-notes/released/0.12.7.md
similarity index 54%
rename from cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md
rename to cpp/ql/lib/change-notes/released/0.12.7.md
index 4e35decaf8e..856a8b665c7 100644
--- a/cpp/ql/lib/change-notes/2024-02-26-ir-named-destructors.md
+++ b/cpp/ql/lib/change-notes/released/0.12.7.md
@@ -1,4 +1,5 @@
----
-category: minorAnalysis
----
-* Added destructors for named objects to the intermediate representation.
\ No newline at end of file
+## 0.12.7
+
+### Minor Analysis Improvements
+
+* Added destructors for named objects to the intermediate representation.
diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml
index 170a312c104..20419e9c610 100644
--- a/cpp/ql/lib/codeql-pack.release.yml
+++ b/cpp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.12.6
+lastReleaseVersion: 0.12.7
diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml
index 8e201fff594..3bb9229bf94 100644
--- a/cpp/ql/lib/qlpack.yml
+++ b/cpp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-all
-version: 0.12.7-dev
+version: 0.12.7
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md
index ffcd73ff5d7..f6acd424bb0 100644
--- a/cpp/ql/src/CHANGELOG.md
+++ b/cpp/ql/src/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.9.6
+
+### Minor Analysis Improvements
+
+* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
+* The new C/C++ dataflow and taint-tracking libraries (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`) now implicitly assume that dataflow and taint modelled via `DataFlowFunction` and `TaintFunction` always fully overwrite their buffers and thus act as flow barriers. As a result, many dataflow and taint-tracking queries now produce fewer false positives. To remove this assumption and go back to the previous behavior for a given model, one can override the new `isPartialWrite` predicate.
+
## 0.9.5
### Minor Analysis Improvements
diff --git a/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md b/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
deleted file mode 100644
index 2e5933a61e8..00000000000
--- a/cpp/ql/src/change-notes/2024-02-29-non-constant-format-path-query.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
\ No newline at end of file
diff --git a/cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md b/cpp/ql/src/change-notes/released/0.9.6.md
similarity index 77%
rename from cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md
rename to cpp/ql/src/change-notes/released/0.9.6.md
index d6ef3c3e056..0c85f3f9f0f 100644
--- a/cpp/ql/src/change-notes/2024-02-16-modelled-functions-block-flow.md
+++ b/cpp/ql/src/change-notes/released/0.9.6.md
@@ -1,4 +1,6 @@
----
-category: minorAnalysis
----
+## 0.9.6
+
+### Minor Analysis Improvements
+
+* The "non-constant format string" query (`cpp/non-constant-format`) has been converted to a `path-problem` query.
* The new C/C++ dataflow and taint-tracking libraries (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`) now implicitly assume that dataflow and taint modelled via `DataFlowFunction` and `TaintFunction` always fully overwrite their buffers and thus act as flow barriers. As a result, many dataflow and taint-tracking queries now produce fewer false positives. To remove this assumption and go back to the previous behavior for a given model, one can override the new `isPartialWrite` predicate.
diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml
index 460240feaff..19139c132b2 100644
--- a/cpp/ql/src/codeql-pack.release.yml
+++ b/cpp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.9.5
+lastReleaseVersion: 0.9.6
diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml
index 31bd20166b2..4052647bb97 100644
--- a/cpp/ql/src/qlpack.yml
+++ b/cpp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-queries
-version: 0.9.6-dev
+version: 0.9.6
groups:
- cpp
- queries
diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
index 190b83b0f25..82eacfc84f7 100644
--- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
+++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.7.10
+
+No user-facing changes.
+
## 1.7.9
No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
new file mode 100644
index 00000000000..8e8007d8475
--- /dev/null
+++ b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.10.md
@@ -0,0 +1,3 @@
+## 1.7.10
+
+No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
index 678da6bc37e..31c7fe07020 100644
--- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
+++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.7.9
+lastReleaseVersion: 1.7.10
diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
index 7e643b0fac3..ee993bed0c9 100644
--- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
-version: 1.7.10-dev
+version: 1.7.10
groups:
- csharp
- solorigate
diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
index 190b83b0f25..82eacfc84f7 100644
--- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
+++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.7.10
+
+No user-facing changes.
+
## 1.7.9
No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
new file mode 100644
index 00000000000..8e8007d8475
--- /dev/null
+++ b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.10.md
@@ -0,0 +1,3 @@
+## 1.7.10
+
+No user-facing changes.
diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
index 678da6bc37e..31c7fe07020 100644
--- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
+++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 1.7.9
+lastReleaseVersion: 1.7.10
diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
index 8654bbfd031..1f421754fc8 100644
--- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
-version: 1.7.10-dev
+version: 1.7.10
groups:
- csharp
- solorigate
diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md
index 95fd64c5270..16cc14259e1 100644
--- a/csharp/ql/lib/CHANGELOG.md
+++ b/csharp/ql/lib/CHANGELOG.md
@@ -1,3 +1,17 @@
+## 0.8.10
+
+### Major Analysis Improvements
+
+* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
+* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
+
+### Minor Analysis Improvements
+
+* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
+* C# 12: Add extractor and QL library support for `ref readonly` parameters.
+* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
+* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
+
## 0.8.9
### Minor Analysis Improvements
diff --git a/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md b/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
deleted file mode 100644
index 6bb8e99c71e..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-21-getonly-properties.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
diff --git a/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md b/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
deleted file mode 100644
index d6ffbd523ac..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-22-no-db-stats.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: majorAnalysis
----
-* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
diff --git a/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md b/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
deleted file mode 100644
index 9b1739b9b6d..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-23-compiler-generated.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
diff --git a/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md b/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
deleted file mode 100644
index 66ab65083dc..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-26-variable-capture-flow.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: majorAnalysis
----
-* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
\ No newline at end of file
diff --git a/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md b/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
deleted file mode 100644
index 8749c790954..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-28-experimental-attribute.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
diff --git a/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md b/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
deleted file mode 100644
index 586b5341d29..00000000000
--- a/csharp/ql/lib/change-notes/2024-02-28-refreadonly-parameter.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* C# 12: Add extractor and QL library support for `ref readonly` parameters.
diff --git a/csharp/ql/lib/change-notes/released/0.8.10.md b/csharp/ql/lib/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..f591ddc5b21
--- /dev/null
+++ b/csharp/ql/lib/change-notes/released/0.8.10.md
@@ -0,0 +1,13 @@
+## 0.8.10
+
+### Major Analysis Improvements
+
+* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
+* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
+
+### Minor Analysis Improvements
+
+* C# 12: Add QL library support (`ExperimentalAttribute`) for the experimental attribute.
+* C# 12: Add extractor and QL library support for `ref readonly` parameters.
+* C#: The table `expr_compiler_generated` has been deleted and its content has been added to `compiler_generated`.
+* Data flow via get only properties like `public object Obj { get; }` is now captured by the data flow library.
diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/csharp/ql/lib/codeql-pack.release.yml
+++ b/csharp/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml
index d75ea3c6320..93c5c1120a2 100644
--- a/csharp/ql/lib/qlpack.yml
+++ b/csharp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-all
-version: 0.8.10-dev
+version: 0.8.10
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp
diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md
index 9fe1609363f..46c939e5cee 100644
--- a/csharp/ql/src/CHANGELOG.md
+++ b/csharp/ql/src/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
+
## 0.8.9
### Minor Analysis Improvements
diff --git a/csharp/ql/src/change-notes/2024-02-06-threat-models.md b/csharp/ql/src/change-notes/released/0.8.10.md
similarity index 88%
rename from csharp/ql/src/change-notes/2024-02-06-threat-models.md
rename to csharp/ql/src/change-notes/released/0.8.10.md
index 69ac4e4dc17..702161c3d28 100644
--- a/csharp/ql/src/change-notes/2024-02-06-threat-models.md
+++ b/csharp/ql/src/change-notes/released/0.8.10.md
@@ -1,4 +1,5 @@
----
-category: minorAnalysis
----
-* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
\ No newline at end of file
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are `cs/code-injection`, `cs/command-line-injection`, `cs/user-controlled-bypass`, `cs/count-untrusted-data-external-api`, `cs/untrusted-data-to-external-api`, `cs/ldap-injection`, `cs/log-forging`, `cs/xml/missing-validation`, `cs/redos`, `cs/regex-injection`, `cs/resource-injection`, `cs/sql-injection`, `cs/path-injection`, `cs/unsafe-deserialization-untrusted-input`, `cs/web/unvalidated-url-redirection`, `cs/xml/insecure-dtd-handling`, `cs/xml/xpath-injection`, `cs/web/xss`, and `cs/uncontrolled-format-string`.
diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/csharp/ql/src/codeql-pack.release.yml
+++ b/csharp/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml
index 9ee23cc7307..46384094b19 100644
--- a/csharp/ql/src/qlpack.yml
+++ b/csharp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-queries
-version: 0.8.10-dev
+version: 0.8.10
groups:
- csharp
- queries
diff --git a/go/ql/consistency-queries/CHANGELOG.md b/go/ql/consistency-queries/CHANGELOG.md
index fba2a870356..a59e560c415 100644
--- a/go/ql/consistency-queries/CHANGELOG.md
+++ b/go/ql/consistency-queries/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.9
+
+No user-facing changes.
+
## 0.0.8
No user-facing changes.
diff --git a/go/ql/consistency-queries/change-notes/released/0.0.9.md b/go/ql/consistency-queries/change-notes/released/0.0.9.md
new file mode 100644
index 00000000000..c9e17c6d6cf
--- /dev/null
+++ b/go/ql/consistency-queries/change-notes/released/0.0.9.md
@@ -0,0 +1,3 @@
+## 0.0.9
+
+No user-facing changes.
diff --git a/go/ql/consistency-queries/codeql-pack.release.yml b/go/ql/consistency-queries/codeql-pack.release.yml
index 58fdc6b45de..ecdd64fbab8 100644
--- a/go/ql/consistency-queries/codeql-pack.release.yml
+++ b/go/ql/consistency-queries/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.8
+lastReleaseVersion: 0.0.9
diff --git a/go/ql/consistency-queries/qlpack.yml b/go/ql/consistency-queries/qlpack.yml
index b574796b995..d5a2fbee5f1 100644
--- a/go/ql/consistency-queries/qlpack.yml
+++ b/go/ql/consistency-queries/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql-go-consistency-queries
-version: 0.0.9-dev
+version: 0.0.9
groups:
- go
- queries
diff --git a/go/ql/lib/CHANGELOG.md b/go/ql/lib/CHANGELOG.md
index 65a2376217b..fee5fd37a26 100644
--- a/go/ql/lib/CHANGELOG.md
+++ b/go/ql/lib/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 0.7.10
+
+### Major Analysis Improvements
+
+* We have significantly improved the Go autobuilder to understand a greater range of project layouts, which allows Go source files to be analysed that could previously not be processed.
+* Go 1.22 has been included in the range of supported Go versions.
+
+### Bug Fixes
+
+* Fixed dataflow out of a `map` using a `range` statement.
+
## 0.7.9
No user-facing changes.
diff --git a/go/ql/lib/change-notes/2024-02-14-range-map-read.md b/go/ql/lib/change-notes/2024-02-14-range-map-read.md
deleted file mode 100644
index ea45737a72e..00000000000
--- a/go/ql/lib/change-notes/2024-02-14-range-map-read.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: fix
----
-* Fixed dataflow out of a `map` using a `range` statement.
diff --git a/go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md b/go/ql/lib/change-notes/released/0.7.10.md
similarity index 68%
rename from go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md
rename to go/ql/lib/change-notes/released/0.7.10.md
index 0442a571029..55954f8a394 100644
--- a/go/ql/lib/change-notes/2024-03-04-autobuilder-changes.md
+++ b/go/ql/lib/change-notes/released/0.7.10.md
@@ -1,5 +1,10 @@
----
-category: majorAnalysis
----
+## 0.7.10
+
+### Major Analysis Improvements
+
* We have significantly improved the Go autobuilder to understand a greater range of project layouts, which allows Go source files to be analysed that could previously not be processed.
* Go 1.22 has been included in the range of supported Go versions.
+
+### Bug Fixes
+
+* Fixed dataflow out of a `map` using a `range` statement.
diff --git a/go/ql/lib/codeql-pack.release.yml b/go/ql/lib/codeql-pack.release.yml
index 576395f3405..67518567297 100644
--- a/go/ql/lib/codeql-pack.release.yml
+++ b/go/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.9
+lastReleaseVersion: 0.7.10
diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml
index f21e478efa6..8cc190fa880 100644
--- a/go/ql/lib/qlpack.yml
+++ b/go/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/go-all
-version: 0.7.10-dev
+version: 0.7.10
groups: go
dbscheme: go.dbscheme
extractor: go
diff --git a/go/ql/src/CHANGELOG.md b/go/ql/src/CHANGELOG.md
index d95165a3a34..24e38b9890e 100644
--- a/go/ql/src/CHANGELOG.md
+++ b/go/ql/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.7.10
+
+No user-facing changes.
+
## 0.7.9
### New Queries
diff --git a/go/ql/src/change-notes/released/0.7.10.md b/go/ql/src/change-notes/released/0.7.10.md
new file mode 100644
index 00000000000..989c5b8f682
--- /dev/null
+++ b/go/ql/src/change-notes/released/0.7.10.md
@@ -0,0 +1,3 @@
+## 0.7.10
+
+No user-facing changes.
diff --git a/go/ql/src/codeql-pack.release.yml b/go/ql/src/codeql-pack.release.yml
index 576395f3405..67518567297 100644
--- a/go/ql/src/codeql-pack.release.yml
+++ b/go/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.9
+lastReleaseVersion: 0.7.10
diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml
index d91cab59612..4ded3a52f63 100644
--- a/go/ql/src/qlpack.yml
+++ b/go/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/go-queries
-version: 0.7.10-dev
+version: 0.7.10
groups:
- go
- queries
diff --git a/java/ql/automodel/src/CHANGELOG.md b/java/ql/automodel/src/CHANGELOG.md
index 4a3c54adb38..c3282c773a9 100644
--- a/java/ql/automodel/src/CHANGELOG.md
+++ b/java/ql/automodel/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.17
+
+No user-facing changes.
+
## 0.0.16
No user-facing changes.
diff --git a/java/ql/automodel/src/change-notes/released/0.0.17.md b/java/ql/automodel/src/change-notes/released/0.0.17.md
new file mode 100644
index 00000000000..62cc89030a6
--- /dev/null
+++ b/java/ql/automodel/src/change-notes/released/0.0.17.md
@@ -0,0 +1,3 @@
+## 0.0.17
+
+No user-facing changes.
diff --git a/java/ql/automodel/src/codeql-pack.release.yml b/java/ql/automodel/src/codeql-pack.release.yml
index a49f7be4cff..cbc3d3cd493 100644
--- a/java/ql/automodel/src/codeql-pack.release.yml
+++ b/java/ql/automodel/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.16
+lastReleaseVersion: 0.0.17
diff --git a/java/ql/automodel/src/qlpack.yml b/java/ql/automodel/src/qlpack.yml
index 898239be098..59fab0cdcc5 100644
--- a/java/ql/automodel/src/qlpack.yml
+++ b/java/ql/automodel/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-automodel-queries
-version: 0.0.17-dev
+version: 0.0.17
groups:
- java
- automodel
diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md
index d369cbdc931..2a02ccee6ab 100644
--- a/java/ql/lib/CHANGELOG.md
+++ b/java/ql/lib/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
+
+### Bug Fixes
+
+* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
+* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
+
## 0.8.9
### Deprecated APIs
diff --git a/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md b/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
deleted file mode 100644
index eb560fba07d..00000000000
--- a/java/ql/lib/change-notes/2024-02-23-widget-flowsteps.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: fix
----
-* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
diff --git a/java/ql/lib/change-notes/2024-02-27-error-types.md b/java/ql/lib/change-notes/2024-02-27-error-types.md
deleted file mode 100644
index cdc6d7620aa..00000000000
--- a/java/ql/lib/change-notes/2024-02-27-error-types.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
diff --git a/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md b/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
deleted file mode 100644
index a0227088ae9..00000000000
--- a/java/ql/lib/change-notes/2024-02-27-mvnw-versions.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: fix
----
-* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
diff --git a/java/ql/lib/change-notes/released/0.8.10.md b/java/ql/lib/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..b45f14bf347
--- /dev/null
+++ b/java/ql/lib/change-notes/released/0.8.10.md
@@ -0,0 +1,10 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL `ErrorType` more often.
+
+### Bug Fixes
+
+* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper `mvnw` is in use and the `maven-wrapper.jar` file is not present in the repository.
+* Some flow steps related to `android.text.Editable.toString` that were accidentally disabled have been re-enabled.
diff --git a/java/ql/lib/codeql-pack.release.yml b/java/ql/lib/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/java/ql/lib/codeql-pack.release.yml
+++ b/java/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml
index 15b4982d41e..428eedc75e3 100644
--- a/java/ql/lib/qlpack.yml
+++ b/java/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-all
-version: 0.8.10-dev
+version: 0.8.10
groups: java
dbscheme: config/semmlecode.dbscheme
extractor: java
diff --git a/java/ql/src/CHANGELOG.md b/java/ql/src/CHANGELOG.md
index 5d835351453..c61275f5ed8 100644
--- a/java/ql/src/CHANGELOG.md
+++ b/java/ql/src/CHANGELOG.md
@@ -1,3 +1,13 @@
+## 0.8.10
+
+### New Queries
+
+* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
+
+### Minor Analysis Improvements
+
+* To reduce the number of false positives in the query "Insertion of sensitive information into log files" (`java/sensitive-log`), variables with names that contain "null" (case-insensitively) are no longer considered sources of sensitive information.
+
## 0.8.9
### New Queries
diff --git a/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md b/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
deleted file mode 100644
index 1de07727796..00000000000
--- a/java/ql/src/change-notes/2024-02-12-android-insecure-keys.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: newQuery
----
-* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
\ No newline at end of file
diff --git a/java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md b/java/ql/src/change-notes/released/0.8.10.md
similarity index 54%
rename from java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md
rename to java/ql/src/change-notes/released/0.8.10.md
index 0bb4f18f2bd..c5d18ae3379 100644
--- a/java/ql/src/change-notes/2024-03-04-sensitive-log-remove-null-from-sources.md
+++ b/java/ql/src/change-notes/released/0.8.10.md
@@ -1,4 +1,9 @@
----
-category: minorAnalysis
----
+## 0.8.10
+
+### New Queries
+
+* Added a new query `java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
+
+### Minor Analysis Improvements
+
* To reduce the number of false positives in the query "Insertion of sensitive information into log files" (`java/sensitive-log`), variables with names that contain "null" (case-insensitively) are no longer considered sources of sensitive information.
diff --git a/java/ql/src/codeql-pack.release.yml b/java/ql/src/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/java/ql/src/codeql-pack.release.yml
+++ b/java/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml
index 8f4de528e21..ebbdbeee3b2 100644
--- a/java/ql/src/qlpack.yml
+++ b/java/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-queries
-version: 0.8.10-dev
+version: 0.8.10
groups:
- java
- queries
diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md
index 5b97ebbb22b..d5edcc00513 100644
--- a/javascript/ql/lib/CHANGELOG.md
+++ b/javascript/ql/lib/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.8.10
+
+No user-facing changes.
+
## 0.8.9
### Minor Analysis Improvements
diff --git a/javascript/ql/lib/change-notes/released/0.8.10.md b/javascript/ql/lib/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..777bbd2fded
--- /dev/null
+++ b/javascript/ql/lib/change-notes/released/0.8.10.md
@@ -0,0 +1,3 @@
+## 0.8.10
+
+No user-facing changes.
diff --git a/javascript/ql/lib/codeql-pack.release.yml b/javascript/ql/lib/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/javascript/ql/lib/codeql-pack.release.yml
+++ b/javascript/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml
index ef3ca7521ac..da16493a21c 100644
--- a/javascript/ql/lib/qlpack.yml
+++ b/javascript/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-all
-version: 0.8.10-dev
+version: 0.8.10
groups: javascript
dbscheme: semmlecode.javascript.dbscheme
extractor: javascript
diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md
index 85516e3625d..b9627cac5ee 100644
--- a/javascript/ql/src/CHANGELOG.md
+++ b/javascript/ql/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.8.10
+
+No user-facing changes.
+
## 0.8.9
### Bug Fixes
diff --git a/javascript/ql/src/change-notes/released/0.8.10.md b/javascript/ql/src/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..777bbd2fded
--- /dev/null
+++ b/javascript/ql/src/change-notes/released/0.8.10.md
@@ -0,0 +1,3 @@
+## 0.8.10
+
+No user-facing changes.
diff --git a/javascript/ql/src/codeql-pack.release.yml b/javascript/ql/src/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/javascript/ql/src/codeql-pack.release.yml
+++ b/javascript/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml
index b6181aa30e9..d224952c564 100644
--- a/javascript/ql/src/qlpack.yml
+++ b/javascript/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-queries
-version: 0.8.10-dev
+version: 0.8.10
groups:
- javascript
- queries
diff --git a/misc/suite-helpers/CHANGELOG.md b/misc/suite-helpers/CHANGELOG.md
index 3c06dd69b0f..1c4455b66c4 100644
--- a/misc/suite-helpers/CHANGELOG.md
+++ b/misc/suite-helpers/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.7.10
+
+No user-facing changes.
+
## 0.7.9
No user-facing changes.
diff --git a/misc/suite-helpers/change-notes/released/0.7.10.md b/misc/suite-helpers/change-notes/released/0.7.10.md
new file mode 100644
index 00000000000..989c5b8f682
--- /dev/null
+++ b/misc/suite-helpers/change-notes/released/0.7.10.md
@@ -0,0 +1,3 @@
+## 0.7.10
+
+No user-facing changes.
diff --git a/misc/suite-helpers/codeql-pack.release.yml b/misc/suite-helpers/codeql-pack.release.yml
index 576395f3405..67518567297 100644
--- a/misc/suite-helpers/codeql-pack.release.yml
+++ b/misc/suite-helpers/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.7.9
+lastReleaseVersion: 0.7.10
diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml
index 49b7a6bda4c..54d978d5efe 100644
--- a/misc/suite-helpers/qlpack.yml
+++ b/misc/suite-helpers/qlpack.yml
@@ -1,4 +1,4 @@
name: codeql/suite-helpers
-version: 0.7.10-dev
+version: 0.7.10
groups: shared
warnOnImplicitThis: true
diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md
index e6f318c51ea..f095607ca1b 100644
--- a/python/ql/lib/CHANGELOG.md
+++ b/python/ql/lib/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.11.10
+
+### Minor Analysis Improvements
+
+* Fixed missing flow for dictionary updates (`d[] = ...`) when `` is a string constant not used in dictionary literals or as name of keyword-argument.
+* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
+
## 0.11.9
### Minor Analysis Improvements
diff --git a/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md b/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
deleted file mode 100644
index 3c47c6ba866..00000000000
--- a/python/ql/lib/change-notes/2024-02-28-iterable-unpacking-module-scope.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
diff --git a/python/ql/lib/change-notes/2024-03-01-dict-update-content.md b/python/ql/lib/change-notes/released/0.11.10.md
similarity index 52%
rename from python/ql/lib/change-notes/2024-03-01-dict-update-content.md
rename to python/ql/lib/change-notes/released/0.11.10.md
index dfb8d247fff..ed873724e4f 100644
--- a/python/ql/lib/change-notes/2024-03-01-dict-update-content.md
+++ b/python/ql/lib/change-notes/released/0.11.10.md
@@ -1,4 +1,6 @@
----
-category: minorAnalysis
----
+## 0.11.10
+
+### Minor Analysis Improvements
+
* Fixed missing flow for dictionary updates (`d[] = ...`) when `` is a string constant not used in dictionary literals or as name of keyword-argument.
+* Fixed flow for iterable unpacking (`a,b = my_tuple`) when it occurs on top-level (module) scope.
diff --git a/python/ql/lib/codeql-pack.release.yml b/python/ql/lib/codeql-pack.release.yml
index b064d1778a1..ddddcbe9193 100644
--- a/python/ql/lib/codeql-pack.release.yml
+++ b/python/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.11.9
+lastReleaseVersion: 0.11.10
diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml
index e9f66e205f2..59a8b4c96d1 100644
--- a/python/ql/lib/qlpack.yml
+++ b/python/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/python-all
-version: 0.11.10-dev
+version: 0.11.10
groups: python
dbscheme: semmlecode.python.dbscheme
extractor: python
diff --git a/python/ql/src/CHANGELOG.md b/python/ql/src/CHANGELOG.md
index 50762bcbf34..d4245aba7a6 100644
--- a/python/ql/src/CHANGELOG.md
+++ b/python/ql/src/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.9.10
+
+### New Queries
+
+* The query `py/nosql-injection` for finding NoSQL injection vulnerabilities is now part of the default security suite.
+
## 0.9.9
No user-facing changes.
diff --git a/python/ql/src/change-notes/2024-03-04-nosql-injection.md b/python/ql/src/change-notes/released/0.9.10.md
similarity index 81%
rename from python/ql/src/change-notes/2024-03-04-nosql-injection.md
rename to python/ql/src/change-notes/released/0.9.10.md
index 6e98540c757..4cbb221b789 100644
--- a/python/ql/src/change-notes/2024-03-04-nosql-injection.md
+++ b/python/ql/src/change-notes/released/0.9.10.md
@@ -1,4 +1,5 @@
----
-category: newQuery
----
+## 0.9.10
+
+### New Queries
+
* The query `py/nosql-injection` for finding NoSQL injection vulnerabilities is now part of the default security suite.
diff --git a/python/ql/src/codeql-pack.release.yml b/python/ql/src/codeql-pack.release.yml
index aabed7c396b..d086ed69541 100644
--- a/python/ql/src/codeql-pack.release.yml
+++ b/python/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.9.9
+lastReleaseVersion: 0.9.10
diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml
index aa18f2d8707..c920f667836 100644
--- a/python/ql/src/qlpack.yml
+++ b/python/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/python-queries
-version: 0.9.10-dev
+version: 0.9.10
groups:
- python
- queries
diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md
index a623a151e89..c61a12e0f4a 100644
--- a/ruby/ql/lib/CHANGELOG.md
+++ b/ruby/ql/lib/CHANGELOG.md
@@ -1,3 +1,12 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
+* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
+* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
+* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
+
## 0.8.9
### Minor Analysis Improvements
diff --git a/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md b/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
deleted file mode 100644
index c2276f284a8..00000000000
--- a/ruby/ql/lib/change-notes/2024-02-15-activerecord_connection_sql_sinks.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md b/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
deleted file mode 100644
index 1486c7a472d..00000000000
--- a/ruby/ql/lib/change-notes/2024-02-20-activerecord-sql-sink-arguments.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md b/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
deleted file mode 100644
index 6f3a90768ba..00000000000
--- a/ruby/ql/lib/change-notes/2024-02-26-arel-sqlliteral.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md b/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
deleted file mode 100644
index 350e049b5bf..00000000000
--- a/ruby/ql/lib/change-notes/2024-02-29-i18n-translate.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
\ No newline at end of file
diff --git a/ruby/ql/lib/change-notes/released/0.8.10.md b/ruby/ql/lib/change-notes/released/0.8.10.md
new file mode 100644
index 00000000000..666e28f840e
--- /dev/null
+++ b/ruby/ql/lib/change-notes/released/0.8.10.md
@@ -0,0 +1,8 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Calls to `I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
+* Calls to `Arel::Nodes::SqlLiteral.new` are now modeled as instances of the `SqlConstruction` concept, as well as propagating taint from their argument.
+* Additional arguments beyond the first of calls to the `ActiveRecord` methods `select`, `reselect`, `order`, `reorder`, `joins`, `group`, and `pluck` are now recognized as sql injection sinks.
+* Calls to several methods of `ActiveRecord::Connection`, such as `ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
diff --git a/ruby/ql/lib/codeql-pack.release.yml b/ruby/ql/lib/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/ruby/ql/lib/codeql-pack.release.yml
+++ b/ruby/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml
index 7d409b83adb..de5b41999fe 100644
--- a/ruby/ql/lib/qlpack.yml
+++ b/ruby/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ruby-all
-version: 0.8.10-dev
+version: 0.8.10
groups: ruby
extractor: ruby
dbscheme: ruby.dbscheme
diff --git a/ruby/ql/src/CHANGELOG.md b/ruby/ql/src/CHANGELOG.md
index 4149c728eff..f875b6d16ad 100644
--- a/ruby/ql/src/CHANGELOG.md
+++ b/ruby/ql/src/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
+* Added additional request sources for Ruby on Rails.
+
## 0.8.9
No user-facing changes.
diff --git a/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md b/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
deleted file mode 100644
index 84ea696dfef..00000000000
--- a/ruby/ql/src/change-notes/2024-02-13-rails-more-request-sources.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: minorAnalysis
----
-* Added additional request sources for Ruby on Rails.
\ No newline at end of file
diff --git a/ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md b/ruby/ql/src/change-notes/released/0.8.10.md
similarity index 51%
rename from ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md
rename to ruby/ql/src/change-notes/released/0.8.10.md
index 43e40d3fd53..985cdf8d22e 100644
--- a/ruby/ql/src/change-notes/2024-03-01-method-code-injection-sinks.md
+++ b/ruby/ql/src/change-notes/released/0.8.10.md
@@ -1,4 +1,6 @@
----
-category: minorAnalysis
----
-* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
\ No newline at end of file
+## 0.8.10
+
+### Minor Analysis Improvements
+
+* Calls to `Object#method`, `Object#public_method` and `Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
+* Added additional request sources for Ruby on Rails.
diff --git a/ruby/ql/src/codeql-pack.release.yml b/ruby/ql/src/codeql-pack.release.yml
index 5290c29b7fe..0521f0f75fa 100644
--- a/ruby/ql/src/codeql-pack.release.yml
+++ b/ruby/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.8.9
+lastReleaseVersion: 0.8.10
diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml
index 8af7f9fd797..5e379268234 100644
--- a/ruby/ql/src/qlpack.yml
+++ b/ruby/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ruby-queries
-version: 0.8.10-dev
+version: 0.8.10
groups:
- ruby
- queries
diff --git a/shared/controlflow/CHANGELOG.md b/shared/controlflow/CHANGELOG.md
index dbfa6ef4512..75f2ca53f98 100644
--- a/shared/controlflow/CHANGELOG.md
+++ b/shared/controlflow/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.10
+
+No user-facing changes.
+
## 0.1.9
No user-facing changes.
diff --git a/shared/controlflow/change-notes/released/0.1.10.md b/shared/controlflow/change-notes/released/0.1.10.md
new file mode 100644
index 00000000000..47358eeee93
--- /dev/null
+++ b/shared/controlflow/change-notes/released/0.1.10.md
@@ -0,0 +1,3 @@
+## 0.1.10
+
+No user-facing changes.
diff --git a/shared/controlflow/codeql-pack.release.yml b/shared/controlflow/codeql-pack.release.yml
index 1425c0edf7f..30f5ca88be0 100644
--- a/shared/controlflow/codeql-pack.release.yml
+++ b/shared/controlflow/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.1.9
+lastReleaseVersion: 0.1.10
diff --git a/shared/controlflow/qlpack.yml b/shared/controlflow/qlpack.yml
index 9d35a678276..1d43802be42 100644
--- a/shared/controlflow/qlpack.yml
+++ b/shared/controlflow/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/controlflow
-version: 0.1.10-dev
+version: 0.1.10
groups: shared
library: true
dependencies:
diff --git a/shared/dataflow/CHANGELOG.md b/shared/dataflow/CHANGELOG.md
index 67a5bf589f4..ef80788bded 100644
--- a/shared/dataflow/CHANGELOG.md
+++ b/shared/dataflow/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.1
+
+No user-facing changes.
+
## 0.2.0
### Breaking Changes
diff --git a/shared/dataflow/change-notes/released/0.2.1.md b/shared/dataflow/change-notes/released/0.2.1.md
new file mode 100644
index 00000000000..3dbfc85fe11
--- /dev/null
+++ b/shared/dataflow/change-notes/released/0.2.1.md
@@ -0,0 +1,3 @@
+## 0.2.1
+
+No user-facing changes.
diff --git a/shared/dataflow/codeql-pack.release.yml b/shared/dataflow/codeql-pack.release.yml
index 5274e27ed52..df29a726bcc 100644
--- a/shared/dataflow/codeql-pack.release.yml
+++ b/shared/dataflow/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.0
+lastReleaseVersion: 0.2.1
diff --git a/shared/dataflow/qlpack.yml b/shared/dataflow/qlpack.yml
index 1e7becf71c4..ee422e02ea9 100644
--- a/shared/dataflow/qlpack.yml
+++ b/shared/dataflow/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/dataflow
-version: 0.2.1-dev
+version: 0.2.1
groups: shared
library: true
dependencies:
diff --git a/shared/mad/CHANGELOG.md b/shared/mad/CHANGELOG.md
index 4d09057118c..4730366775e 100644
--- a/shared/mad/CHANGELOG.md
+++ b/shared/mad/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/mad/change-notes/released/0.2.10.md b/shared/mad/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/mad/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/mad/codeql-pack.release.yml b/shared/mad/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/mad/codeql-pack.release.yml
+++ b/shared/mad/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml
index 22c8f271ccc..6d7269ef3da 100644
--- a/shared/mad/qlpack.yml
+++ b/shared/mad/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/mad
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies: null
diff --git a/shared/rangeanalysis/CHANGELOG.md b/shared/rangeanalysis/CHANGELOG.md
index 5b8dbcfab22..9943dcb7972 100644
--- a/shared/rangeanalysis/CHANGELOG.md
+++ b/shared/rangeanalysis/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.9
+
+No user-facing changes.
+
## 0.0.8
No user-facing changes.
diff --git a/shared/rangeanalysis/change-notes/released/0.0.9.md b/shared/rangeanalysis/change-notes/released/0.0.9.md
new file mode 100644
index 00000000000..c9e17c6d6cf
--- /dev/null
+++ b/shared/rangeanalysis/change-notes/released/0.0.9.md
@@ -0,0 +1,3 @@
+## 0.0.9
+
+No user-facing changes.
diff --git a/shared/rangeanalysis/codeql-pack.release.yml b/shared/rangeanalysis/codeql-pack.release.yml
index 58fdc6b45de..ecdd64fbab8 100644
--- a/shared/rangeanalysis/codeql-pack.release.yml
+++ b/shared/rangeanalysis/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.8
+lastReleaseVersion: 0.0.9
diff --git a/shared/rangeanalysis/qlpack.yml b/shared/rangeanalysis/qlpack.yml
index 836fe51ee34..01db5d5734d 100644
--- a/shared/rangeanalysis/qlpack.yml
+++ b/shared/rangeanalysis/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/rangeanalysis
-version: 0.0.9-dev
+version: 0.0.9
groups: shared
library: true
dependencies:
diff --git a/shared/regex/CHANGELOG.md b/shared/regex/CHANGELOG.md
index cd5f91f71ec..c05869c153d 100644
--- a/shared/regex/CHANGELOG.md
+++ b/shared/regex/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/regex/change-notes/released/0.2.10.md b/shared/regex/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/regex/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/regex/codeql-pack.release.yml b/shared/regex/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/regex/codeql-pack.release.yml
+++ b/shared/regex/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml
index ea3f7f9b238..0d4f485312f 100644
--- a/shared/regex/qlpack.yml
+++ b/shared/regex/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/regex
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies:
diff --git a/shared/ssa/CHANGELOG.md b/shared/ssa/CHANGELOG.md
index 01acfae0148..a9161ff578b 100644
--- a/shared/ssa/CHANGELOG.md
+++ b/shared/ssa/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/ssa/change-notes/released/0.2.10.md b/shared/ssa/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/ssa/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/ssa/codeql-pack.release.yml b/shared/ssa/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/ssa/codeql-pack.release.yml
+++ b/shared/ssa/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml
index 19304ad107f..2ad254711a5 100644
--- a/shared/ssa/qlpack.yml
+++ b/shared/ssa/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ssa
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies:
diff --git a/shared/threat-models/CHANGELOG.md b/shared/threat-models/CHANGELOG.md
index fba2a870356..a59e560c415 100644
--- a/shared/threat-models/CHANGELOG.md
+++ b/shared/threat-models/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.9
+
+No user-facing changes.
+
## 0.0.8
No user-facing changes.
diff --git a/shared/threat-models/change-notes/released/0.0.9.md b/shared/threat-models/change-notes/released/0.0.9.md
new file mode 100644
index 00000000000..c9e17c6d6cf
--- /dev/null
+++ b/shared/threat-models/change-notes/released/0.0.9.md
@@ -0,0 +1,3 @@
+## 0.0.9
+
+No user-facing changes.
diff --git a/shared/threat-models/codeql-pack.release.yml b/shared/threat-models/codeql-pack.release.yml
index 58fdc6b45de..ecdd64fbab8 100644
--- a/shared/threat-models/codeql-pack.release.yml
+++ b/shared/threat-models/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.0.8
+lastReleaseVersion: 0.0.9
diff --git a/shared/threat-models/qlpack.yml b/shared/threat-models/qlpack.yml
index d0ed9a913b2..60cbbc56fcb 100644
--- a/shared/threat-models/qlpack.yml
+++ b/shared/threat-models/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/threat-models
-version: 0.0.9-dev
+version: 0.0.9
library: true
groups: shared
dataExtensions:
diff --git a/shared/tutorial/CHANGELOG.md b/shared/tutorial/CHANGELOG.md
index 1db3a01af0b..560ad058d5b 100644
--- a/shared/tutorial/CHANGELOG.md
+++ b/shared/tutorial/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/tutorial/change-notes/released/0.2.10.md b/shared/tutorial/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/tutorial/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/tutorial/codeql-pack.release.yml b/shared/tutorial/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/tutorial/codeql-pack.release.yml
+++ b/shared/tutorial/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml
index b595ae9ee70..69116705c1b 100644
--- a/shared/tutorial/qlpack.yml
+++ b/shared/tutorial/qlpack.yml
@@ -1,7 +1,7 @@
name: codeql/tutorial
description: Library for the CodeQL detective tutorials, helping new users learn to
write CodeQL queries.
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/shared/typetracking/CHANGELOG.md b/shared/typetracking/CHANGELOG.md
index afc857bc6bc..350f9ecbeae 100644
--- a/shared/typetracking/CHANGELOG.md
+++ b/shared/typetracking/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/typetracking/change-notes/released/0.2.10.md b/shared/typetracking/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/typetracking/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/typetracking/codeql-pack.release.yml b/shared/typetracking/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/typetracking/codeql-pack.release.yml
+++ b/shared/typetracking/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml
index b55927f59bb..fbbdcf5162a 100644
--- a/shared/typetracking/qlpack.yml
+++ b/shared/typetracking/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/typetracking
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies:
diff --git a/shared/typos/CHANGELOG.md b/shared/typos/CHANGELOG.md
index 66c5871d982..54b1eaa4d58 100644
--- a/shared/typos/CHANGELOG.md
+++ b/shared/typos/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/typos/change-notes/released/0.2.10.md b/shared/typos/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/typos/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/typos/codeql-pack.release.yml b/shared/typos/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/typos/codeql-pack.release.yml
+++ b/shared/typos/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml
index 644bfe11bff..4d59d9b3c34 100644
--- a/shared/typos/qlpack.yml
+++ b/shared/typos/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/typos
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/shared/util/CHANGELOG.md b/shared/util/CHANGELOG.md
index 63832e927fa..1ca1f71bcbc 100644
--- a/shared/util/CHANGELOG.md
+++ b/shared/util/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/util/change-notes/released/0.2.10.md b/shared/util/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/util/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/util/codeql-pack.release.yml b/shared/util/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/util/codeql-pack.release.yml
+++ b/shared/util/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml
index ca1a866a53d..28ed738a93d 100644
--- a/shared/util/qlpack.yml
+++ b/shared/util/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/util
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
dependencies: null
diff --git a/shared/yaml/CHANGELOG.md b/shared/yaml/CHANGELOG.md
index e5495abcd50..9fd5ebc26ab 100644
--- a/shared/yaml/CHANGELOG.md
+++ b/shared/yaml/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.10
+
+No user-facing changes.
+
## 0.2.9
No user-facing changes.
diff --git a/shared/yaml/change-notes/released/0.2.10.md b/shared/yaml/change-notes/released/0.2.10.md
new file mode 100644
index 00000000000..81c9722b19f
--- /dev/null
+++ b/shared/yaml/change-notes/released/0.2.10.md
@@ -0,0 +1,3 @@
+## 0.2.10
+
+No user-facing changes.
diff --git a/shared/yaml/codeql-pack.release.yml b/shared/yaml/codeql-pack.release.yml
index d021cf0a6be..a71167814cb 100644
--- a/shared/yaml/codeql-pack.release.yml
+++ b/shared/yaml/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.2.9
+lastReleaseVersion: 0.2.10
diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml
index de5b47e120a..9643ffcec66 100644
--- a/shared/yaml/qlpack.yml
+++ b/shared/yaml/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/yaml
-version: 0.2.10-dev
+version: 0.2.10
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/swift/ql/lib/CHANGELOG.md b/swift/ql/lib/CHANGELOG.md
index e88cd0259cc..8f14bfcedc9 100644
--- a/swift/ql/lib/CHANGELOG.md
+++ b/swift/ql/lib/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.3.10
+
+### Bug Fixes
+
+* Fixed an issue where `TypeDecl.getFullName` would get stuck in an loop and fail when minor database inconsistencies are present.
+
## 0.3.9
### Minor Analysis Improvements
diff --git a/swift/ql/lib/change-notes/2024-02-22-extension-patch.md b/swift/ql/lib/change-notes/released/0.3.10.md
similarity index 83%
rename from swift/ql/lib/change-notes/2024-02-22-extension-patch.md
rename to swift/ql/lib/change-notes/released/0.3.10.md
index 7bd78f3b785..9d6286ff58a 100644
--- a/swift/ql/lib/change-notes/2024-02-22-extension-patch.md
+++ b/swift/ql/lib/change-notes/released/0.3.10.md
@@ -1,4 +1,5 @@
----
-category: fix
----
+## 0.3.10
+
+### Bug Fixes
+
* Fixed an issue where `TypeDecl.getFullName` would get stuck in an loop and fail when minor database inconsistencies are present.
diff --git a/swift/ql/lib/codeql-pack.release.yml b/swift/ql/lib/codeql-pack.release.yml
index 3fa5180bcb4..76ca0ac8ba7 100644
--- a/swift/ql/lib/codeql-pack.release.yml
+++ b/swift/ql/lib/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.3.9
+lastReleaseVersion: 0.3.10
diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml
index a37a4cb3d58..70ec4798ea8 100644
--- a/swift/ql/lib/qlpack.yml
+++ b/swift/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/swift-all
-version: 0.3.10-dev
+version: 0.3.10
groups: swift
extractor: swift
dbscheme: swift.dbscheme
diff --git a/swift/ql/src/CHANGELOG.md b/swift/ql/src/CHANGELOG.md
index 96615d06972..bda9834c9bc 100644
--- a/swift/ql/src/CHANGELOG.md
+++ b/swift/ql/src/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.3.10
+
+No user-facing changes.
+
## 0.3.9
### New Queries
diff --git a/swift/ql/src/change-notes/released/0.3.10.md b/swift/ql/src/change-notes/released/0.3.10.md
new file mode 100644
index 00000000000..925a48fc52e
--- /dev/null
+++ b/swift/ql/src/change-notes/released/0.3.10.md
@@ -0,0 +1,3 @@
+## 0.3.10
+
+No user-facing changes.
diff --git a/swift/ql/src/codeql-pack.release.yml b/swift/ql/src/codeql-pack.release.yml
index 3fa5180bcb4..76ca0ac8ba7 100644
--- a/swift/ql/src/codeql-pack.release.yml
+++ b/swift/ql/src/codeql-pack.release.yml
@@ -1,2 +1,2 @@
---
-lastReleaseVersion: 0.3.9
+lastReleaseVersion: 0.3.10
diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml
index e3ead42c98b..ba66b065529 100644
--- a/swift/ql/src/qlpack.yml
+++ b/swift/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/swift-queries
-version: 0.3.10-dev
+version: 0.3.10
groups:
- swift
- queries
From dc9092c9ec2cdda8188e9e44d8d51d2a0c6b6cc9 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Wed, 6 Mar 2024 22:19:33 +0000
Subject: [PATCH 032/497] Post-release preparation for codeql-cli-2.16.4
---
cpp/ql/lib/qlpack.yml | 2 +-
cpp/ql/src/qlpack.yml | 2 +-
csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +-
csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +-
csharp/ql/lib/qlpack.yml | 2 +-
csharp/ql/src/qlpack.yml | 2 +-
go/ql/consistency-queries/qlpack.yml | 2 +-
go/ql/lib/qlpack.yml | 2 +-
go/ql/src/qlpack.yml | 2 +-
java/ql/automodel/src/qlpack.yml | 2 +-
java/ql/lib/qlpack.yml | 2 +-
java/ql/src/qlpack.yml | 2 +-
javascript/ql/lib/qlpack.yml | 2 +-
javascript/ql/src/qlpack.yml | 2 +-
misc/suite-helpers/qlpack.yml | 2 +-
python/ql/lib/qlpack.yml | 2 +-
python/ql/src/qlpack.yml | 2 +-
ruby/ql/lib/qlpack.yml | 2 +-
ruby/ql/src/qlpack.yml | 2 +-
shared/controlflow/qlpack.yml | 2 +-
shared/dataflow/qlpack.yml | 2 +-
shared/mad/qlpack.yml | 2 +-
shared/rangeanalysis/qlpack.yml | 2 +-
shared/regex/qlpack.yml | 2 +-
shared/ssa/qlpack.yml | 2 +-
shared/threat-models/qlpack.yml | 2 +-
shared/tutorial/qlpack.yml | 2 +-
shared/typetracking/qlpack.yml | 2 +-
shared/typos/qlpack.yml | 2 +-
shared/util/qlpack.yml | 2 +-
shared/yaml/qlpack.yml | 2 +-
swift/ql/lib/qlpack.yml | 2 +-
swift/ql/src/qlpack.yml | 2 +-
33 files changed, 33 insertions(+), 33 deletions(-)
diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml
index 3bb9229bf94..8b17a050d82 100644
--- a/cpp/ql/lib/qlpack.yml
+++ b/cpp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-all
-version: 0.12.7
+version: 0.12.8-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml
index 4052647bb97..49eb255cc8f 100644
--- a/cpp/ql/src/qlpack.yml
+++ b/cpp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/cpp-queries
-version: 0.9.6
+version: 0.9.7-dev
groups:
- cpp
- queries
diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
index ee993bed0c9..3e8792bce0e 100644
--- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
-version: 1.7.10
+version: 1.7.11-dev
groups:
- csharp
- solorigate
diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
index 1f421754fc8..c67ab9130a0 100644
--- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml
+++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
-version: 1.7.10
+version: 1.7.11-dev
groups:
- csharp
- solorigate
diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml
index 93c5c1120a2..a67b40f744f 100644
--- a/csharp/ql/lib/qlpack.yml
+++ b/csharp/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-all
-version: 0.8.10
+version: 0.8.11-dev
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp
diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml
index 46384094b19..a2148a36157 100644
--- a/csharp/ql/src/qlpack.yml
+++ b/csharp/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/csharp-queries
-version: 0.8.10
+version: 0.8.11-dev
groups:
- csharp
- queries
diff --git a/go/ql/consistency-queries/qlpack.yml b/go/ql/consistency-queries/qlpack.yml
index d5a2fbee5f1..e82c98f52cb 100644
--- a/go/ql/consistency-queries/qlpack.yml
+++ b/go/ql/consistency-queries/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql-go-consistency-queries
-version: 0.0.9
+version: 0.0.10-dev
groups:
- go
- queries
diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml
index 8cc190fa880..54b284e7ee5 100644
--- a/go/ql/lib/qlpack.yml
+++ b/go/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/go-all
-version: 0.7.10
+version: 0.7.11-dev
groups: go
dbscheme: go.dbscheme
extractor: go
diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml
index 4ded3a52f63..c89aacb8aa2 100644
--- a/go/ql/src/qlpack.yml
+++ b/go/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/go-queries
-version: 0.7.10
+version: 0.7.11-dev
groups:
- go
- queries
diff --git a/java/ql/automodel/src/qlpack.yml b/java/ql/automodel/src/qlpack.yml
index 59fab0cdcc5..8064163f5cc 100644
--- a/java/ql/automodel/src/qlpack.yml
+++ b/java/ql/automodel/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-automodel-queries
-version: 0.0.17
+version: 0.0.18-dev
groups:
- java
- automodel
diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml
index 428eedc75e3..ed83a620d20 100644
--- a/java/ql/lib/qlpack.yml
+++ b/java/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-all
-version: 0.8.10
+version: 0.8.11-dev
groups: java
dbscheme: config/semmlecode.dbscheme
extractor: java
diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml
index ebbdbeee3b2..d7612d9da67 100644
--- a/java/ql/src/qlpack.yml
+++ b/java/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/java-queries
-version: 0.8.10
+version: 0.8.11-dev
groups:
- java
- queries
diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml
index da16493a21c..30fa7de4198 100644
--- a/javascript/ql/lib/qlpack.yml
+++ b/javascript/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-all
-version: 0.8.10
+version: 0.8.11-dev
groups: javascript
dbscheme: semmlecode.javascript.dbscheme
extractor: javascript
diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml
index d224952c564..01a3e8a0841 100644
--- a/javascript/ql/src/qlpack.yml
+++ b/javascript/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-queries
-version: 0.8.10
+version: 0.8.11-dev
groups:
- javascript
- queries
diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml
index 54d978d5efe..5d8225b2e0b 100644
--- a/misc/suite-helpers/qlpack.yml
+++ b/misc/suite-helpers/qlpack.yml
@@ -1,4 +1,4 @@
name: codeql/suite-helpers
-version: 0.7.10
+version: 0.7.11-dev
groups: shared
warnOnImplicitThis: true
diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml
index 59a8b4c96d1..daab6a41206 100644
--- a/python/ql/lib/qlpack.yml
+++ b/python/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/python-all
-version: 0.11.10
+version: 0.11.11-dev
groups: python
dbscheme: semmlecode.python.dbscheme
extractor: python
diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml
index c920f667836..5b641a329cb 100644
--- a/python/ql/src/qlpack.yml
+++ b/python/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/python-queries
-version: 0.9.10
+version: 0.9.11-dev
groups:
- python
- queries
diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml
index de5b41999fe..81695d545ec 100644
--- a/ruby/ql/lib/qlpack.yml
+++ b/ruby/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ruby-all
-version: 0.8.10
+version: 0.8.11-dev
groups: ruby
extractor: ruby
dbscheme: ruby.dbscheme
diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml
index 5e379268234..65e81bf2ba2 100644
--- a/ruby/ql/src/qlpack.yml
+++ b/ruby/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ruby-queries
-version: 0.8.10
+version: 0.8.11-dev
groups:
- ruby
- queries
diff --git a/shared/controlflow/qlpack.yml b/shared/controlflow/qlpack.yml
index 1d43802be42..19c95747294 100644
--- a/shared/controlflow/qlpack.yml
+++ b/shared/controlflow/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/controlflow
-version: 0.1.10
+version: 0.1.11-dev
groups: shared
library: true
dependencies:
diff --git a/shared/dataflow/qlpack.yml b/shared/dataflow/qlpack.yml
index ee422e02ea9..4e896e9ae02 100644
--- a/shared/dataflow/qlpack.yml
+++ b/shared/dataflow/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/dataflow
-version: 0.2.1
+version: 0.2.2-dev
groups: shared
library: true
dependencies:
diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml
index 6d7269ef3da..e3d2ccaf748 100644
--- a/shared/mad/qlpack.yml
+++ b/shared/mad/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/mad
-version: 0.2.10
+version: 0.2.11-dev
groups: shared
library: true
dependencies: null
diff --git a/shared/rangeanalysis/qlpack.yml b/shared/rangeanalysis/qlpack.yml
index 01db5d5734d..6a528c17637 100644
--- a/shared/rangeanalysis/qlpack.yml
+++ b/shared/rangeanalysis/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/rangeanalysis
-version: 0.0.9
+version: 0.0.10-dev
groups: shared
library: true
dependencies:
diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml
index 0d4f485312f..8717c5b8a73 100644
--- a/shared/regex/qlpack.yml
+++ b/shared/regex/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/regex
-version: 0.2.10
+version: 0.2.11-dev
groups: shared
library: true
dependencies:
diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml
index 2ad254711a5..656662e9061 100644
--- a/shared/ssa/qlpack.yml
+++ b/shared/ssa/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/ssa
-version: 0.2.10
+version: 0.2.11-dev
groups: shared
library: true
dependencies:
diff --git a/shared/threat-models/qlpack.yml b/shared/threat-models/qlpack.yml
index 60cbbc56fcb..ece8f74f701 100644
--- a/shared/threat-models/qlpack.yml
+++ b/shared/threat-models/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/threat-models
-version: 0.0.9
+version: 0.0.10-dev
library: true
groups: shared
dataExtensions:
diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml
index 69116705c1b..b1f2b729a85 100644
--- a/shared/tutorial/qlpack.yml
+++ b/shared/tutorial/qlpack.yml
@@ -1,7 +1,7 @@
name: codeql/tutorial
description: Library for the CodeQL detective tutorials, helping new users learn to
write CodeQL queries.
-version: 0.2.10
+version: 0.2.11-dev
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml
index fbbdcf5162a..efca1702069 100644
--- a/shared/typetracking/qlpack.yml
+++ b/shared/typetracking/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/typetracking
-version: 0.2.10
+version: 0.2.11-dev
groups: shared
library: true
dependencies:
diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml
index 4d59d9b3c34..76434dcb21c 100644
--- a/shared/typos/qlpack.yml
+++ b/shared/typos/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/typos
-version: 0.2.10
+version: 0.2.11-dev
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml
index 28ed738a93d..f4d51c896ce 100644
--- a/shared/util/qlpack.yml
+++ b/shared/util/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/util
-version: 0.2.10
+version: 0.2.11-dev
groups: shared
library: true
dependencies: null
diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml
index 9643ffcec66..41f2bc851fd 100644
--- a/shared/yaml/qlpack.yml
+++ b/shared/yaml/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/yaml
-version: 0.2.10
+version: 0.2.11-dev
groups: shared
library: true
warnOnImplicitThis: true
diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml
index 70ec4798ea8..673004b5172 100644
--- a/swift/ql/lib/qlpack.yml
+++ b/swift/ql/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/swift-all
-version: 0.3.10
+version: 0.3.11-dev
groups: swift
extractor: swift
dbscheme: swift.dbscheme
diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml
index ba66b065529..11192f11d8b 100644
--- a/swift/ql/src/qlpack.yml
+++ b/swift/ql/src/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/swift-queries
-version: 0.3.10
+version: 0.3.11-dev
groups:
- swift
- queries
From c325ff8a237d6c5fa860a1eed288ee508b5c46bf Mon Sep 17 00:00:00 2001
From: Henry Mercer
Date: Mon, 11 Mar 2024 16:38:33 +0000
Subject: [PATCH 033/497] Mark lines of code queries as telemetry queries
The new file coverage metrics are available in all supported GHES
versions. This PR tags lines of code queries as telemetry queries. Lines
of code information will still be available in the SARIF file, but it
will no longer be displayed in the logging output of the CLI.
The one exception is the metric queries for Java/Kotlin that provides
separate lines of code information for Java and Kotlin. I've kept these
since separate file coverage information for languages like Java and
Kotlin is only available for GHES 3.12 and later.
---
cpp/ql/src/Summary/LinesOfUserCode.ql | 1 +
csharp/ql/src/Metrics/Summaries/LinesOfCode.ql | 1 +
go/ql/src/Summary/LinesOfCode.ql | 1 +
java/ql/src/Metrics/Summaries/LinesOfCode.ql | 1 +
javascript/ql/src/Summary/LinesOfUserCode.ql | 1 +
python/ql/src/Summary/LinesOfUserCode.ql | 1 +
ql/ql/src/queries/summary/LinesOfCode.ql | 1 +
ql/ql/src/queries/summary/LinesOfUserCode.ql | 1 +
ruby/ql/src/queries/summary/LinesOfCode.ql | 1 +
ruby/ql/src/queries/summary/LinesOfUserCode.ql | 1 +
swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql | 1 +
11 files changed, 11 insertions(+)
diff --git a/cpp/ql/src/Summary/LinesOfUserCode.ql b/cpp/ql/src/Summary/LinesOfUserCode.ql
index 67d3aa6a8e0..2c198a1488d 100644
--- a/cpp/ql/src/Summary/LinesOfUserCode.ql
+++ b/cpp/ql/src/Summary/LinesOfUserCode.ql
@@ -4,6 +4,7 @@
* @kind metric
* @tags summary
* lines-of-code
+ * telemetry
* @id cpp/summary/lines-of-user-code
*/
diff --git a/csharp/ql/src/Metrics/Summaries/LinesOfCode.ql b/csharp/ql/src/Metrics/Summaries/LinesOfCode.ql
index 2115cd60d2b..4c6eb55e5ab 100644
--- a/csharp/ql/src/Metrics/Summaries/LinesOfCode.ql
+++ b/csharp/ql/src/Metrics/Summaries/LinesOfCode.ql
@@ -5,6 +5,7 @@
* @kind metric
* @tags summary
* lines-of-code
+ * telemetry
*/
import csharp
diff --git a/go/ql/src/Summary/LinesOfCode.ql b/go/ql/src/Summary/LinesOfCode.ql
index 383d7c5021e..04864e5c4a0 100644
--- a/go/ql/src/Summary/LinesOfCode.ql
+++ b/go/ql/src/Summary/LinesOfCode.ql
@@ -5,6 +5,7 @@
* @kind metric
* @tags summary
* lines-of-code
+ * telemetry
*/
import go
diff --git a/java/ql/src/Metrics/Summaries/LinesOfCode.ql b/java/ql/src/Metrics/Summaries/LinesOfCode.ql
index 769a3476ed2..1ead46f1b20 100644
--- a/java/ql/src/Metrics/Summaries/LinesOfCode.ql
+++ b/java/ql/src/Metrics/Summaries/LinesOfCode.ql
@@ -7,6 +7,7 @@
* @kind metric
* @tags summary
* lines-of-code
+ * telemetry
*/
import java
diff --git a/javascript/ql/src/Summary/LinesOfUserCode.ql b/javascript/ql/src/Summary/LinesOfUserCode.ql
index 61ad13519cb..83fbb9b32da 100644
--- a/javascript/ql/src/Summary/LinesOfUserCode.ql
+++ b/javascript/ql/src/Summary/LinesOfUserCode.ql
@@ -6,6 +6,7 @@
* @kind metric
* @tags summary
* lines-of-code
+ * telemetry
* @id js/summary/lines-of-user-code
*/
diff --git a/python/ql/src/Summary/LinesOfUserCode.ql b/python/ql/src/Summary/LinesOfUserCode.ql
index 528ae948cd7..a30ba7afd19 100644
--- a/python/ql/src/Summary/LinesOfUserCode.ql
+++ b/python/ql/src/Summary/LinesOfUserCode.ql
@@ -8,6 +8,7 @@
* @kind metric
* @tags summary
* lines-of-code
+ * telemetry
* @id py/summary/lines-of-user-code
*/
diff --git a/ql/ql/src/queries/summary/LinesOfCode.ql b/ql/ql/src/queries/summary/LinesOfCode.ql
index cb5ef617476..c0dbe831967 100644
--- a/ql/ql/src/queries/summary/LinesOfCode.ql
+++ b/ql/ql/src/queries/summary/LinesOfCode.ql
@@ -8,6 +8,7 @@
* @kind metric
* @tags summary
* lines-of-code
+ * telemetry
*/
import ql
diff --git a/ql/ql/src/queries/summary/LinesOfUserCode.ql b/ql/ql/src/queries/summary/LinesOfUserCode.ql
index 1701af1a5c9..8f49ce27d2f 100644
--- a/ql/ql/src/queries/summary/LinesOfUserCode.ql
+++ b/ql/ql/src/queries/summary/LinesOfUserCode.ql
@@ -6,6 +6,7 @@
* query counts the lines of code, excluding whitespace or comments.
* @kind metric
* @tags summary
+ * telemetry
*/
import ql
diff --git a/ruby/ql/src/queries/summary/LinesOfCode.ql b/ruby/ql/src/queries/summary/LinesOfCode.ql
index 74994d77347..34e7438bab1 100644
--- a/ruby/ql/src/queries/summary/LinesOfCode.ql
+++ b/ruby/ql/src/queries/summary/LinesOfCode.ql
@@ -8,6 +8,7 @@
* @kind metric
* @tags summary
* lines-of-code
+ * telemetry
*/
import codeql.ruby.AST
diff --git a/ruby/ql/src/queries/summary/LinesOfUserCode.ql b/ruby/ql/src/queries/summary/LinesOfUserCode.ql
index d8025088ceb..121124862a1 100644
--- a/ruby/ql/src/queries/summary/LinesOfUserCode.ql
+++ b/ruby/ql/src/queries/summary/LinesOfUserCode.ql
@@ -6,6 +6,7 @@
* query counts the lines of code, excluding whitespace or comments.
* @kind metric
* @tags summary
+ * telemetry
*/
import codeql.ruby.AST
diff --git a/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql b/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql
index 373b6c4bd0f..9fc40680852 100644
--- a/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql
+++ b/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql
@@ -4,6 +4,7 @@
* @kind metric
* @id swift/diagnostics/successfully-extracted-lines
* @tags summary
+ * telemetry
*/
import swift
From d1f8336be6a44017cbfc7f3749ea18764409c1db Mon Sep 17 00:00:00 2001
From: Pierre
Date: Mon, 11 Mar 2024 22:21:25 +0100
Subject: [PATCH 034/497] Add changelog for 2.16.4
---
.../codeql-changelog/codeql-cli-2.16.1.rst | 2 +-
.../codeql-changelog/codeql-cli-2.16.3.rst | 13 +-
.../codeql-changelog/codeql-cli-2.16.4.rst | 156 ++++++++++++++++++
.../codeql-changelog/index.rst | 1 +
4 files changed, 165 insertions(+), 7 deletions(-)
create mode 100644 docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.16.4.rst
diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.16.1.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.16.1.rst
index e9f1dd20f34..7a1e6b6230b 100644
--- a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.16.1.rst
+++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.16.1.rst
@@ -171,7 +171,7 @@ Python
Ruby
""""
-* Deleted many deprecated predicates and classes with uppercase :code:`HTTP`, :code:`CSRF`, :code:`,` etc. in their names. Use the PascalCased versions instead.
+* Deleted many deprecated predicates and classes with uppercase :code:`HTTP`, :code:`CSRF` etc. in their names. Use the PascalCased versions instead.
* Deleted the deprecated :code:`getAUse` and :code:`getARhs` predicates from :code:`API::Node`, use :code:`getASource` and :code:`getASink` instead.
* Deleted the deprecated :code:`disablesCertificateValidation` predicate from the :code:`Http` module.
* Deleted the deprecated :code:`ParamsCall`, :code:`CookiesCall`, and :code:`ActionControllerControllerClass` classes from :code:`ActionController.qll`, use the simarly named classes from :code:`codeql.ruby.frameworks.Rails::Rails` instead.
diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.16.3.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.16.3.rst
index af699a301c4..af7c4ce84b0 100644
--- a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.16.3.rst
+++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.16.3.rst
@@ -27,14 +27,15 @@ Bug Fixes
New Features
~~~~~~~~~~~~
-* A new extractor option has been added to the Python extractor: :code:`python_executable_name`.
- You can use this option to override the default process the extractor uses to find and select a Python executable.
- Pass one of :code:`--extractor-option python_executable_name=py` or :code:`--extractor-option python_executable_name=python` or :code:`--extractor-option python_executable_name=python3` to commands that run the extractor, for example: :code:`codeql database create`.
+* A new extractor option has been added to the Python extractor:
+ :code:`python_executable_name`. You can use this option to override the default process the extractor uses to find and select a Python executable. Pass one of
+ :code:`--extractor-option python_executable_name=py` or :code:`--extractor-option python_executable_name=python` or :code:`--extractor-option python_executable_name=python3` to commands that run the extractor, for example: :code:`codeql database create`.
- On Windows machines, the Python extractor will expect to find :code:`py.exe` on the system :code:`PATH` by default.
- If the Python executable has a different name, you can set the new extractor option to override this value and look for :code:`python.exe` or :code:`python3.exe`.
+ On Windows machines, the Python extractor will expect to find :code:`py.exe` on the system :code:`PATH` by default. If the Python executable has a different name, you can set the new extractor option to override this value and look for
+ :code:`python.exe` or :code:`python3.exe`.
- For more information about using the extractor option with the CodeQL CLI, see `Extractor options `__.
+ For more information about using the extractor option with the CodeQL CLI, see
+ \ `Extractor options `__.
Security Updates
~~~~~~~~~~~~~~~~
diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.16.4.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.16.4.rst
new file mode 100644
index 00000000000..dccf2ce4796
--- /dev/null
+++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.16.4.rst
@@ -0,0 +1,156 @@
+.. _codeql-cli-2.16.4:
+
+==========================
+CodeQL 2.16.4 (2024-03-11)
+==========================
+
+.. contents:: Contents
+ :depth: 2
+ :local:
+ :backlinks: none
+
+This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog `__, `relevant GitHub Changelog updates `__, `changes in the CodeQL extension for Visual Studio Code `__, and the `CodeQL Action changelog `__.
+
+Security Coverage
+-----------------
+
+CodeQL 2.16.4 runs a total of 409 security queries when configured with the Default suite (covering 160 CWE). The Extended suite enables an additional 132 queries (covering 34 more CWE). 2 security queries have been added with this release.
+
+CodeQL CLI
+----------
+
+Potentially Breaking Changes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* A number of internal command line options (:code:`--builtin_functions_file`, :code:`--clang_builtin_functions`,
+ :code:`--disable-objc-default-synthesize-properties`, :code:`--list_builtin_functions`, :code:`--memory-limit-bytes`,
+ :code:`--mimic_config`, and :code:`--objc`) has been removed from the C/C++ extractor. It has never been possible to pass these options through the CLI itself, but some customers with advanced setups may have been passing them through internal undocumented interfaces. All of the removed options were already no-ops, and will now generate errors.
+
+ The :code:`--verbosity` command line option has also been removed. The option was an alias for
+ :code:`--codeql-verbosity`, which should be used instead.
+
+Bug Fixes
+~~~~~~~~~
+
+* When parsing user-authored YAML files such as :code:`codeql-pack.yml`,
+ :code:`qlpack.yml`, :code:`codeql-workspace.yml`, and any YAML file defining a data extension, unquoted string values starting with a :code:`*` character are now correctly interpreted as YAML aliases. Previously, they were interpreted as strings, but with the first character skipped.
+
+ If you see a parse error similar to :code:`while scanning an alias... unexpected` :code:`character found *(42)`,it likely means that you need to add quotes around the indicated string value. The most common cause is unquoted glob patterns that start with :code:`*`, such as :code:`include: **/*.yml`, which will need to be quoted as :code:`include: "**/*.yml"`.
+
+Improvements
+~~~~~~~~~~~~
+
+* The frontend of the C/C++ extractor has been updated, improving the extractor's reliability and increasing its ability to extract source code.
+
+Query Packs
+-----------
+
+Minor Analysis Improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+C/C++
+"""""
+
+* The "non-constant format string" query (:code:`cpp/non-constant-format`) has been converted to a :code:`path-problem` query.
+* The new C/C++ dataflow and taint-tracking libraries (:code:`semmle.code.cpp.dataflow.new.DataFlow` and :code:`semmle.code.cpp.dataflow.new.TaintTracking`) now implicitly assume that dataflow and taint modelled via :code:`DataFlowFunction` and :code:`TaintFunction` always fully overwrite their buffers and thus act as flow barriers. As a result, many dataflow and taint-tracking queries now produce fewer false positives. To remove this assumption and go back to the previous behavior for a given model, one can override the new :code:`isPartialWrite` predicate.
+
+C#
+""
+
+* Most data flow queries that track flow from *remote* flow sources now use the current *threat model* configuration instead. This doesn't lead to any changes in the produced alerts (as the default configuration is *remote* flow sources) unless the threat model configuration is changed. The changed queries are :code:`cs/code-injection`, :code:`cs/command-line-injection`, :code:`cs/user-controlled-bypass`, :code:`cs/count-untrusted-data-external-api`, :code:`cs/untrusted-data-to-external-api`, :code:`cs/ldap-injection`, :code:`cs/log-forging`, :code:`cs/xml/missing-validation`, :code:`cs/redos`, :code:`cs/regex-injection`, :code:`cs/resource-injection`, :code:`cs/sql-injection`, :code:`cs/path-injection`, :code:`cs/unsafe-deserialization-untrusted-input`, :code:`cs/web/unvalidated-url-redirection`, :code:`cs/xml/insecure-dtd-handling`, :code:`cs/xml/xpath-injection`, :code:`cs/web/xss`, and :code:`cs/uncontrolled-format-string`.
+
+Java
+""""
+
+* To reduce the number of false positives in the query "Insertion of sensitive information into log files" (:code:`java/sensitive-log`), variables with names that contain "null" (case-insensitively) are no longer considered sources of sensitive information.
+
+Ruby
+""""
+
+* Calls to :code:`Object#method`, :code:`Object#public_method` and :code:`Object#singleton_method` with untrusted data are now recognised as sinks for code injection.
+* Added additional request sources for Ruby on Rails.
+
+New Queries
+~~~~~~~~~~~
+
+Java
+""""
+
+* Added a new query :code:`java/android/insecure-local-key-gen` for finding instances of keys generated for biometric authentication in an insecure way.
+
+Python
+""""""
+
+* The query :code:`py/nosql-injection` for finding NoSQL injection vulnerabilities is now part of the default security suite.
+
+Language Libraries
+------------------
+
+Bug Fixes
+~~~~~~~~~
+
+Golang
+""""""
+
+* Fixed dataflow out of a :code:`map` using a :code:`range` statement.
+
+Java
+""""
+
+* Fixed the Java autobuilder overriding the version of Maven used by a project when the Maven wrapper :code:`mvnw` is in use and the :code:`maven-wrapper.jar` file is not present in the repository.
+* Some flow steps related to :code:`android.text.Editable.toString` that were accidentally disabled have been re-enabled.
+
+Swift
+"""""
+
+* Fixed an issue where :code:`TypeDecl.getFullName` would get stuck in an loop and fail when minor database inconsistencies are present.
+
+Major Analysis Improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+C#
+""
+
+* Improved support for flow through captured variables that properly adheres to inter-procedural control flow.
+* We no longer make use of CodeQL database stats, which may affect join-orders in custom queries. It is therefore recommended to test performance of custom queries after upgrading to this version.
+
+Golang
+""""""
+
+* We have significantly improved the Go autobuilder to understand a greater range of project layouts, which allows Go source files to be analysed that could previously not be processed.
+* Go 1.22 has been included in the range of supported Go versions.
+
+Minor Analysis Improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+C/C++
+"""""
+
+* Added destructors for named objects to the intermediate representation.
+
+C#
+""
+
+* C# 12: Add QL library support (:code:`ExperimentalAttribute`) for the experimental attribute.
+* C# 12: Add extractor and QL library support for :code:`ref readonly` parameters.
+* C#: The table :code:`expr_compiler_generated` has been deleted and its content has been added to :code:`compiler_generated`.
+* Data flow via get only properties like :code:`public object Obj { get; }` is now captured by the data flow library.
+
+Java
+""""
+
+* Java expressions with erroneous types (e.g. the result of a call whose callee couldn't be resolved during extraction) are now given a CodeQL :code:`ErrorType` more often.
+
+Python
+""""""
+
+* Fixed missing flow for dictionary updates (:code:`d[] = ...`) when :code:`` is a string constant not used in dictionary literals or as name of keyword-argument.
+* Fixed flow for iterable unpacking (:code:`a,b = my_tuple`) when it occurs on top-level (module) scope.
+
+Ruby
+""""
+
+* Calls to :code:`I18n.translate` as well as Rails helper translate methods now propagate taint from their keyword arguments. The Rails translate methods are also recognized as XSS sanitizers when using keys marked as html safe.
+* Calls to :code:`Arel::Nodes::SqlLiteral.new` are now modeled as instances of the :code:`SqlConstruction` concept, as well as propagating taint from their argument.
+* Additional arguments beyond the first of calls to the :code:`ActiveRecord` methods :code:`select`, :code:`reselect`, :code:`order`, :code:`reorder`, :code:`joins`, :code:`group`, and :code:`pluck` are now recognized as sql injection sinks.
+* Calls to several methods of :code:`ActiveRecord::Connection`, such as :code:`ActiveRecord::Connection#exec_query`, are now recognized as SQL executions, including those via subclasses.
diff --git a/docs/codeql/codeql-overview/codeql-changelog/index.rst b/docs/codeql/codeql-overview/codeql-changelog/index.rst
index a04f37ad9e4..edec857c740 100644
--- a/docs/codeql/codeql-overview/codeql-changelog/index.rst
+++ b/docs/codeql/codeql-overview/codeql-changelog/index.rst
@@ -11,6 +11,7 @@ A list of queries for each suite and language `is available here
Date: Tue, 12 Mar 2024 19:59:26 +0100
Subject: [PATCH 035/497] [cpp-docs] Fix 404 link in guards library doc.
---
.../codeql-language-guides/using-the-guards-library-in-cpp.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/codeql/codeql-language-guides/using-the-guards-library-in-cpp.rst b/docs/codeql/codeql-language-guides/using-the-guards-library-in-cpp.rst
index 792cbcd4703..1900f1b8e05 100644
--- a/docs/codeql/codeql-language-guides/using-the-guards-library-in-cpp.rst
+++ b/docs/codeql/codeql-language-guides/using-the-guards-library-in-cpp.rst
@@ -8,7 +8,7 @@ You can use the CodeQL guards library to identify conditional expressions that c
About the guards library
------------------------
-The guards library (defined in ``semmle.code.cpp.controlflow.Guards``) provides a class `GuardCondition `__ representing Boolean values that are used to make control flow decisions.
+The guards library (defined in ``semmle.code.cpp.controlflow.Guards``) provides a class `GuardCondition `__ representing Boolean values that are used to make control flow decisions.
A ``GuardCondition`` is considered to guard a basic block if the block can only be reached if the ``GuardCondition`` is evaluated a certain way. For instance, in the following code, ``x < 10`` is a ``GuardCondition``, and it guards all the code before the return statement.
.. code-block:: cpp
From 806f42ef7240357b2d2b00948210deab939afa3e Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Wed, 13 Mar 2024 09:54:17 +0000
Subject: [PATCH 036/497] Ruby: Update change note
---
.../src/change-notes/2023-09-25-csrf-protection-not-enabled.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ruby/ql/src/change-notes/2023-09-25-csrf-protection-not-enabled.md b/ruby/ql/src/change-notes/2023-09-25-csrf-protection-not-enabled.md
index e8e7ac54e38..c84492291a3 100644
--- a/ruby/ql/src/change-notes/2023-09-25-csrf-protection-not-enabled.md
+++ b/ruby/ql/src/change-notes/2023-09-25-csrf-protection-not-enabled.md
@@ -1,4 +1,4 @@
---
category: newQuery
---
-* Added a new experimental query, `rb/csrf-protection-not-enabled`, to detect cases where Cross-Site Request Forgery protection is not enabled in Ruby on Rails controllers.
+* Added a new query, `rb/csrf-protection-not-enabled`, to detect cases where Cross-Site Request Forgery protection is not enabled in Ruby on Rails controllers.
From 533b63743b2b538f257d975851c5fca0bcfb49e7 Mon Sep 17 00:00:00 2001
From: Rasmus Lerchedahl Petersen
Date: Wed, 13 Mar 2024 15:28:34 +0100
Subject: [PATCH 037/497] Python: test MaD syntax for keyword argument use the
combined positional/keyword syntax as that is what we will probably mostly
use.
---
.../dataflow/model-summaries/NormalDataflowTest.ext.yml | 2 +-
.../experimental/dataflow/model-summaries/model_summaries.py | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml b/python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml
index e3a7e059401..b3898193f59 100644
--- a/python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml
+++ b/python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml
@@ -3,7 +3,7 @@ extensions:
pack: codeql/python-all
extensible: summaryModel
data:
- - ["foo", "Member[MS_identity]", "Argument[0]", "ReturnValue", "value"]
+ - ["foo", "Member[MS_identity]", "Argument[0,x:]", "ReturnValue", "value"]
- ["foo", "Member[MS_apply_lambda]", "Argument[1]", "Argument[0].Parameter[0]", "value"]
- ["foo", "Member[MS_apply_lambda]", "Argument[0].ReturnValue", "ReturnValue", "value"]
- ["foo", "Member[MS_reversed]", "Argument[0].ListElement", "ReturnValue.ListElement", "value"]
diff --git a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py
index c8c5ac0a888..071d1ae6aa4 100644
--- a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py
+++ b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py
@@ -36,6 +36,10 @@ from foo import MS_identity, MS_apply_lambda, MS_reversed, MS_list_map, MS_appen
via_identity = MS_identity(SOURCE)
SINK(via_identity) # $ flow="SOURCE, l:-1 -> via_identity"
+# Simple summary keyword
+via_identity_kw = MS_identity(x = SOURCE)
+SINK(via_identity_kw) # $ flow="SOURCE, l:-1 -> via_identity_kw"
+
# Lambda summary
via_lambda = MS_apply_lambda(lambda x: [x], SOURCE)
SINK(via_lambda[0]) # $ flow="SOURCE, l:-1 -> via_lambda[0]"
From 0d38a9625e039120e715dfe79b529dc5bfead3d8 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Mon, 20 Nov 2023 15:12:33 -0500
Subject: [PATCH 038/497] Java: copy files from experimental
---
...unsafeUrlForwardExperimentalMove.model.yml | 61 ++++
.../CWE/CWE-552/UnsafeLoadSpringResource.java | 21 ++
.../CWE/CWE-552/UnsafeResourceGet.java | 18 ++
.../CWE-552/UnsafeServletRequestDispatch.java | 11 +
.../CWE/CWE-552/UnsafeUrlForward.java | 38 +++
.../CWE/CWE-552/UnsafeUrlForward.qhelp | 70 +++++
.../Security/CWE/CWE-552/UnsafeUrlForward.ql | 63 ++++
.../Security/CWE/CWE-552/UnsafeUrlForward.qll | 163 +++++++++++
.../CWE-552/UnsafeLoadSpringResource.java | 155 ++++++++++
.../security/CWE-552/UnsafeRequestPath.java | 52 ++++
.../security/CWE-552/UnsafeResourceGet.java | 270 ++++++++++++++++++
.../security/CWE-552/UnsafeResourceGet2.java | 58 ++++
.../CWE-552/UnsafeServletRequestDispatch.java | 131 +++++++++
.../CWE-552/UnsafeUrlForward.expected | 129 +++++++++
.../security/CWE-552/UnsafeUrlForward.java | 78 +++++
.../security/CWE-552/UnsafeUrlForward.qlref | 1 +
.../test/query-tests/security/CWE-552/options | 1 +
17 files changed, 1320 insertions(+)
create mode 100644 java/ql/lib/ext/unsafeUrlForwardExperimentalMove.model.yml
create mode 100644 java/ql/src/Security/CWE/CWE-552/UnsafeLoadSpringResource.java
create mode 100644 java/ql/src/Security/CWE/CWE-552/UnsafeResourceGet.java
create mode 100644 java/ql/src/Security/CWE/CWE-552/UnsafeServletRequestDispatch.java
create mode 100644 java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.java
create mode 100644 java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qhelp
create mode 100644 java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql
create mode 100644 java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qll
create mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeLoadSpringResource.java
create mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java
create mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet.java
create mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet2.java
create mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java
create mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.expected
create mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.java
create mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.qlref
create mode 100644 java/ql/test/query-tests/security/CWE-552/options
diff --git a/java/ql/lib/ext/unsafeUrlForwardExperimentalMove.model.yml b/java/ql/lib/ext/unsafeUrlForwardExperimentalMove.model.yml
new file mode 100644
index 00000000000..b48d891e692
--- /dev/null
+++ b/java/ql/lib/ext/unsafeUrlForwardExperimentalMove.model.yml
@@ -0,0 +1,61 @@
+extensions:
+ - addsTo:
+ pack: codeql/java-all
+ extensible: sourceModel
+ data:
+ - ["jakarta.servlet.http", "HttpServletRequest", True, "getServletPath", "", "", "ReturnValue", "remote", "manual"]
+ - ["javax.servlet.http", "HttpServletRequest", True, "getServletPath", "", "", "ReturnValue", "remote", "manual"]
+
+ # # ! below added by me when debugging CVEs:
+ # - ["org.springframework.cloud.config.server.resource", "ResourceController", True, "retrieve", "(String,String,String,ServletWebRequest,boolean)", "", "Parameter[3]", "remote", "manual"]
+ # - ["org.springframework.web.context.request", "ServletWebRequest", True, "getContextPath", "()", "", "ReturnValue", "remote", "manual"]
+
+ - addsTo:
+ pack: codeql/java-all
+ extensible: sinkModel
+ data:
+ - ["java.util.concurrent", "TimeUnit", True, "sleep", "", "", "Argument[0]", "thread-pause", "manual"] # ! this seems like a typo; doesn't look like it's used in the query at all
+
+ - ["org.springframework.core.io", "ClassPathResource", True, "getFilename", "", "", "Argument[this]", "get-resource", "manual"] # ! Note: `ClassPathResource` implements `Resource`, so it might make more sense to model some of these as `Resource` with subtype True.
+ - ["org.springframework.core.io", "ClassPathResource", True, "getPath", "", "", "Argument[this]", "get-resource", "manual"]
+ - ["org.springframework.core.io", "ClassPathResource", True, "getURL", "", "", "Argument[this]", "get-resource", "manual"]
+ - ["org.springframework.core.io", "ClassPathResource", True, "resolveURL", "", "", "Argument[this]", "get-resource", "manual"]
+ # # ! below added by me when debugging CVEs:
+ # - ["org.springframework.cloud.config.server.resource", "ResourceController", True, "retrieve", "", "", "Argument[0]", "get-resource", "manual"] # don't need
+ # # - ["org.springframework.cloud.config.server.resource", "ResourceController", True, "getFilePath", "", "", "Argument[0..3]", "get-resource", "manual"] # don't need
+ # # - ["org.springframework.cloud.config.server.resource", "ResourceRepository", True, "findOne", "", "", "Argument[0..3]", "get-resource", "manual"] # convert to summary
+ # # - ["org.springframework.core.io", "InputStreamSource", True, "getInputStream", "", "", "Argument[this]", "get-resource", "manual"] # convert to summary
+ # - ["org.springframework.util", "StreamUtils", True, "copyToString", "", "", "Argument[0]", "get-resource", "manual"] # * public class with good docs
+ # # - ["org.springframework.cloud.config.server.environment", "SearchPathLocator", True, "getLocations", "(String,String,String)", "", "Argument[0..2]", "get-resource", "manual"] # convert to summary
+ # # - ["org.springframework.cloud.config.server.environment", "SearchPathLocator$Locations", True, "getLocations", "()", "", "Argument[this]", "get-resource", "manual"] # convert to summary
+ # - ["org.springframework.core.io", "ResourceLoader", True, "getResource", "", "", "Argument[0]", "get-resource", "manual"] # * public interface with good docs, might be problematic for FPs based on fact that the ext contributor changed this to a taint step to avoid "exists" FPS (maybe there's another way to exclude those FPs though).
+ # - ["javax.servlet", "ServletContext", True, "getResource", "", "", "Argument[0]", "get-resource", "manual"]
+ # - ["javax.servlet", "ServletContext", True, "getResourceAsStream", "", "", "Argument[0]", "get-resource", "manual"]
+ # - ["javax.servlet", "ServletContext", True, "getResourcePaths", "", "", "Argument[0]", "get-resource", "manual"]
+ # - ["javax.servlet", "ServletContext", True, "getResource", "", "", "Argument[this]", "get-resource", "manual"]
+ # - ["javax.servlet", "ServletContext", True, "getResourceAsStream", "", "", "Argument[this]", "get-resource", "manual"]
+ # - ["javax.servlet", "ServletContext", True, "getResourcePaths", "", "", "Argument[this]", "get-resource", "manual"]
+ # # - ["org.apache.tomcat.util.http", "RequestUtil", True, "normalize", "", "", "Argument[0]", "get-resource", "manual"]
+
+ - addsTo:
+ pack: codeql/java-all
+ extensible: summaryModel
+ data:
+ - ["io.undertow.server.handlers.resource", "Resource", True, "getFile", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
+ - ["io.undertow.server.handlers.resource", "Resource", True, "getFilePath", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
+ - ["io.undertow.server.handlers.resource", "Resource", True, "getPath", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] # ! this as a taint step seems to contradict the fact that they did `ClassPathResource.getPath` as a sink for Spring...
+ - ["java.nio.file", "Path", True, "normalize", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] # ! shouldn't this be a sanitizer instead??? Or no because WEB-INF ones don't care about normalization?
+ - ["java.nio.file", "Path", True, "resolve", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] # ! check if this and the below are already in the default models
+ - ["java.nio.file", "Path", True, "resolve", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
+ - ["java.nio.file", "Path", True, "toString", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
+ - ["java.nio.file", "Paths", True, "get", "", "", "Argument[0..1]", "ReturnValue", "taint", "manual"]
+
+ - ["org.springframework.core.io", "ClassPathResource", False, "ClassPathResource", "", "", "Argument[0]", "Argument[this]", "taint", "manual"]
+ - ["org.springframework.core.io", "Resource", True, "createRelative", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
+ # # ! below added/modified by me when debugging CVEs:
+ - ["org.springframework.core.io", "ResourceLoader", True, "getResource", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
+ # - ["org.springframework.cloud.config.server.resource", "ResourceRepository", True, "findOne", "", "", "Argument[0..3]", "ReturnValue", "taint", "manual"] # * public interface, but might be too specific, no easily findable docs...
+ # - ["org.springframework.core.io", "InputStreamSource", True, "getInputStream", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] # * public interface with good docs, Note: other `getInputStream`s are remote source and/or taint step, so this as taint step versus sink probably is more consistent
+ # - ["org.springframework.cloud.config.server.environment", "SearchPathLocator", True, "getLocations", "(String,String,String)", "", "Argument[0..2]", "ReturnValue", "taint", "manual"] # * public interface with docs: https://www.javadoc.io/static/org.springframework.cloud/spring-cloud-config-server/2.1.0.RELEASE/org/springframework/cloud/config/server/environment/SearchPathLocator.html
+ # - ["org.springframework.cloud.config.server.environment", "SearchPathLocator$Locations", True, "getLocations", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] # ! is the `Locations` class package-private? Or does it inherit public from it's enclosing interface?
+ # - ["org.springframework.cloud.config.server.resource", "ResourceController", True, "getFilePath", "", "", "Argument[0..3]", "ReturnValue", "taint", "manual"] # don't need
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeLoadSpringResource.java b/java/ql/src/Security/CWE/CWE-552/UnsafeLoadSpringResource.java
new file mode 100644
index 00000000000..ce462fe490e
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-552/UnsafeLoadSpringResource.java
@@ -0,0 +1,21 @@
+//BAD: no path validation in Spring resource loading
+@GetMapping("/file")
+public String getFileContent(@RequestParam(name="fileName") String fileName) {
+ ClassPathResource clr = new ClassPathResource(fileName);
+
+ File file = ResourceUtils.getFile(fileName);
+
+ Resource resource = resourceLoader.getResource(fileName);
+}
+
+//GOOD: check for a trusted prefix, ensuring path traversal is not used to erase that prefix in Spring resource loading:
+@GetMapping("/file")
+public String getFileContent(@RequestParam(name="fileName") String fileName) {
+ if (!fileName.contains("..") && fileName.hasPrefix("/public-content")) {
+ ClassPathResource clr = new ClassPathResource(fileName);
+
+ File file = ResourceUtils.getFile(fileName);
+
+ Resource resource = resourceLoader.getResource(fileName);
+ }
+}
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeResourceGet.java b/java/ql/src/Security/CWE/CWE-552/UnsafeResourceGet.java
new file mode 100644
index 00000000000..8b3583bf59e
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-552/UnsafeResourceGet.java
@@ -0,0 +1,18 @@
+// BAD: no URI validation
+URL url = request.getServletContext().getResource(requestUrl);
+url = getClass().getResource(requestUrl);
+InputStream in = url.openStream();
+
+InputStream in = request.getServletContext().getResourceAsStream(requestPath);
+in = getClass().getClassLoader().getResourceAsStream(requestPath);
+
+// GOOD: check for a trusted prefix, ensuring path traversal is not used to erase that prefix:
+// (alternatively use `Path.normalize` instead of checking for `..`)
+if (!requestPath.contains("..") && requestPath.startsWith("/trusted")) {
+ InputStream in = request.getServletContext().getResourceAsStream(requestPath);
+}
+
+Path path = Paths.get(requestUrl).normalize().toRealPath();
+if (path.startsWith("/trusted")) {
+ URL url = request.getServletContext().getResource(path.toString());
+}
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeServletRequestDispatch.java b/java/ql/src/Security/CWE/CWE-552/UnsafeServletRequestDispatch.java
new file mode 100644
index 00000000000..a2bbf3dfcd8
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-552/UnsafeServletRequestDispatch.java
@@ -0,0 +1,11 @@
+// BAD: no URI validation
+String returnURL = request.getParameter("returnURL");
+RequestDispatcher rd = sc.getRequestDispatcher(returnURL);
+rd.forward(request, response);
+
+// GOOD: check for a trusted prefix, ensuring path traversal is not used to erase that prefix:
+// (alternatively use `Path.normalize` instead of checking for `..`)
+if (!returnURL.contains("..") && returnURL.hasPrefix("/pages")) { ... }
+// Also GOOD: check for a forbidden prefix, ensuring URL-encoding is not used to evade the check:
+// (alternatively use `URLDecoder.decode` before `hasPrefix`)
+if (returnURL.hasPrefix("/internal") && !returnURL.contains("%")) { ... }
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.java b/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.java
new file mode 100644
index 00000000000..d159c405736
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.java
@@ -0,0 +1,38 @@
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+@Controller
+public class UnsafeUrlForward {
+
+ @GetMapping("/bad1")
+ public ModelAndView bad1(String url) {
+ return new ModelAndView(url);
+ }
+
+ @GetMapping("/bad2")
+ public void bad2(String url, HttpServletRequest request, HttpServletResponse response) {
+ try {
+ request.getRequestDispatcher("/WEB-INF/jsp/" + url + ".jsp").include(request, response);
+ } catch (ServletException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @GetMapping("/good1")
+ public void good1(String url, HttpServletRequest request, HttpServletResponse response) {
+ try {
+ request.getRequestDispatcher("/index.jsp?token=" + url).forward(request, response);
+ } catch (ServletException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qhelp b/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qhelp
new file mode 100644
index 00000000000..2e425952edc
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qhelp
@@ -0,0 +1,70 @@
+
+
+
+
+
+
Constructing a server-side redirect path with user input could allow an attacker to download application binaries
+(including application classes or jar files) or view arbitrary files within protected directories.
+
+
+
+
+
Unsanitized user provided data must not be used to construct the path for URL forwarding. In order to prevent
+untrusted URL forwarding, it is recommended to avoid concatenating user input directly into the forwarding URL.
+Instead, user input should be checked against allowed (e.g., must come within user_content/) or disallowed
+(e.g. must not come within /internal) paths, ensuring that neither path traversal using ../
+or URL encoding are used to evade these checks.
+
+
+
+
+
+
The following examples show the bad case and the good case respectively.
+The bad methods show an HTTP request parameter being used directly in a URL forward
+without validating the input, which may cause file leakage. In the good1 method,
+ordinary forwarding requests are shown, which will not cause file leakage.
+
+
+
+
+
The following examples show an HTTP request parameter or request path being used directly in a
+request dispatcher of Java EE without validating the input, which allows sensitive file exposure
+attacks. It also shows how to remedy the problem by validating the user input.
+
+
+
+
+
The following examples show an HTTP request parameter or request path being used directly to
+retrieve a resource of a Java EE application without validating the input, which allows sensitive
+file exposure attacks. It also shows how to remedy the problem by validating the user input.
+
+
+
+
+
The following examples show an HTTP request parameter being used directly to retrieve a resource
+ of a Java Spring application without validating the input, which allows sensitive file exposure
+ attacks. It also shows how to remedy the problem by validating the user input.
+
+
+
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql b/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql
new file mode 100644
index 00000000000..240023f9ffc
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql
@@ -0,0 +1,63 @@
+/**
+ * @name Unsafe URL forward or include from a remote source
+ * @description URL forward or include based on unvalidated user-input
+ * may cause file information disclosure.
+ * @kind path-problem
+ * @problem.severity error
+ * @precision high
+ * @id java/unsafe-url-forward-include
+ * @tags security
+ * external/cwe-552
+ */
+
+import java
+import UnsafeUrlForward
+import semmle.code.java.dataflow.FlowSources
+import semmle.code.java.dataflow.TaintTracking
+import experimental.semmle.code.java.frameworks.Jsf
+import semmle.code.java.security.PathSanitizer
+import UnsafeUrlForwardFlow::PathGraph
+
+module UnsafeUrlForwardFlowConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) {
+ source instanceof ThreatModelFlowSource and
+ not exists(MethodCall ma, Method m | ma.getMethod() = m |
+ (
+ m instanceof HttpServletRequestGetRequestUriMethod or
+ m instanceof HttpServletRequestGetRequestUrlMethod or
+ m instanceof HttpServletRequestGetPathMethod
+ ) and
+ ma = source.asExpr()
+ )
+ }
+
+ predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeUrlForwardSink }
+
+ predicate isBarrier(DataFlow::Node node) {
+ node instanceof UnsafeUrlForwardSanitizer or
+ node instanceof PathInjectionSanitizer
+ }
+
+ DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
+
+ predicate isAdditionalFlowStep(DataFlow::Node prev, DataFlow::Node succ) {
+ exists(MethodCall ma |
+ (
+ ma.getMethod() instanceof GetServletResourceMethod or
+ ma.getMethod() instanceof GetFacesResourceMethod or
+ ma.getMethod() instanceof GetClassResourceMethod or
+ ma.getMethod() instanceof GetClassLoaderResourceMethod or
+ ma.getMethod() instanceof GetWildflyResourceMethod
+ ) and
+ ma.getArgument(0) = prev.asExpr() and
+ ma = succ.asExpr()
+ )
+ }
+}
+
+module UnsafeUrlForwardFlow = TaintTracking::Global;
+
+from UnsafeUrlForwardFlow::PathNode source, UnsafeUrlForwardFlow::PathNode sink
+where UnsafeUrlForwardFlow::flowPath(source, sink)
+select sink.getNode(), source, sink, "Potentially untrusted URL forward due to $@.",
+ source.getNode(), "user-provided value"
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qll b/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qll
new file mode 100644
index 00000000000..db610eb65ce
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qll
@@ -0,0 +1,163 @@
+import java
+private import experimental.semmle.code.java.frameworks.Jsf
+private import semmle.code.java.dataflow.ExternalFlow
+private import semmle.code.java.dataflow.FlowSources
+private import semmle.code.java.dataflow.StringPrefixes
+private import semmle.code.java.frameworks.javaee.ejb.EJBRestrictions
+private import experimental.semmle.code.java.frameworks.SpringResource
+
+/** A sink for unsafe URL forward vulnerabilities. */
+abstract class UnsafeUrlForwardSink extends DataFlow::Node { }
+
+/** A sanitizer for unsafe URL forward vulnerabilities. */
+abstract class UnsafeUrlForwardSanitizer extends DataFlow::Node { }
+
+/** An argument to `getRequestDispatcher`. */
+private class RequestDispatcherSink extends UnsafeUrlForwardSink {
+ RequestDispatcherSink() {
+ exists(MethodCall ma |
+ ma.getMethod() instanceof GetRequestDispatcherMethod and
+ ma.getArgument(0) = this.asExpr()
+ )
+ }
+}
+
+/** The `getResource` method of `Class`. */
+class GetClassResourceMethod extends Method {
+ GetClassResourceMethod() {
+ this.getDeclaringType() instanceof TypeClass and
+ this.hasName("getResource")
+ }
+}
+
+/** The `getResourceAsStream` method of `Class`. */
+class GetClassResourceAsStreamMethod extends Method {
+ GetClassResourceAsStreamMethod() {
+ this.getDeclaringType() instanceof TypeClass and
+ this.hasName("getResourceAsStream")
+ }
+}
+
+/** The `getResource` method of `ClassLoader`. */
+class GetClassLoaderResourceMethod extends Method {
+ GetClassLoaderResourceMethod() {
+ this.getDeclaringType() instanceof ClassLoaderClass and
+ this.hasName("getResource")
+ }
+}
+
+/** The `getResourceAsStream` method of `ClassLoader`. */
+class GetClassLoaderResourceAsStreamMethod extends Method {
+ GetClassLoaderResourceAsStreamMethod() {
+ this.getDeclaringType() instanceof ClassLoaderClass and
+ this.hasName("getResourceAsStream")
+ }
+}
+
+/** The JBoss class `FileResourceManager`. */
+class FileResourceManager extends RefType {
+ FileResourceManager() {
+ this.hasQualifiedName("io.undertow.server.handlers.resource", "FileResourceManager")
+ }
+}
+
+/** The JBoss method `getResource` of `FileResourceManager`. */
+class GetWildflyResourceMethod extends Method {
+ GetWildflyResourceMethod() {
+ this.getDeclaringType().getASupertype*() instanceof FileResourceManager and
+ this.hasName("getResource")
+ }
+}
+
+/** The JBoss class `VirtualFile`. */
+class VirtualFile extends RefType {
+ VirtualFile() { this.hasQualifiedName("org.jboss.vfs", "VirtualFile") }
+}
+
+/** The JBoss method `getChild` of `FileResourceManager`. */
+class GetVirtualFileChildMethod extends Method {
+ GetVirtualFileChildMethod() {
+ this.getDeclaringType().getASupertype*() instanceof VirtualFile and
+ this.hasName("getChild")
+ }
+}
+
+/** An argument to `getResource()` or `getResourceAsStream()`. */
+private class GetResourceSink extends UnsafeUrlForwardSink {
+ GetResourceSink() {
+ sinkNode(this, "request-forgery")
+ or
+ sinkNode(this, "get-resource")
+ or
+ exists(MethodCall ma |
+ (
+ ma.getMethod() instanceof GetServletResourceAsStreamMethod or
+ ma.getMethod() instanceof GetFacesResourceAsStreamMethod or
+ ma.getMethod() instanceof GetClassResourceAsStreamMethod or
+ ma.getMethod() instanceof GetClassLoaderResourceAsStreamMethod or
+ ma.getMethod() instanceof GetVirtualFileChildMethod
+ ) and
+ ma.getArgument(0) = this.asExpr()
+ )
+ }
+}
+
+/** A sink for methods that load Spring resources. */
+private class SpringResourceSink extends UnsafeUrlForwardSink {
+ SpringResourceSink() {
+ exists(MethodCall ma |
+ ma.getMethod() instanceof GetResourceUtilsMethod and
+ ma.getArgument(0) = this.asExpr()
+ )
+ }
+}
+
+/** An argument to `new ModelAndView` or `ModelAndView.setViewName`. */
+private class SpringModelAndViewSink extends UnsafeUrlForwardSink {
+ SpringModelAndViewSink() {
+ exists(ClassInstanceExpr cie |
+ cie.getConstructedType() instanceof ModelAndView and
+ cie.getArgument(0) = this.asExpr()
+ )
+ or
+ exists(SpringModelAndViewSetViewNameCall smavsvnc | smavsvnc.getArgument(0) = this.asExpr())
+ }
+}
+
+private class PrimitiveSanitizer extends UnsafeUrlForwardSanitizer {
+ PrimitiveSanitizer() {
+ this.getType() instanceof PrimitiveType or
+ this.getType() instanceof BoxedType or
+ this.getType() instanceof NumberType
+ }
+}
+
+private class SanitizingPrefix extends InterestingPrefix {
+ SanitizingPrefix() {
+ not this.getStringValue().matches("/WEB-INF/%") and
+ not this.getStringValue() = "forward:"
+ }
+
+ override int getOffset() { result = 0 }
+}
+
+private class FollowsSanitizingPrefix extends UnsafeUrlForwardSanitizer {
+ FollowsSanitizingPrefix() { this.asExpr() = any(SanitizingPrefix fp).getAnAppendedExpression() }
+}
+
+private class ForwardPrefix extends InterestingPrefix {
+ ForwardPrefix() { this.getStringValue() = "forward:" }
+
+ override int getOffset() { result = 0 }
+}
+
+/**
+ * An expression appended (perhaps indirectly) to `"forward:"`, and which
+ * is reachable from a Spring entry point.
+ */
+private class SpringUrlForwardSink extends UnsafeUrlForwardSink {
+ SpringUrlForwardSink() {
+ any(SpringRequestMappingMethod sqmm).polyCalls*(this.getEnclosingCallable()) and
+ this.asExpr() = any(ForwardPrefix fp).getAnAppendedExpression()
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeLoadSpringResource.java b/java/ql/test/query-tests/security/CWE-552/UnsafeLoadSpringResource.java
new file mode 100644
index 00000000000..c7e114aede3
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeLoadSpringResource.java
@@ -0,0 +1,155 @@
+package com.example;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.nio.file.Files;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.util.ResourceUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/** Sample class of Spring RestController */
+@RestController
+public class UnsafeLoadSpringResource {
+ @GetMapping("/file1")
+ //BAD: Get resource from ClassPathResource without input validation
+ public String getFileContent1(@RequestParam(name="fileName") String fileName) {
+ // A request such as the following can disclose source code and application configuration
+ // fileName=/../../WEB-INF/views/page.jsp
+ // fileName=/com/example/package/SampleController.class
+ ClassPathResource clr = new ClassPathResource(fileName);
+ char[] buffer = new char[4096];
+ StringBuilder out = new StringBuilder();
+ try {
+ Reader in = new FileReader(clr.getFilename());
+ for (int numRead; (numRead = in.read(buffer, 0, buffer.length)) > 0; ) {
+ out.append(buffer, 0, numRead);
+ }
+ } catch (IOException ie) {
+ ie.printStackTrace();
+ }
+ return out.toString();
+ }
+
+ @GetMapping("/file1a")
+ //GOOD: Get resource from ClassPathResource with input path validation
+ public String getFileContent1a(@RequestParam(name="fileName") String fileName) {
+ String result = null;
+ if (fileName.startsWith("/safe_dir") && !fileName.contains("..")) {
+ ClassPathResource clr = new ClassPathResource(fileName);
+ char[] buffer = new char[4096];
+ StringBuilder out = new StringBuilder();
+ try {
+ Reader in = new InputStreamReader(clr.getInputStream(), "UTF-8");
+ for (int numRead; (numRead = in.read(buffer, 0, buffer.length)) > 0; ) {
+ out.append(buffer, 0, numRead);
+ }
+ } catch (IOException ie) {
+ ie.printStackTrace();
+ }
+ result = out.toString();
+ }
+ return result;
+ }
+
+ @GetMapping("/file2")
+ //BAD: Get resource from ResourceUtils without input validation
+ public String getFileContent2(@RequestParam(name="fileName") String fileName) {
+ String content = null;
+
+ try {
+ // A request such as the following can disclose source code and system configuration
+ // fileName=/etc/hosts
+ // fileName=file:/etc/hosts
+ // fileName=/opt/appdir/WEB-INF/views/page.jsp
+ File file = ResourceUtils.getFile(fileName);
+ //Read File Content
+ content = new String(Files.readAllBytes(file.toPath()));
+ } catch (IOException ie) {
+ ie.printStackTrace();
+ }
+ return content;
+ }
+
+ @GetMapping("/file2a")
+ //GOOD: Get resource from ResourceUtils with input path validation
+ public String getFileContent2a(@RequestParam(name="fileName") String fileName) {
+ String content = null;
+
+ if (fileName.startsWith("/safe_dir") && !fileName.contains("..")) {
+ try {
+ File file = ResourceUtils.getFile(fileName);
+ //Read File Content
+ content = new String(Files.readAllBytes(file.toPath()));
+ } catch (IOException ie) {
+ ie.printStackTrace();
+ }
+ }
+ return content;
+ }
+
+ @Autowired
+ ResourceLoader resourceLoader;
+
+ @GetMapping("/file3")
+ //BAD: Get resource from ResourceLoader (same as application context) without input validation
+ // Note it is not detected without the generic `resource.getInputStream()` check
+ public String getFileContent3(@RequestParam(name="fileName") String fileName) {
+ String content = null;
+
+ try {
+ // A request such as the following can disclose source code and system configuration
+ // fileName=/WEB-INF/views/page.jsp
+ // fileName=/WEB-INF/classes/com/example/package/SampleController.class
+ // fileName=file:/etc/hosts
+ Resource resource = resourceLoader.getResource(fileName);
+
+ char[] buffer = new char[4096];
+ StringBuilder out = new StringBuilder();
+
+ Reader in = new InputStreamReader(resource.getInputStream(), "UTF-8");
+ for (int numRead; (numRead = in.read(buffer, 0, buffer.length)) > 0; ) {
+ out.append(buffer, 0, numRead);
+ }
+ content = out.toString();
+ } catch (IOException ie) {
+ ie.printStackTrace();
+ }
+ return content;
+ }
+
+ @GetMapping("/file3a")
+ //GOOD: Get resource from ResourceLoader (same as application context) with input path validation
+ public String getFileContent3a(@RequestParam(name="fileName") String fileName) {
+ String content = null;
+
+ if (fileName.startsWith("/safe_dir") && !fileName.contains("..")) {
+ try {
+ Resource resource = resourceLoader.getResource(fileName);
+
+ char[] buffer = new char[4096];
+ StringBuilder out = new StringBuilder();
+
+ Reader in = new InputStreamReader(resource.getInputStream(), "UTF-8");
+ for (int numRead; (numRead = in.read(buffer, 0, buffer.length)) > 0; ) {
+ out.append(buffer, 0, numRead);
+ }
+ content = out.toString();
+ } catch (IOException ie) {
+ ie.printStackTrace();
+ }
+ }
+ return content;
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java b/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java
new file mode 100644
index 00000000000..2de0cae0d3c
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java
@@ -0,0 +1,52 @@
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+// @WebFilter("/*")
+public class UnsafeRequestPath implements Filter {
+ private static final String BASE_PATH = "/pages";
+
+ @Override
+ // BAD: Request dispatcher from servlet path without check
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ String path = ((HttpServletRequest) request).getServletPath();
+ // A sample payload "/%57EB-INF/web.xml" can bypass this `startsWith` check
+ if (path != null && !path.startsWith("/WEB-INF")) {
+ request.getRequestDispatcher(path).forward(request, response);
+ } else {
+ chain.doFilter(request, response);
+ }
+ }
+
+ // GOOD: Request dispatcher from servlet path with check
+ public void doFilter2(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ String path = ((HttpServletRequest) request).getServletPath();
+
+ if (path.startsWith(BASE_PATH) && !path.contains("..")) {
+ request.getRequestDispatcher(path).forward(request, response);
+ } else {
+ chain.doFilter(request, response);
+ }
+ }
+
+ // GOOD: Request dispatcher from servlet path with whitelisted string comparison
+ public void doFilter3(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ String path = ((HttpServletRequest) request).getServletPath();
+
+ if (path.equals("/comaction")) {
+ request.getRequestDispatcher(path).forward(request, response);
+ } else {
+ chain.doFilter(request, response);
+ }
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet.java b/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet.java
new file mode 100644
index 00000000000..64c23334f18
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet.java
@@ -0,0 +1,270 @@
+package com.example;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.net.URI;
+import java.net.URL;
+import java.net.URISyntaxException;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletException;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+
+import io.undertow.server.handlers.resource.FileResourceManager;
+import io.undertow.server.handlers.resource.Resource;
+import org.jboss.vfs.VFS;
+import org.jboss.vfs.VirtualFile;
+
+public class UnsafeResourceGet extends HttpServlet {
+ private static final String BASE_PATH = "/pages";
+
+ @Override
+ // BAD: getResource constructed from `ServletContext` without input validation
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String requestUrl = request.getParameter("requestURL");
+ ServletOutputStream out = response.getOutputStream();
+
+ ServletConfig cfg = getServletConfig();
+ ServletContext sc = cfg.getServletContext();
+
+ // A sample request /fake.jsp/../WEB-INF/web.xml can load the web.xml file
+ URL url = sc.getResource(requestUrl);
+
+ InputStream in = url.openStream();
+ byte[] buf = new byte[4 * 1024]; // 4K buffer
+ int bytesRead;
+ while ((bytesRead = in.read(buf)) != -1) {
+ out.write(buf, 0, bytesRead);
+ }
+ }
+
+ // GOOD: getResource constructed from `ServletContext` with input validation
+ protected void doGetGood(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String requestUrl = request.getParameter("requestURL");
+ ServletOutputStream out = response.getOutputStream();
+
+ ServletConfig cfg = getServletConfig();
+ ServletContext sc = cfg.getServletContext();
+
+ Path path = Paths.get(requestUrl).normalize().toRealPath();
+ if (path.startsWith(BASE_PATH)) {
+ URL url = sc.getResource(path.toString());
+
+ InputStream in = url.openStream();
+ byte[] buf = new byte[4 * 1024]; // 4K buffer
+ int bytesRead;
+ while ((bytesRead = in.read(buf)) != -1) {
+ out.write(buf, 0, bytesRead);
+ }
+ }
+ }
+
+ // GOOD: getResource constructed from `ServletContext` with null check only
+ protected void doGetGood2(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String requestUrl = request.getParameter("requestURL");
+ PrintWriter writer = response.getWriter();
+
+ ServletConfig cfg = getServletConfig();
+ ServletContext sc = cfg.getServletContext();
+
+ // A sample request /fake.jsp/../WEB-INF/web.xml can load the web.xml file
+ URL url = sc.getResource(requestUrl);
+ if (url == null) {
+ writer.println("Requested source not found");
+ }
+ }
+
+ // GOOD: getResource constructed from `ServletContext` with `equals` check
+ protected void doGetGood3(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String requestUrl = request.getParameter("requestURL");
+ ServletOutputStream out = response.getOutputStream();
+
+ ServletContext sc = request.getServletContext();
+
+ if (requestUrl.equals("/public/crossdomain.xml")) {
+ URL url = sc.getResource(requestUrl);
+
+ InputStream in = url.openStream();
+ byte[] buf = new byte[4 * 1024]; // 4K buffer
+ int bytesRead;
+ while ((bytesRead = in.read(buf)) != -1) {
+ out.write(buf, 0, bytesRead);
+ }
+ }
+ }
+
+ @Override
+ // BAD: getResourceAsStream constructed from `ServletContext` without input validation
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String requestPath = request.getParameter("requestPath");
+ ServletOutputStream out = response.getOutputStream();
+
+ // A sample request /fake.jsp/../WEB-INF/web.xml can load the web.xml file
+ InputStream in = request.getServletContext().getResourceAsStream(requestPath);
+ byte[] buf = new byte[4 * 1024]; // 4K buffer
+ int bytesRead;
+ while ((bytesRead = in.read(buf)) != -1) {
+ out.write(buf, 0, bytesRead);
+ }
+ }
+
+ // GOOD: getResourceAsStream constructed from `ServletContext` with input validation
+ protected void doPostGood(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String requestPath = request.getParameter("requestPath");
+ ServletOutputStream out = response.getOutputStream();
+
+ if (!requestPath.contains("..") && requestPath.startsWith("/trusted")) {
+ InputStream in = request.getServletContext().getResourceAsStream(requestPath);
+ byte[] buf = new byte[4 * 1024]; // 4K buffer
+ int bytesRead;
+ while ((bytesRead = in.read(buf)) != -1) {
+ out.write(buf, 0, bytesRead);
+ }
+ }
+ }
+
+ @Override
+ // BAD: getResource constructed from `Class` without input validation
+ protected void doHead(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String requestUrl = request.getParameter("requestURL");
+ ServletOutputStream out = response.getOutputStream();
+
+ // A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file
+ // Note the class is in two levels of subpackages and `Class.getResource` starts from its own directory
+ URL url = getClass().getResource(requestUrl);
+
+ InputStream in = url.openStream();
+ byte[] buf = new byte[4 * 1024]; // 4K buffer
+ int bytesRead;
+ while ((bytesRead = in.read(buf)) != -1) {
+ out.write(buf, 0, bytesRead);
+ }
+ }
+
+ // GOOD: getResource constructed from `Class` with input validation
+ protected void doHeadGood(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String requestUrl = request.getParameter("requestURL");
+ ServletOutputStream out = response.getOutputStream();
+
+ Path path = Paths.get(requestUrl).normalize().toRealPath();
+ if (path.startsWith(BASE_PATH)) {
+ URL url = getClass().getResource(path.toString());
+
+ InputStream in = url.openStream();
+ byte[] buf = new byte[4 * 1024]; // 4K buffer
+ int bytesRead;
+ while ((bytesRead = in.read(buf)) != -1) {
+ out.write(buf, 0, bytesRead);
+ }
+ }
+ }
+
+ @Override
+ // BAD: getResourceAsStream constructed from `ClassLoader` without input validation
+ protected void doPut(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String requestPath = request.getParameter("requestPath");
+ ServletOutputStream out = response.getOutputStream();
+
+ ServletConfig cfg = getServletConfig();
+ ServletContext sc = cfg.getServletContext();
+
+ // A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file
+ // Note the class is in two levels of subpackages and `ClassLoader.getResourceAsStream` starts from its own directory
+ InputStream in = getClass().getClassLoader().getResourceAsStream(requestPath);
+ byte[] buf = new byte[4 * 1024]; // 4K buffer
+ int bytesRead;
+ while ((bytesRead = in.read(buf)) != -1) {
+ out.write(buf, 0, bytesRead);
+ }
+ }
+
+ // GOOD: getResourceAsStream constructed from `ClassLoader` with input validation
+ protected void doPutGood(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String requestPath = request.getParameter("requestPath");
+ ServletOutputStream out = response.getOutputStream();
+
+ ServletConfig cfg = getServletConfig();
+ ServletContext sc = cfg.getServletContext();
+
+ if (!requestPath.contains("..") && requestPath.startsWith("/trusted")) {
+ InputStream in = getClass().getClassLoader().getResourceAsStream(requestPath);
+ byte[] buf = new byte[4 * 1024]; // 4K buffer
+ int bytesRead;
+ while ((bytesRead = in.read(buf)) != -1) {
+ out.write(buf, 0, bytesRead);
+ }
+ }
+ }
+
+ // BAD: getResource constructed from `ClassLoader` without input validation
+ protected void doPutBad(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String requestUrl = request.getParameter("requestURL");
+ ServletOutputStream out = response.getOutputStream();
+
+ // A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file
+ // Note the class is in two levels of subpackages and `ClassLoader.getResource` starts from its own directory
+ URL url = getClass().getClassLoader().getResource(requestUrl);
+
+ InputStream in = url.openStream();
+ byte[] buf = new byte[4 * 1024]; // 4K buffer
+ int bytesRead;
+ while ((bytesRead = in.read(buf)) != -1) {
+ out.write(buf, 0, bytesRead);
+ }
+ }
+
+ // BAD: getResource constructed using Undertow IO without input validation
+ protected void doPutBad2(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String requestPath = request.getParameter("requestPath");
+
+ try {
+ FileResourceManager rm = new FileResourceManager(VFS.getChild(new URI("/usr/share")).getPhysicalFile());
+ Resource rs = rm.getResource(requestPath);
+
+ VirtualFile overlay = VFS.getChild(new URI("EAP_HOME/modules/"));
+ // Do file operations
+ overlay.getChild(rs.getPath());
+ } catch (URISyntaxException ue) {
+ throw new IOException("Cannot parse the URI");
+ }
+ }
+
+ // GOOD: getResource constructed using Undertow IO with input validation
+ protected void doPutGood2(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String requestPath = request.getParameter("requestPath");
+
+ try {
+ FileResourceManager rm = new FileResourceManager(VFS.getChild(new URI("/usr/share")).getPhysicalFile());
+ Resource rs = rm.getResource(requestPath);
+
+ VirtualFile overlay = VFS.getChild(new URI("EAP_HOME/modules/"));
+ String path = rs.getPath();
+ if (path.startsWith("/trusted_path") && !path.contains("..")) {
+ // Do file operations
+ overlay.getChild(path);
+ }
+ } catch (URISyntaxException ue) {
+ throw new IOException("Cannot parse the URI");
+ }
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet2.java b/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet2.java
new file mode 100644
index 00000000000..b3d041d024c
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet2.java
@@ -0,0 +1,58 @@
+package com.example;
+
+import javax.faces.context.FacesContext;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Map;
+
+/** Sample class of JSF managed bean */
+public class UnsafeResourceGet2 {
+ // BAD: getResourceAsStream constructed from `ExternalContext` without input validation
+ public String parameterActionBad1() throws IOException {
+ FacesContext fc = FacesContext.getCurrentInstance();
+ Map params = fc.getExternalContext().getRequestParameterMap();
+ String loadUrl = params.get("loadUrl");
+
+ InputStreamReader isr = new InputStreamReader(fc.getExternalContext().getResourceAsStream(loadUrl));
+ BufferedReader br = new BufferedReader(isr);
+ if(br.ready()) {
+ //Do Stuff
+ return "result";
+ }
+
+ return "home";
+ }
+
+ // BAD: getResource constructed from `ExternalContext` without input validation
+ public String parameterActionBad2() throws IOException {
+ FacesContext fc = FacesContext.getCurrentInstance();
+ Map params = fc.getExternalContext().getRequestParameterMap();
+ String loadUrl = params.get("loadUrl");
+
+ URL url = fc.getExternalContext().getResource(loadUrl);
+
+ InputStream in = url.openStream();
+ //Do Stuff
+ return "result";
+ }
+
+ // GOOD: getResource constructed from `ExternalContext` with input validation
+ public String parameterActionGood1() throws IOException {
+ FacesContext fc = FacesContext.getCurrentInstance();
+ Map params = fc.getExternalContext().getRequestParameterMap();
+ String loadUrl = params.get("loadUrl");
+
+ if (loadUrl.equals("/public/crossdomain.xml")) {
+ URL url = fc.getExternalContext().getResource(loadUrl);
+
+ InputStream in = url.openStream();
+ //Do Stuff
+ return "result";
+ }
+
+ return "home";
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java b/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java
new file mode 100644
index 00000000000..ee63939b209
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java
@@ -0,0 +1,131 @@
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+
+public class UnsafeServletRequestDispatch extends HttpServlet {
+ private static final String BASE_PATH = "/pages";
+
+ @Override
+ // BAD: Request dispatcher constructed from `ServletContext` without input validation
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String action = request.getParameter("action");
+ String returnURL = request.getParameter("returnURL");
+
+ ServletConfig cfg = getServletConfig();
+ if (action.equals("Login")) {
+ ServletContext sc = cfg.getServletContext();
+ RequestDispatcher rd = sc.getRequestDispatcher("/Login.jsp");
+ rd.forward(request, response);
+ } else {
+ ServletContext sc = cfg.getServletContext();
+ RequestDispatcher rd = sc.getRequestDispatcher(returnURL);
+ rd.forward(request, response);
+ }
+ }
+
+ @Override
+ // BAD: Request dispatcher constructed from `HttpServletRequest` without input validation
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String action = request.getParameter("action");
+ String returnURL = request.getParameter("returnURL");
+
+ if (action.equals("Login")) {
+ RequestDispatcher rd = request.getRequestDispatcher("/Login.jsp");
+ rd.forward(request, response);
+ } else {
+ RequestDispatcher rd = request.getRequestDispatcher(returnURL);
+ rd.forward(request, response);
+ }
+ }
+
+ @Override
+ // GOOD: Request dispatcher with a whitelisted URI
+ protected void doPut(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String action = request.getParameter("action");
+
+ if (action.equals("Login")) {
+ RequestDispatcher rd = request.getRequestDispatcher("/Login.jsp");
+ rd.forward(request, response);
+ } else if (action.equals("Register")) {
+ RequestDispatcher rd = request.getRequestDispatcher("/Register.jsp");
+ rd.forward(request, response);
+ }
+ }
+
+ // BAD: Request dispatcher without path traversal check
+ protected void doHead2(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path");
+
+ // A sample payload "/pages/welcome.jsp/../WEB-INF/web.xml" can bypass the `startsWith` check
+ // The payload "/pages/welcome.jsp/../../%57EB-INF/web.xml" can bypass the check as well since RequestDispatcher will decode `%57` as `W`
+ if (path.startsWith(BASE_PATH)) {
+ request.getServletContext().getRequestDispatcher(path).include(request, response);
+ }
+ }
+
+ // GOOD: Request dispatcher with path traversal check
+ protected void doHead3(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path");
+
+ if (path.startsWith(BASE_PATH) && !path.contains("..")) {
+ request.getServletContext().getRequestDispatcher(path).include(request, response);
+ }
+ }
+
+ // GOOD: Request dispatcher with path normalization and comparison
+ protected void doHead4(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path");
+ Path requestedPath = Paths.get(BASE_PATH).resolve(path).normalize();
+
+ // /pages/welcome.jsp/../../WEB-INF/web.xml becomes /WEB-INF/web.xml
+ // /pages/welcome.jsp/../../%57EB-INF/web.xml becomes /%57EB-INF/web.xml
+ if (requestedPath.startsWith(BASE_PATH)) {
+ request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response);
+ }
+ }
+
+ // FN: Request dispatcher with negation check and path normalization, but without URL decoding
+ // When promoting this query, consider using FlowStates to make `getRequestDispatcher` a sink
+ // only if a URL-decoding step has NOT been crossed (i.e. make URLDecoder.decode change the
+ // state to a different value than the one required at the sink).
+ protected void doHead5(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path");
+ Path requestedPath = Paths.get(BASE_PATH).resolve(path).normalize();
+
+ if (!requestedPath.startsWith("/WEB-INF") && !requestedPath.startsWith("/META-INF")) {
+ request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response);
+ }
+ }
+
+ // GOOD: Request dispatcher with path traversal check and URL decoding
+ protected void doHead6(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path");
+ boolean hasEncoding = path.contains("%");
+ while (hasEncoding) {
+ path = URLDecoder.decode(path, "UTF-8");
+ hasEncoding = path.contains("%");
+ }
+
+ if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
+ request.getServletContext().getRequestDispatcher(path).include(request, response);
+ }
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.expected b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.expected
new file mode 100644
index 00000000000..5d809244fdb
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.expected
@@ -0,0 +1,129 @@
+edges
+| UnsafeLoadSpringResource.java:27:32:27:77 | fileName : String | UnsafeLoadSpringResource.java:31:49:31:56 | fileName : String |
+| UnsafeLoadSpringResource.java:31:27:31:57 | new ClassPathResource(...) : ClassPathResource | UnsafeLoadSpringResource.java:35:31:35:33 | clr |
+| UnsafeLoadSpringResource.java:31:49:31:56 | fileName : String | UnsafeLoadSpringResource.java:31:27:31:57 | new ClassPathResource(...) : ClassPathResource |
+| UnsafeLoadSpringResource.java:68:32:68:77 | fileName : String | UnsafeLoadSpringResource.java:76:38:76:45 | fileName |
+| UnsafeLoadSpringResource.java:108:32:108:77 | fileName : String | UnsafeLoadSpringResource.java:116:51:116:58 | fileName |
+| UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) : String | UnsafeRequestPath.java:23:33:23:36 | path |
+| UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:17:20:17:25 | params : Map |
+| UnsafeResourceGet2.java:17:20:17:25 | params : Map | UnsafeResourceGet2.java:17:20:17:40 | get(...) : String |
+| UnsafeResourceGet2.java:17:20:17:40 | get(...) : String | UnsafeResourceGet2.java:19:93:19:99 | loadUrl |
+| UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:33:20:33:25 | params : Map |
+| UnsafeResourceGet2.java:33:20:33:25 | params : Map | UnsafeResourceGet2.java:33:20:33:40 | get(...) : String |
+| UnsafeResourceGet2.java:33:20:33:40 | get(...) : String | UnsafeResourceGet2.java:35:49:35:55 | loadUrl : String |
+| UnsafeResourceGet2.java:35:13:35:56 | getResource(...) : URL | UnsafeResourceGet2.java:37:20:37:22 | url |
+| UnsafeResourceGet2.java:35:49:35:55 | loadUrl : String | UnsafeResourceGet2.java:35:13:35:56 | getResource(...) : URL |
+| UnsafeResourceGet.java:32:23:32:56 | getParameter(...) : String | UnsafeResourceGet.java:39:28:39:37 | requestUrl : String |
+| UnsafeResourceGet.java:39:13:39:38 | getResource(...) : URL | UnsafeResourceGet.java:41:20:41:22 | url |
+| UnsafeResourceGet.java:39:28:39:37 | requestUrl : String | UnsafeResourceGet.java:39:13:39:38 | getResource(...) : URL |
+| UnsafeResourceGet.java:111:24:111:58 | getParameter(...) : String | UnsafeResourceGet.java:115:68:115:78 | requestPath |
+| UnsafeResourceGet.java:143:23:143:56 | getParameter(...) : String | UnsafeResourceGet.java:148:36:148:45 | requestUrl : String |
+| UnsafeResourceGet.java:148:13:148:46 | getResource(...) : URL | UnsafeResourceGet.java:150:20:150:22 | url |
+| UnsafeResourceGet.java:148:36:148:45 | requestUrl : String | UnsafeResourceGet.java:148:13:148:46 | getResource(...) : URL |
+| UnsafeResourceGet.java:181:24:181:58 | getParameter(...) : String | UnsafeResourceGet.java:189:68:189:78 | requestPath |
+| UnsafeResourceGet.java:219:23:219:56 | getParameter(...) : String | UnsafeResourceGet.java:224:53:224:62 | requestUrl : String |
+| UnsafeResourceGet.java:224:13:224:63 | getResource(...) : URL | UnsafeResourceGet.java:226:20:226:22 | url |
+| UnsafeResourceGet.java:224:53:224:62 | requestUrl : String | UnsafeResourceGet.java:224:13:224:63 | getResource(...) : URL |
+| UnsafeResourceGet.java:237:24:237:58 | getParameter(...) : String | UnsafeResourceGet.java:241:33:241:43 | requestPath : String |
+| UnsafeResourceGet.java:241:18:241:44 | getResource(...) : Resource | UnsafeResourceGet.java:245:21:245:22 | rs : Resource |
+| UnsafeResourceGet.java:241:33:241:43 | requestPath : String | UnsafeResourceGet.java:241:18:241:44 | getResource(...) : Resource |
+| UnsafeResourceGet.java:245:21:245:22 | rs : Resource | UnsafeResourceGet.java:245:21:245:32 | getPath(...) |
+| UnsafeServletRequestDispatch.java:23:22:23:54 | getParameter(...) : String | UnsafeServletRequestDispatch.java:32:51:32:59 | returnURL |
+| UnsafeServletRequestDispatch.java:42:22:42:54 | getParameter(...) : String | UnsafeServletRequestDispatch.java:48:56:48:64 | returnURL |
+| UnsafeServletRequestDispatch.java:71:17:71:44 | getParameter(...) : String | UnsafeServletRequestDispatch.java:76:53:76:56 | path |
+| UnsafeUrlForward.java:13:27:13:36 | url : String | UnsafeUrlForward.java:14:27:14:29 | url |
+| UnsafeUrlForward.java:18:27:18:36 | url : String | UnsafeUrlForward.java:20:28:20:30 | url |
+| UnsafeUrlForward.java:25:21:25:30 | url : String | UnsafeUrlForward.java:26:23:26:25 | url |
+| UnsafeUrlForward.java:30:27:30:36 | url : String | UnsafeUrlForward.java:31:48:31:63 | ... + ... |
+| UnsafeUrlForward.java:30:27:30:36 | url : String | UnsafeUrlForward.java:31:61:31:63 | url |
+| UnsafeUrlForward.java:36:19:36:28 | url : String | UnsafeUrlForward.java:38:33:38:35 | url |
+| UnsafeUrlForward.java:47:19:47:28 | url : String | UnsafeUrlForward.java:49:33:49:62 | ... + ... |
+| UnsafeUrlForward.java:58:19:58:28 | url : String | UnsafeUrlForward.java:60:33:60:62 | ... + ... |
+nodes
+| UnsafeLoadSpringResource.java:27:32:27:77 | fileName : String | semmle.label | fileName : String |
+| UnsafeLoadSpringResource.java:31:27:31:57 | new ClassPathResource(...) : ClassPathResource | semmle.label | new ClassPathResource(...) : ClassPathResource |
+| UnsafeLoadSpringResource.java:31:49:31:56 | fileName : String | semmle.label | fileName : String |
+| UnsafeLoadSpringResource.java:35:31:35:33 | clr | semmle.label | clr |
+| UnsafeLoadSpringResource.java:68:32:68:77 | fileName : String | semmle.label | fileName : String |
+| UnsafeLoadSpringResource.java:76:38:76:45 | fileName | semmle.label | fileName |
+| UnsafeLoadSpringResource.java:108:32:108:77 | fileName : String | semmle.label | fileName : String |
+| UnsafeLoadSpringResource.java:116:51:116:58 | fileName | semmle.label | fileName |
+| UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) : String | semmle.label | getServletPath(...) : String |
+| UnsafeRequestPath.java:23:33:23:36 | path | semmle.label | path |
+| UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | semmle.label | getRequestParameterMap(...) : Map |
+| UnsafeResourceGet2.java:17:20:17:25 | params : Map | semmle.label | params : Map |
+| UnsafeResourceGet2.java:17:20:17:40 | get(...) : String | semmle.label | get(...) : String |
+| UnsafeResourceGet2.java:19:93:19:99 | loadUrl | semmle.label | loadUrl |
+| UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) : Map | semmle.label | getRequestParameterMap(...) : Map |
+| UnsafeResourceGet2.java:33:20:33:25 | params : Map | semmle.label | params : Map |
+| UnsafeResourceGet2.java:33:20:33:40 | get(...) : String | semmle.label | get(...) : String |
+| UnsafeResourceGet2.java:35:13:35:56 | getResource(...) : URL | semmle.label | getResource(...) : URL |
+| UnsafeResourceGet2.java:35:49:35:55 | loadUrl : String | semmle.label | loadUrl : String |
+| UnsafeResourceGet2.java:37:20:37:22 | url | semmle.label | url |
+| UnsafeResourceGet.java:32:23:32:56 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| UnsafeResourceGet.java:39:13:39:38 | getResource(...) : URL | semmle.label | getResource(...) : URL |
+| UnsafeResourceGet.java:39:28:39:37 | requestUrl : String | semmle.label | requestUrl : String |
+| UnsafeResourceGet.java:41:20:41:22 | url | semmle.label | url |
+| UnsafeResourceGet.java:111:24:111:58 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| UnsafeResourceGet.java:115:68:115:78 | requestPath | semmle.label | requestPath |
+| UnsafeResourceGet.java:143:23:143:56 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| UnsafeResourceGet.java:148:13:148:46 | getResource(...) : URL | semmle.label | getResource(...) : URL |
+| UnsafeResourceGet.java:148:36:148:45 | requestUrl : String | semmle.label | requestUrl : String |
+| UnsafeResourceGet.java:150:20:150:22 | url | semmle.label | url |
+| UnsafeResourceGet.java:181:24:181:58 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| UnsafeResourceGet.java:189:68:189:78 | requestPath | semmle.label | requestPath |
+| UnsafeResourceGet.java:219:23:219:56 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| UnsafeResourceGet.java:224:13:224:63 | getResource(...) : URL | semmle.label | getResource(...) : URL |
+| UnsafeResourceGet.java:224:53:224:62 | requestUrl : String | semmle.label | requestUrl : String |
+| UnsafeResourceGet.java:226:20:226:22 | url | semmle.label | url |
+| UnsafeResourceGet.java:237:24:237:58 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| UnsafeResourceGet.java:241:18:241:44 | getResource(...) : Resource | semmle.label | getResource(...) : Resource |
+| UnsafeResourceGet.java:241:33:241:43 | requestPath : String | semmle.label | requestPath : String |
+| UnsafeResourceGet.java:245:21:245:22 | rs : Resource | semmle.label | rs : Resource |
+| UnsafeResourceGet.java:245:21:245:32 | getPath(...) | semmle.label | getPath(...) |
+| UnsafeServletRequestDispatch.java:23:22:23:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| UnsafeServletRequestDispatch.java:32:51:32:59 | returnURL | semmle.label | returnURL |
+| UnsafeServletRequestDispatch.java:42:22:42:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| UnsafeServletRequestDispatch.java:48:56:48:64 | returnURL | semmle.label | returnURL |
+| UnsafeServletRequestDispatch.java:71:17:71:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| UnsafeServletRequestDispatch.java:76:53:76:56 | path | semmle.label | path |
+| UnsafeUrlForward.java:13:27:13:36 | url : String | semmle.label | url : String |
+| UnsafeUrlForward.java:14:27:14:29 | url | semmle.label | url |
+| UnsafeUrlForward.java:18:27:18:36 | url : String | semmle.label | url : String |
+| UnsafeUrlForward.java:20:28:20:30 | url | semmle.label | url |
+| UnsafeUrlForward.java:25:21:25:30 | url : String | semmle.label | url : String |
+| UnsafeUrlForward.java:26:23:26:25 | url | semmle.label | url |
+| UnsafeUrlForward.java:30:27:30:36 | url : String | semmle.label | url : String |
+| UnsafeUrlForward.java:31:48:31:63 | ... + ... | semmle.label | ... + ... |
+| UnsafeUrlForward.java:31:61:31:63 | url | semmle.label | url |
+| UnsafeUrlForward.java:36:19:36:28 | url : String | semmle.label | url : String |
+| UnsafeUrlForward.java:38:33:38:35 | url | semmle.label | url |
+| UnsafeUrlForward.java:47:19:47:28 | url : String | semmle.label | url : String |
+| UnsafeUrlForward.java:49:33:49:62 | ... + ... | semmle.label | ... + ... |
+| UnsafeUrlForward.java:58:19:58:28 | url : String | semmle.label | url : String |
+| UnsafeUrlForward.java:60:33:60:62 | ... + ... | semmle.label | ... + ... |
+subpaths
+#select
+| UnsafeLoadSpringResource.java:35:31:35:33 | clr | UnsafeLoadSpringResource.java:27:32:27:77 | fileName : String | UnsafeLoadSpringResource.java:35:31:35:33 | clr | Potentially untrusted URL forward due to $@. | UnsafeLoadSpringResource.java:27:32:27:77 | fileName | user-provided value |
+| UnsafeLoadSpringResource.java:76:38:76:45 | fileName | UnsafeLoadSpringResource.java:68:32:68:77 | fileName : String | UnsafeLoadSpringResource.java:76:38:76:45 | fileName | Potentially untrusted URL forward due to $@. | UnsafeLoadSpringResource.java:68:32:68:77 | fileName | user-provided value |
+| UnsafeLoadSpringResource.java:116:51:116:58 | fileName | UnsafeLoadSpringResource.java:108:32:108:77 | fileName : String | UnsafeLoadSpringResource.java:116:51:116:58 | fileName | Potentially untrusted URL forward due to $@. | UnsafeLoadSpringResource.java:108:32:108:77 | fileName | user-provided value |
+| UnsafeRequestPath.java:23:33:23:36 | path | UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) : String | UnsafeRequestPath.java:23:33:23:36 | path | Potentially untrusted URL forward due to $@. | UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) | user-provided value |
+| UnsafeResourceGet2.java:19:93:19:99 | loadUrl | UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:19:93:19:99 | loadUrl | Potentially untrusted URL forward due to $@. | UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) | user-provided value |
+| UnsafeResourceGet2.java:37:20:37:22 | url | UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:37:20:37:22 | url | Potentially untrusted URL forward due to $@. | UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) | user-provided value |
+| UnsafeResourceGet.java:41:20:41:22 | url | UnsafeResourceGet.java:32:23:32:56 | getParameter(...) : String | UnsafeResourceGet.java:41:20:41:22 | url | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:32:23:32:56 | getParameter(...) | user-provided value |
+| UnsafeResourceGet.java:115:68:115:78 | requestPath | UnsafeResourceGet.java:111:24:111:58 | getParameter(...) : String | UnsafeResourceGet.java:115:68:115:78 | requestPath | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:111:24:111:58 | getParameter(...) | user-provided value |
+| UnsafeResourceGet.java:150:20:150:22 | url | UnsafeResourceGet.java:143:23:143:56 | getParameter(...) : String | UnsafeResourceGet.java:150:20:150:22 | url | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:143:23:143:56 | getParameter(...) | user-provided value |
+| UnsafeResourceGet.java:189:68:189:78 | requestPath | UnsafeResourceGet.java:181:24:181:58 | getParameter(...) : String | UnsafeResourceGet.java:189:68:189:78 | requestPath | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:181:24:181:58 | getParameter(...) | user-provided value |
+| UnsafeResourceGet.java:226:20:226:22 | url | UnsafeResourceGet.java:219:23:219:56 | getParameter(...) : String | UnsafeResourceGet.java:226:20:226:22 | url | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:219:23:219:56 | getParameter(...) | user-provided value |
+| UnsafeResourceGet.java:245:21:245:32 | getPath(...) | UnsafeResourceGet.java:237:24:237:58 | getParameter(...) : String | UnsafeResourceGet.java:245:21:245:32 | getPath(...) | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:237:24:237:58 | getParameter(...) | user-provided value |
+| UnsafeServletRequestDispatch.java:32:51:32:59 | returnURL | UnsafeServletRequestDispatch.java:23:22:23:54 | getParameter(...) : String | UnsafeServletRequestDispatch.java:32:51:32:59 | returnURL | Potentially untrusted URL forward due to $@. | UnsafeServletRequestDispatch.java:23:22:23:54 | getParameter(...) | user-provided value |
+| UnsafeServletRequestDispatch.java:48:56:48:64 | returnURL | UnsafeServletRequestDispatch.java:42:22:42:54 | getParameter(...) : String | UnsafeServletRequestDispatch.java:48:56:48:64 | returnURL | Potentially untrusted URL forward due to $@. | UnsafeServletRequestDispatch.java:42:22:42:54 | getParameter(...) | user-provided value |
+| UnsafeServletRequestDispatch.java:76:53:76:56 | path | UnsafeServletRequestDispatch.java:71:17:71:44 | getParameter(...) : String | UnsafeServletRequestDispatch.java:76:53:76:56 | path | Potentially untrusted URL forward due to $@. | UnsafeServletRequestDispatch.java:71:17:71:44 | getParameter(...) | user-provided value |
+| UnsafeUrlForward.java:14:27:14:29 | url | UnsafeUrlForward.java:13:27:13:36 | url : String | UnsafeUrlForward.java:14:27:14:29 | url | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:13:27:13:36 | url | user-provided value |
+| UnsafeUrlForward.java:20:28:20:30 | url | UnsafeUrlForward.java:18:27:18:36 | url : String | UnsafeUrlForward.java:20:28:20:30 | url | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:18:27:18:36 | url | user-provided value |
+| UnsafeUrlForward.java:26:23:26:25 | url | UnsafeUrlForward.java:25:21:25:30 | url : String | UnsafeUrlForward.java:26:23:26:25 | url | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:25:21:25:30 | url | user-provided value |
+| UnsafeUrlForward.java:31:48:31:63 | ... + ... | UnsafeUrlForward.java:30:27:30:36 | url : String | UnsafeUrlForward.java:31:48:31:63 | ... + ... | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:30:27:30:36 | url | user-provided value |
+| UnsafeUrlForward.java:31:61:31:63 | url | UnsafeUrlForward.java:30:27:30:36 | url : String | UnsafeUrlForward.java:31:61:31:63 | url | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:30:27:30:36 | url | user-provided value |
+| UnsafeUrlForward.java:38:33:38:35 | url | UnsafeUrlForward.java:36:19:36:28 | url : String | UnsafeUrlForward.java:38:33:38:35 | url | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:36:19:36:28 | url | user-provided value |
+| UnsafeUrlForward.java:49:33:49:62 | ... + ... | UnsafeUrlForward.java:47:19:47:28 | url : String | UnsafeUrlForward.java:49:33:49:62 | ... + ... | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:47:19:47:28 | url | user-provided value |
+| UnsafeUrlForward.java:60:33:60:62 | ... + ... | UnsafeUrlForward.java:58:19:58:28 | url : String | UnsafeUrlForward.java:60:33:60:62 | ... + ... | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:58:19:58:28 | url | user-provided value |
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.java b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.java
new file mode 100644
index 00000000000..4018ed28948
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.java
@@ -0,0 +1,78 @@
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+@Controller
+public class UnsafeUrlForward {
+
+ @GetMapping("/bad1")
+ public ModelAndView bad1(String url) {
+ return new ModelAndView(url);
+ }
+
+ @GetMapping("/bad2")
+ public ModelAndView bad2(String url) {
+ ModelAndView modelAndView = new ModelAndView();
+ modelAndView.setViewName(url);
+ return modelAndView;
+ }
+
+ @GetMapping("/bad3")
+ public String bad3(String url) {
+ return "forward:" + url + "/swagger-ui/index.html";
+ }
+
+ @GetMapping("/bad4")
+ public ModelAndView bad4(String url) {
+ ModelAndView modelAndView = new ModelAndView("forward:" + url);
+ return modelAndView;
+ }
+
+ @GetMapping("/bad5")
+ public void bad5(String url, HttpServletRequest request, HttpServletResponse response) {
+ try {
+ request.getRequestDispatcher(url).include(request, response);
+ } catch (ServletException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @GetMapping("/bad6")
+ public void bad6(String url, HttpServletRequest request, HttpServletResponse response) {
+ try {
+ request.getRequestDispatcher("/WEB-INF/jsp/" + url + ".jsp").include(request, response);
+ } catch (ServletException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @GetMapping("/bad7")
+ public void bad7(String url, HttpServletRequest request, HttpServletResponse response) {
+ try {
+ request.getRequestDispatcher("/WEB-INF/jsp/" + url + ".jsp").forward(request, response);
+ } catch (ServletException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @GetMapping("/good1")
+ public void good1(String url, HttpServletRequest request, HttpServletResponse response) {
+ try {
+ request.getRequestDispatcher("/index.jsp?token=" + url).forward(request, response);
+ } catch (ServletException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.qlref b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.qlref
new file mode 100644
index 00000000000..934a18cc6c7
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.qlref
@@ -0,0 +1 @@
+experimental/Security/CWE/CWE-552/UnsafeUrlForward.ql
diff --git a/java/ql/test/query-tests/security/CWE-552/options b/java/ql/test/query-tests/security/CWE-552/options
new file mode 100644
index 00000000000..025b888db02
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-552/options
@@ -0,0 +1 @@
+//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.3.8/:${testdir}/../../../stubs/javax-faces-2.3/:${testdir}/../../../stubs/undertow-io-2.2/:${testdir}/../../../stubs/jboss-vfs-3.2/:${testdir}/../../../stubs/springframework-5.3.8/
From 2793f28428567060b66819525a5a045f52f2228d Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Mon, 20 Nov 2023 16:56:41 -0500
Subject: [PATCH 039/497] Java: move config to Query.qll file
---
java/ql/lib/semmle/code/java/Jsf.qll | 35 +++++++++++++++
.../lib/semmle/code/java/SpringResource.qll | 22 +++++++++
.../code/java/security}/UnsafeUrlForward.qll | 4 +-
.../java/security/UnsafeUrlForwardQuery.qll | 45 +++++++++++++++++++
.../Security/CWE/CWE-552/UnsafeUrlForward.ql | 45 +------------------
5 files changed, 105 insertions(+), 46 deletions(-)
create mode 100644 java/ql/lib/semmle/code/java/Jsf.qll
create mode 100644 java/ql/lib/semmle/code/java/SpringResource.qll
rename java/ql/{src/Security/CWE/CWE-552 => lib/semmle/code/java/security}/UnsafeUrlForward.qll (97%)
create mode 100644 java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
diff --git a/java/ql/lib/semmle/code/java/Jsf.qll b/java/ql/lib/semmle/code/java/Jsf.qll
new file mode 100644
index 00000000000..9023953add4
--- /dev/null
+++ b/java/ql/lib/semmle/code/java/Jsf.qll
@@ -0,0 +1,35 @@
+/**
+ * Provides classes and predicates for working with the Java Server Faces (JSF).
+ */
+
+// TODO: COMBINE WITH EXISTING JSF-RELATED QLL FILES!
+import java
+
+/**
+ * The JSF class `ExternalContext` for processing HTTP requests.
+ */
+class ExternalContext extends RefType {
+ ExternalContext() {
+ this.hasQualifiedName(["javax.faces.context", "jakarta.faces.context"], "ExternalContext")
+ }
+}
+
+/**
+ * The method `getResource()` declared in JSF `ExternalContext`.
+ */
+class GetFacesResourceMethod extends Method {
+ GetFacesResourceMethod() {
+ this.getDeclaringType().getASupertype*() instanceof ExternalContext and
+ this.hasName("getResource")
+ }
+}
+
+/**
+ * The method `getResourceAsStream()` declared in JSF `ExternalContext`.
+ */
+class GetFacesResourceAsStreamMethod extends Method {
+ GetFacesResourceAsStreamMethod() {
+ this.getDeclaringType().getASupertype*() instanceof ExternalContext and
+ this.hasName("getResourceAsStream")
+ }
+}
diff --git a/java/ql/lib/semmle/code/java/SpringResource.qll b/java/ql/lib/semmle/code/java/SpringResource.qll
new file mode 100644
index 00000000000..a7d3a3793b6
--- /dev/null
+++ b/java/ql/lib/semmle/code/java/SpringResource.qll
@@ -0,0 +1,22 @@
+/**
+ * Provides classes for working with resource loading in Spring.
+ */
+
+// TODO: COMBINE WITH EXISTING SPRING-RELATED QLL FILES!
+import java
+private import semmle.code.java.dataflow.FlowSources
+
+/** A utility class for resolving resource locations to files in the file system in the Spring framework. */
+class ResourceUtils extends Class {
+ ResourceUtils() { this.hasQualifiedName("org.springframework.util", "ResourceUtils") }
+}
+
+/**
+ * A method declared in `org.springframework.util.ResourceUtils` that loads Spring resources.
+ */
+class GetResourceUtilsMethod extends Method {
+ GetResourceUtilsMethod() {
+ this.getDeclaringType().getASupertype*() instanceof ResourceUtils and
+ this.hasName(["extractArchiveURL", "extractJarFileURL", "getFile", "getURL"])
+ }
+}
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qll b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
similarity index 97%
rename from java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qll
rename to java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
index db610eb65ce..48b4431015e 100644
--- a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
@@ -1,10 +1,10 @@
import java
-private import experimental.semmle.code.java.frameworks.Jsf
+private import semmle.code.java.Jsf
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.StringPrefixes
private import semmle.code.java.frameworks.javaee.ejb.EJBRestrictions
-private import experimental.semmle.code.java.frameworks.SpringResource
+private import semmle.code.java.SpringResource
/** A sink for unsafe URL forward vulnerabilities. */
abstract class UnsafeUrlForwardSink extends DataFlow::Node { }
diff --git a/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll b/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
new file mode 100644
index 00000000000..9ee3f2ab417
--- /dev/null
+++ b/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
@@ -0,0 +1,45 @@
+import java
+import semmle.code.java.security.UnsafeUrlForward
+import semmle.code.java.dataflow.FlowSources
+import semmle.code.java.dataflow.TaintTracking
+import semmle.code.java.Jsf
+import semmle.code.java.security.PathSanitizer
+
+module UnsafeUrlForwardFlowConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node source) {
+ source instanceof ThreatModelFlowSource and
+ not exists(MethodCall ma, Method m | ma.getMethod() = m |
+ (
+ m instanceof HttpServletRequestGetRequestUriMethod or
+ m instanceof HttpServletRequestGetRequestUrlMethod or
+ m instanceof HttpServletRequestGetPathMethod
+ ) and
+ ma = source.asExpr()
+ )
+ }
+
+ predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeUrlForwardSink }
+
+ predicate isBarrier(DataFlow::Node node) {
+ node instanceof UnsafeUrlForwardSanitizer or
+ node instanceof PathInjectionSanitizer
+ }
+
+ DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
+
+ predicate isAdditionalFlowStep(DataFlow::Node prev, DataFlow::Node succ) {
+ exists(MethodCall ma |
+ (
+ ma.getMethod() instanceof GetServletResourceMethod or
+ ma.getMethod() instanceof GetFacesResourceMethod or
+ ma.getMethod() instanceof GetClassResourceMethod or
+ ma.getMethod() instanceof GetClassLoaderResourceMethod or
+ ma.getMethod() instanceof GetWildflyResourceMethod
+ ) and
+ ma.getArgument(0) = prev.asExpr() and
+ ma = succ.asExpr()
+ )
+ }
+}
+
+module UnsafeUrlForwardFlow = TaintTracking::Global;
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql b/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql
index 240023f9ffc..4e3326a831e 100644
--- a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql
+++ b/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql
@@ -11,52 +11,9 @@
*/
import java
-import UnsafeUrlForward
-import semmle.code.java.dataflow.FlowSources
-import semmle.code.java.dataflow.TaintTracking
-import experimental.semmle.code.java.frameworks.Jsf
-import semmle.code.java.security.PathSanitizer
+import semmle.code.java.security.UnsafeUrlForwardQuery
import UnsafeUrlForwardFlow::PathGraph
-module UnsafeUrlForwardFlowConfig implements DataFlow::ConfigSig {
- predicate isSource(DataFlow::Node source) {
- source instanceof ThreatModelFlowSource and
- not exists(MethodCall ma, Method m | ma.getMethod() = m |
- (
- m instanceof HttpServletRequestGetRequestUriMethod or
- m instanceof HttpServletRequestGetRequestUrlMethod or
- m instanceof HttpServletRequestGetPathMethod
- ) and
- ma = source.asExpr()
- )
- }
-
- predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeUrlForwardSink }
-
- predicate isBarrier(DataFlow::Node node) {
- node instanceof UnsafeUrlForwardSanitizer or
- node instanceof PathInjectionSanitizer
- }
-
- DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
-
- predicate isAdditionalFlowStep(DataFlow::Node prev, DataFlow::Node succ) {
- exists(MethodCall ma |
- (
- ma.getMethod() instanceof GetServletResourceMethod or
- ma.getMethod() instanceof GetFacesResourceMethod or
- ma.getMethod() instanceof GetClassResourceMethod or
- ma.getMethod() instanceof GetClassLoaderResourceMethod or
- ma.getMethod() instanceof GetWildflyResourceMethod
- ) and
- ma.getArgument(0) = prev.asExpr() and
- ma = succ.asExpr()
- )
- }
-}
-
-module UnsafeUrlForwardFlow = TaintTracking::Global;
-
from UnsafeUrlForwardFlow::PathNode source, UnsafeUrlForwardFlow::PathNode sink
where UnsafeUrlForwardFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Potentially untrusted URL forward due to $@.",
From 35a083ae9e5c70a29ac426cf54112ef98286507b Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Mon, 20 Nov 2023 16:59:19 -0500
Subject: [PATCH 040/497] Java: update test cases to use inline expectations
---
.../CWE-552/UnsafeLoadSpringResource.java | 10 +-
.../security/CWE-552/UnsafeRequestPath.java | 12 +-
.../security/CWE-552/UnsafeResourceGet.java | 12 +-
.../security/CWE-552/UnsafeResourceGet2.java | 4 +-
.../CWE-552/UnsafeServletRequestDispatch.java | 20 +--
.../CWE-552/UnsafeUrlForward.expected | 129 ------------------
.../security/CWE-552/UnsafeUrlForward.java | 14 +-
.../security/CWE-552/UnsafeUrlForward.qlref | 1 -
.../CWE-552/UnsafeUrlForwardTest.expected | 2 +
.../security/CWE-552/UnsafeUrlForwardTest.ql | 18 +++
10 files changed, 56 insertions(+), 166 deletions(-)
delete mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.expected
delete mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.qlref
create mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.expected
create mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.ql
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeLoadSpringResource.java b/java/ql/test/query-tests/security/CWE-552/UnsafeLoadSpringResource.java
index c7e114aede3..363d84cabe9 100644
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeLoadSpringResource.java
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeLoadSpringResource.java
@@ -32,7 +32,7 @@ public class UnsafeLoadSpringResource {
char[] buffer = new char[4096];
StringBuilder out = new StringBuilder();
try {
- Reader in = new FileReader(clr.getFilename());
+ Reader in = new FileReader(clr.getFilename()); // $ hasUnsafeUrlForward (path-inj?)
for (int numRead; (numRead = in.read(buffer, 0, buffer.length)) > 0; ) {
out.append(buffer, 0, numRead);
}
@@ -67,13 +67,13 @@ public class UnsafeLoadSpringResource {
//BAD: Get resource from ResourceUtils without input validation
public String getFileContent2(@RequestParam(name="fileName") String fileName) {
String content = null;
-
+
try {
// A request such as the following can disclose source code and system configuration
// fileName=/etc/hosts
// fileName=file:/etc/hosts
// fileName=/opt/appdir/WEB-INF/views/page.jsp
- File file = ResourceUtils.getFile(fileName);
+ File file = ResourceUtils.getFile(fileName); // $ hasUnsafeUrlForward (path-inj?)
//Read File Content
content = new String(Files.readAllBytes(file.toPath()));
} catch (IOException ie) {
@@ -86,7 +86,7 @@ public class UnsafeLoadSpringResource {
//GOOD: Get resource from ResourceUtils with input path validation
public String getFileContent2a(@RequestParam(name="fileName") String fileName) {
String content = null;
-
+
if (fileName.startsWith("/safe_dir") && !fileName.contains("..")) {
try {
File file = ResourceUtils.getFile(fileName);
@@ -113,7 +113,7 @@ public class UnsafeLoadSpringResource {
// fileName=/WEB-INF/views/page.jsp
// fileName=/WEB-INF/classes/com/example/package/SampleController.class
// fileName=file:/etc/hosts
- Resource resource = resourceLoader.getResource(fileName);
+ Resource resource = resourceLoader.getResource(fileName); // $ hasUnsafeUrlForward (path-inj?)
char[] buffer = new char[4096];
StringBuilder out = new StringBuilder();
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java b/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java
index 2de0cae0d3c..55afe84bc19 100644
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java
@@ -14,23 +14,23 @@ public class UnsafeRequestPath implements Filter {
private static final String BASE_PATH = "/pages";
@Override
- // BAD: Request dispatcher from servlet path without check
+ // BAD: Request dispatcher from servlet path without check
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
String path = ((HttpServletRequest) request).getServletPath();
// A sample payload "/%57EB-INF/web.xml" can bypass this `startsWith` check
if (path != null && !path.startsWith("/WEB-INF")) {
- request.getRequestDispatcher(path).forward(request, response);
+ request.getRequestDispatcher(path).forward(request, response); // $ hasUnsafeUrlForward
} else {
chain.doFilter(request, response);
}
}
- // GOOD: Request dispatcher from servlet path with check
+ // GOOD: Request dispatcher from servlet path with check
public void doFilter2(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
String path = ((HttpServletRequest) request).getServletPath();
-
+
if (path.startsWith(BASE_PATH) && !path.contains("..")) {
request.getRequestDispatcher(path).forward(request, response);
} else {
@@ -38,11 +38,11 @@ public class UnsafeRequestPath implements Filter {
}
}
- // GOOD: Request dispatcher from servlet path with whitelisted string comparison
+ // GOOD: Request dispatcher from servlet path with whitelisted string comparison
public void doFilter3(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
String path = ((HttpServletRequest) request).getServletPath();
-
+
if (path.equals("/comaction")) {
request.getRequestDispatcher(path).forward(request, response);
} else {
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet.java b/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet.java
index 64c23334f18..053887984c6 100644
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet.java
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet.java
@@ -38,7 +38,7 @@ public class UnsafeResourceGet extends HttpServlet {
// A sample request /fake.jsp/../WEB-INF/web.xml can load the web.xml file
URL url = sc.getResource(requestUrl);
- InputStream in = url.openStream();
+ InputStream in = url.openStream(); // $ hasUnsafeUrlForward (SSRF)
byte[] buf = new byte[4 * 1024]; // 4K buffer
int bytesRead;
while ((bytesRead = in.read(buf)) != -1) {
@@ -112,7 +112,7 @@ public class UnsafeResourceGet extends HttpServlet {
ServletOutputStream out = response.getOutputStream();
// A sample request /fake.jsp/../WEB-INF/web.xml can load the web.xml file
- InputStream in = request.getServletContext().getResourceAsStream(requestPath);
+ InputStream in = request.getServletContext().getResourceAsStream(requestPath); // $ hasUnsafeUrlForward (path-inj?)
byte[] buf = new byte[4 * 1024]; // 4K buffer
int bytesRead;
while ((bytesRead = in.read(buf)) != -1) {
@@ -147,7 +147,7 @@ public class UnsafeResourceGet extends HttpServlet {
// Note the class is in two levels of subpackages and `Class.getResource` starts from its own directory
URL url = getClass().getResource(requestUrl);
- InputStream in = url.openStream();
+ InputStream in = url.openStream(); // $ hasUnsafeUrlForward (SSRF)
byte[] buf = new byte[4 * 1024]; // 4K buffer
int bytesRead;
while ((bytesRead = in.read(buf)) != -1) {
@@ -186,7 +186,7 @@ public class UnsafeResourceGet extends HttpServlet {
// A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file
// Note the class is in two levels of subpackages and `ClassLoader.getResourceAsStream` starts from its own directory
- InputStream in = getClass().getClassLoader().getResourceAsStream(requestPath);
+ InputStream in = getClass().getClassLoader().getResourceAsStream(requestPath); // $ hasUnsafeUrlForward (path-inj?)
byte[] buf = new byte[4 * 1024]; // 4K buffer
int bytesRead;
while ((bytesRead = in.read(buf)) != -1) {
@@ -223,7 +223,7 @@ public class UnsafeResourceGet extends HttpServlet {
// Note the class is in two levels of subpackages and `ClassLoader.getResource` starts from its own directory
URL url = getClass().getClassLoader().getResource(requestUrl);
- InputStream in = url.openStream();
+ InputStream in = url.openStream(); // $ hasUnsafeUrlForward (SSRF)
byte[] buf = new byte[4 * 1024]; // 4K buffer
int bytesRead;
while ((bytesRead = in.read(buf)) != -1) {
@@ -242,7 +242,7 @@ public class UnsafeResourceGet extends HttpServlet {
VirtualFile overlay = VFS.getChild(new URI("EAP_HOME/modules/"));
// Do file operations
- overlay.getChild(rs.getPath());
+ overlay.getChild(rs.getPath()); // $ hasUnsafeUrlForward (path-inj?)
} catch (URISyntaxException ue) {
throw new IOException("Cannot parse the URI");
}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet2.java b/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet2.java
index b3d041d024c..0043bb06c67 100644
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet2.java
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet2.java
@@ -16,7 +16,7 @@ public class UnsafeResourceGet2 {
Map params = fc.getExternalContext().getRequestParameterMap();
String loadUrl = params.get("loadUrl");
- InputStreamReader isr = new InputStreamReader(fc.getExternalContext().getResourceAsStream(loadUrl));
+ InputStreamReader isr = new InputStreamReader(fc.getExternalContext().getResourceAsStream(loadUrl)); // $ hasUnsafeUrlForward (path-inj?)
BufferedReader br = new BufferedReader(isr);
if(br.ready()) {
//Do Stuff
@@ -34,7 +34,7 @@ public class UnsafeResourceGet2 {
URL url = fc.getExternalContext().getResource(loadUrl);
- InputStream in = url.openStream();
+ InputStream in = url.openStream(); // $ hasUnsafeUrlForward (SSRF)
//Do Stuff
return "result";
}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java b/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java
index ee63939b209..9d501f2ec0d 100644
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java
@@ -29,13 +29,13 @@ public class UnsafeServletRequestDispatch extends HttpServlet {
rd.forward(request, response);
} else {
ServletContext sc = cfg.getServletContext();
- RequestDispatcher rd = sc.getRequestDispatcher(returnURL);
+ RequestDispatcher rd = sc.getRequestDispatcher(returnURL); // $ hasUnsafeUrlForward
rd.forward(request, response);
}
}
@Override
- // BAD: Request dispatcher constructed from `HttpServletRequest` without input validation
+ // BAD: Request dispatcher constructed from `HttpServletRequest` without input validation
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
@@ -45,7 +45,7 @@ public class UnsafeServletRequestDispatch extends HttpServlet {
RequestDispatcher rd = request.getRequestDispatcher("/Login.jsp");
rd.forward(request, response);
} else {
- RequestDispatcher rd = request.getRequestDispatcher(returnURL);
+ RequestDispatcher rd = request.getRequestDispatcher(returnURL); // $ hasUnsafeUrlForward
rd.forward(request, response);
}
}
@@ -65,22 +65,22 @@ public class UnsafeServletRequestDispatch extends HttpServlet {
}
}
- // BAD: Request dispatcher without path traversal check
+ // BAD: Request dispatcher without path traversal check
protected void doHead2(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
- // A sample payload "/pages/welcome.jsp/../WEB-INF/web.xml" can bypass the `startsWith` check
- // The payload "/pages/welcome.jsp/../../%57EB-INF/web.xml" can bypass the check as well since RequestDispatcher will decode `%57` as `W`
+ // A sample payload "/pages/welcome.jsp/../WEB-INF/web.xml" can bypass the `startsWith` check
+ // The payload "/pages/welcome.jsp/../../%57EB-INF/web.xml" can bypass the check as well since RequestDispatcher will decode `%57` as `W`
if (path.startsWith(BASE_PATH)) {
- request.getServletContext().getRequestDispatcher(path).include(request, response);
+ request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUnsafeUrlForward
}
}
- // GOOD: Request dispatcher with path traversal check
+ // GOOD: Request dispatcher with path traversal check
protected void doHead3(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
- String path = request.getParameter("path");
+ String path = request.getParameter("path");
if (path.startsWith(BASE_PATH) && !path.contains("..")) {
request.getServletContext().getRequestDispatcher(path).include(request, response);
@@ -110,7 +110,7 @@ public class UnsafeServletRequestDispatch extends HttpServlet {
Path requestedPath = Paths.get(BASE_PATH).resolve(path).normalize();
if (!requestedPath.startsWith("/WEB-INF") && !requestedPath.startsWith("/META-INF")) {
- request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response);
+ request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response); // $ MISSING: hasUnsafeUrlForward
}
}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.expected b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.expected
deleted file mode 100644
index 5d809244fdb..00000000000
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.expected
+++ /dev/null
@@ -1,129 +0,0 @@
-edges
-| UnsafeLoadSpringResource.java:27:32:27:77 | fileName : String | UnsafeLoadSpringResource.java:31:49:31:56 | fileName : String |
-| UnsafeLoadSpringResource.java:31:27:31:57 | new ClassPathResource(...) : ClassPathResource | UnsafeLoadSpringResource.java:35:31:35:33 | clr |
-| UnsafeLoadSpringResource.java:31:49:31:56 | fileName : String | UnsafeLoadSpringResource.java:31:27:31:57 | new ClassPathResource(...) : ClassPathResource |
-| UnsafeLoadSpringResource.java:68:32:68:77 | fileName : String | UnsafeLoadSpringResource.java:76:38:76:45 | fileName |
-| UnsafeLoadSpringResource.java:108:32:108:77 | fileName : String | UnsafeLoadSpringResource.java:116:51:116:58 | fileName |
-| UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) : String | UnsafeRequestPath.java:23:33:23:36 | path |
-| UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:17:20:17:25 | params : Map |
-| UnsafeResourceGet2.java:17:20:17:25 | params : Map | UnsafeResourceGet2.java:17:20:17:40 | get(...) : String |
-| UnsafeResourceGet2.java:17:20:17:40 | get(...) : String | UnsafeResourceGet2.java:19:93:19:99 | loadUrl |
-| UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:33:20:33:25 | params : Map |
-| UnsafeResourceGet2.java:33:20:33:25 | params : Map | UnsafeResourceGet2.java:33:20:33:40 | get(...) : String |
-| UnsafeResourceGet2.java:33:20:33:40 | get(...) : String | UnsafeResourceGet2.java:35:49:35:55 | loadUrl : String |
-| UnsafeResourceGet2.java:35:13:35:56 | getResource(...) : URL | UnsafeResourceGet2.java:37:20:37:22 | url |
-| UnsafeResourceGet2.java:35:49:35:55 | loadUrl : String | UnsafeResourceGet2.java:35:13:35:56 | getResource(...) : URL |
-| UnsafeResourceGet.java:32:23:32:56 | getParameter(...) : String | UnsafeResourceGet.java:39:28:39:37 | requestUrl : String |
-| UnsafeResourceGet.java:39:13:39:38 | getResource(...) : URL | UnsafeResourceGet.java:41:20:41:22 | url |
-| UnsafeResourceGet.java:39:28:39:37 | requestUrl : String | UnsafeResourceGet.java:39:13:39:38 | getResource(...) : URL |
-| UnsafeResourceGet.java:111:24:111:58 | getParameter(...) : String | UnsafeResourceGet.java:115:68:115:78 | requestPath |
-| UnsafeResourceGet.java:143:23:143:56 | getParameter(...) : String | UnsafeResourceGet.java:148:36:148:45 | requestUrl : String |
-| UnsafeResourceGet.java:148:13:148:46 | getResource(...) : URL | UnsafeResourceGet.java:150:20:150:22 | url |
-| UnsafeResourceGet.java:148:36:148:45 | requestUrl : String | UnsafeResourceGet.java:148:13:148:46 | getResource(...) : URL |
-| UnsafeResourceGet.java:181:24:181:58 | getParameter(...) : String | UnsafeResourceGet.java:189:68:189:78 | requestPath |
-| UnsafeResourceGet.java:219:23:219:56 | getParameter(...) : String | UnsafeResourceGet.java:224:53:224:62 | requestUrl : String |
-| UnsafeResourceGet.java:224:13:224:63 | getResource(...) : URL | UnsafeResourceGet.java:226:20:226:22 | url |
-| UnsafeResourceGet.java:224:53:224:62 | requestUrl : String | UnsafeResourceGet.java:224:13:224:63 | getResource(...) : URL |
-| UnsafeResourceGet.java:237:24:237:58 | getParameter(...) : String | UnsafeResourceGet.java:241:33:241:43 | requestPath : String |
-| UnsafeResourceGet.java:241:18:241:44 | getResource(...) : Resource | UnsafeResourceGet.java:245:21:245:22 | rs : Resource |
-| UnsafeResourceGet.java:241:33:241:43 | requestPath : String | UnsafeResourceGet.java:241:18:241:44 | getResource(...) : Resource |
-| UnsafeResourceGet.java:245:21:245:22 | rs : Resource | UnsafeResourceGet.java:245:21:245:32 | getPath(...) |
-| UnsafeServletRequestDispatch.java:23:22:23:54 | getParameter(...) : String | UnsafeServletRequestDispatch.java:32:51:32:59 | returnURL |
-| UnsafeServletRequestDispatch.java:42:22:42:54 | getParameter(...) : String | UnsafeServletRequestDispatch.java:48:56:48:64 | returnURL |
-| UnsafeServletRequestDispatch.java:71:17:71:44 | getParameter(...) : String | UnsafeServletRequestDispatch.java:76:53:76:56 | path |
-| UnsafeUrlForward.java:13:27:13:36 | url : String | UnsafeUrlForward.java:14:27:14:29 | url |
-| UnsafeUrlForward.java:18:27:18:36 | url : String | UnsafeUrlForward.java:20:28:20:30 | url |
-| UnsafeUrlForward.java:25:21:25:30 | url : String | UnsafeUrlForward.java:26:23:26:25 | url |
-| UnsafeUrlForward.java:30:27:30:36 | url : String | UnsafeUrlForward.java:31:48:31:63 | ... + ... |
-| UnsafeUrlForward.java:30:27:30:36 | url : String | UnsafeUrlForward.java:31:61:31:63 | url |
-| UnsafeUrlForward.java:36:19:36:28 | url : String | UnsafeUrlForward.java:38:33:38:35 | url |
-| UnsafeUrlForward.java:47:19:47:28 | url : String | UnsafeUrlForward.java:49:33:49:62 | ... + ... |
-| UnsafeUrlForward.java:58:19:58:28 | url : String | UnsafeUrlForward.java:60:33:60:62 | ... + ... |
-nodes
-| UnsafeLoadSpringResource.java:27:32:27:77 | fileName : String | semmle.label | fileName : String |
-| UnsafeLoadSpringResource.java:31:27:31:57 | new ClassPathResource(...) : ClassPathResource | semmle.label | new ClassPathResource(...) : ClassPathResource |
-| UnsafeLoadSpringResource.java:31:49:31:56 | fileName : String | semmle.label | fileName : String |
-| UnsafeLoadSpringResource.java:35:31:35:33 | clr | semmle.label | clr |
-| UnsafeLoadSpringResource.java:68:32:68:77 | fileName : String | semmle.label | fileName : String |
-| UnsafeLoadSpringResource.java:76:38:76:45 | fileName | semmle.label | fileName |
-| UnsafeLoadSpringResource.java:108:32:108:77 | fileName : String | semmle.label | fileName : String |
-| UnsafeLoadSpringResource.java:116:51:116:58 | fileName | semmle.label | fileName |
-| UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) : String | semmle.label | getServletPath(...) : String |
-| UnsafeRequestPath.java:23:33:23:36 | path | semmle.label | path |
-| UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | semmle.label | getRequestParameterMap(...) : Map |
-| UnsafeResourceGet2.java:17:20:17:25 | params : Map | semmle.label | params : Map |
-| UnsafeResourceGet2.java:17:20:17:40 | get(...) : String | semmle.label | get(...) : String |
-| UnsafeResourceGet2.java:19:93:19:99 | loadUrl | semmle.label | loadUrl |
-| UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) : Map | semmle.label | getRequestParameterMap(...) : Map |
-| UnsafeResourceGet2.java:33:20:33:25 | params : Map | semmle.label | params : Map |
-| UnsafeResourceGet2.java:33:20:33:40 | get(...) : String | semmle.label | get(...) : String |
-| UnsafeResourceGet2.java:35:13:35:56 | getResource(...) : URL | semmle.label | getResource(...) : URL |
-| UnsafeResourceGet2.java:35:49:35:55 | loadUrl : String | semmle.label | loadUrl : String |
-| UnsafeResourceGet2.java:37:20:37:22 | url | semmle.label | url |
-| UnsafeResourceGet.java:32:23:32:56 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| UnsafeResourceGet.java:39:13:39:38 | getResource(...) : URL | semmle.label | getResource(...) : URL |
-| UnsafeResourceGet.java:39:28:39:37 | requestUrl : String | semmle.label | requestUrl : String |
-| UnsafeResourceGet.java:41:20:41:22 | url | semmle.label | url |
-| UnsafeResourceGet.java:111:24:111:58 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| UnsafeResourceGet.java:115:68:115:78 | requestPath | semmle.label | requestPath |
-| UnsafeResourceGet.java:143:23:143:56 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| UnsafeResourceGet.java:148:13:148:46 | getResource(...) : URL | semmle.label | getResource(...) : URL |
-| UnsafeResourceGet.java:148:36:148:45 | requestUrl : String | semmle.label | requestUrl : String |
-| UnsafeResourceGet.java:150:20:150:22 | url | semmle.label | url |
-| UnsafeResourceGet.java:181:24:181:58 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| UnsafeResourceGet.java:189:68:189:78 | requestPath | semmle.label | requestPath |
-| UnsafeResourceGet.java:219:23:219:56 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| UnsafeResourceGet.java:224:13:224:63 | getResource(...) : URL | semmle.label | getResource(...) : URL |
-| UnsafeResourceGet.java:224:53:224:62 | requestUrl : String | semmle.label | requestUrl : String |
-| UnsafeResourceGet.java:226:20:226:22 | url | semmle.label | url |
-| UnsafeResourceGet.java:237:24:237:58 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| UnsafeResourceGet.java:241:18:241:44 | getResource(...) : Resource | semmle.label | getResource(...) : Resource |
-| UnsafeResourceGet.java:241:33:241:43 | requestPath : String | semmle.label | requestPath : String |
-| UnsafeResourceGet.java:245:21:245:22 | rs : Resource | semmle.label | rs : Resource |
-| UnsafeResourceGet.java:245:21:245:32 | getPath(...) | semmle.label | getPath(...) |
-| UnsafeServletRequestDispatch.java:23:22:23:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| UnsafeServletRequestDispatch.java:32:51:32:59 | returnURL | semmle.label | returnURL |
-| UnsafeServletRequestDispatch.java:42:22:42:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| UnsafeServletRequestDispatch.java:48:56:48:64 | returnURL | semmle.label | returnURL |
-| UnsafeServletRequestDispatch.java:71:17:71:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| UnsafeServletRequestDispatch.java:76:53:76:56 | path | semmle.label | path |
-| UnsafeUrlForward.java:13:27:13:36 | url : String | semmle.label | url : String |
-| UnsafeUrlForward.java:14:27:14:29 | url | semmle.label | url |
-| UnsafeUrlForward.java:18:27:18:36 | url : String | semmle.label | url : String |
-| UnsafeUrlForward.java:20:28:20:30 | url | semmle.label | url |
-| UnsafeUrlForward.java:25:21:25:30 | url : String | semmle.label | url : String |
-| UnsafeUrlForward.java:26:23:26:25 | url | semmle.label | url |
-| UnsafeUrlForward.java:30:27:30:36 | url : String | semmle.label | url : String |
-| UnsafeUrlForward.java:31:48:31:63 | ... + ... | semmle.label | ... + ... |
-| UnsafeUrlForward.java:31:61:31:63 | url | semmle.label | url |
-| UnsafeUrlForward.java:36:19:36:28 | url : String | semmle.label | url : String |
-| UnsafeUrlForward.java:38:33:38:35 | url | semmle.label | url |
-| UnsafeUrlForward.java:47:19:47:28 | url : String | semmle.label | url : String |
-| UnsafeUrlForward.java:49:33:49:62 | ... + ... | semmle.label | ... + ... |
-| UnsafeUrlForward.java:58:19:58:28 | url : String | semmle.label | url : String |
-| UnsafeUrlForward.java:60:33:60:62 | ... + ... | semmle.label | ... + ... |
-subpaths
-#select
-| UnsafeLoadSpringResource.java:35:31:35:33 | clr | UnsafeLoadSpringResource.java:27:32:27:77 | fileName : String | UnsafeLoadSpringResource.java:35:31:35:33 | clr | Potentially untrusted URL forward due to $@. | UnsafeLoadSpringResource.java:27:32:27:77 | fileName | user-provided value |
-| UnsafeLoadSpringResource.java:76:38:76:45 | fileName | UnsafeLoadSpringResource.java:68:32:68:77 | fileName : String | UnsafeLoadSpringResource.java:76:38:76:45 | fileName | Potentially untrusted URL forward due to $@. | UnsafeLoadSpringResource.java:68:32:68:77 | fileName | user-provided value |
-| UnsafeLoadSpringResource.java:116:51:116:58 | fileName | UnsafeLoadSpringResource.java:108:32:108:77 | fileName : String | UnsafeLoadSpringResource.java:116:51:116:58 | fileName | Potentially untrusted URL forward due to $@. | UnsafeLoadSpringResource.java:108:32:108:77 | fileName | user-provided value |
-| UnsafeRequestPath.java:23:33:23:36 | path | UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) : String | UnsafeRequestPath.java:23:33:23:36 | path | Potentially untrusted URL forward due to $@. | UnsafeRequestPath.java:20:17:20:63 | getServletPath(...) | user-provided value |
-| UnsafeResourceGet2.java:19:93:19:99 | loadUrl | UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:19:93:19:99 | loadUrl | Potentially untrusted URL forward due to $@. | UnsafeResourceGet2.java:16:32:16:79 | getRequestParameterMap(...) | user-provided value |
-| UnsafeResourceGet2.java:37:20:37:22 | url | UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) : Map | UnsafeResourceGet2.java:37:20:37:22 | url | Potentially untrusted URL forward due to $@. | UnsafeResourceGet2.java:32:32:32:79 | getRequestParameterMap(...) | user-provided value |
-| UnsafeResourceGet.java:41:20:41:22 | url | UnsafeResourceGet.java:32:23:32:56 | getParameter(...) : String | UnsafeResourceGet.java:41:20:41:22 | url | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:32:23:32:56 | getParameter(...) | user-provided value |
-| UnsafeResourceGet.java:115:68:115:78 | requestPath | UnsafeResourceGet.java:111:24:111:58 | getParameter(...) : String | UnsafeResourceGet.java:115:68:115:78 | requestPath | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:111:24:111:58 | getParameter(...) | user-provided value |
-| UnsafeResourceGet.java:150:20:150:22 | url | UnsafeResourceGet.java:143:23:143:56 | getParameter(...) : String | UnsafeResourceGet.java:150:20:150:22 | url | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:143:23:143:56 | getParameter(...) | user-provided value |
-| UnsafeResourceGet.java:189:68:189:78 | requestPath | UnsafeResourceGet.java:181:24:181:58 | getParameter(...) : String | UnsafeResourceGet.java:189:68:189:78 | requestPath | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:181:24:181:58 | getParameter(...) | user-provided value |
-| UnsafeResourceGet.java:226:20:226:22 | url | UnsafeResourceGet.java:219:23:219:56 | getParameter(...) : String | UnsafeResourceGet.java:226:20:226:22 | url | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:219:23:219:56 | getParameter(...) | user-provided value |
-| UnsafeResourceGet.java:245:21:245:32 | getPath(...) | UnsafeResourceGet.java:237:24:237:58 | getParameter(...) : String | UnsafeResourceGet.java:245:21:245:32 | getPath(...) | Potentially untrusted URL forward due to $@. | UnsafeResourceGet.java:237:24:237:58 | getParameter(...) | user-provided value |
-| UnsafeServletRequestDispatch.java:32:51:32:59 | returnURL | UnsafeServletRequestDispatch.java:23:22:23:54 | getParameter(...) : String | UnsafeServletRequestDispatch.java:32:51:32:59 | returnURL | Potentially untrusted URL forward due to $@. | UnsafeServletRequestDispatch.java:23:22:23:54 | getParameter(...) | user-provided value |
-| UnsafeServletRequestDispatch.java:48:56:48:64 | returnURL | UnsafeServletRequestDispatch.java:42:22:42:54 | getParameter(...) : String | UnsafeServletRequestDispatch.java:48:56:48:64 | returnURL | Potentially untrusted URL forward due to $@. | UnsafeServletRequestDispatch.java:42:22:42:54 | getParameter(...) | user-provided value |
-| UnsafeServletRequestDispatch.java:76:53:76:56 | path | UnsafeServletRequestDispatch.java:71:17:71:44 | getParameter(...) : String | UnsafeServletRequestDispatch.java:76:53:76:56 | path | Potentially untrusted URL forward due to $@. | UnsafeServletRequestDispatch.java:71:17:71:44 | getParameter(...) | user-provided value |
-| UnsafeUrlForward.java:14:27:14:29 | url | UnsafeUrlForward.java:13:27:13:36 | url : String | UnsafeUrlForward.java:14:27:14:29 | url | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:13:27:13:36 | url | user-provided value |
-| UnsafeUrlForward.java:20:28:20:30 | url | UnsafeUrlForward.java:18:27:18:36 | url : String | UnsafeUrlForward.java:20:28:20:30 | url | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:18:27:18:36 | url | user-provided value |
-| UnsafeUrlForward.java:26:23:26:25 | url | UnsafeUrlForward.java:25:21:25:30 | url : String | UnsafeUrlForward.java:26:23:26:25 | url | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:25:21:25:30 | url | user-provided value |
-| UnsafeUrlForward.java:31:48:31:63 | ... + ... | UnsafeUrlForward.java:30:27:30:36 | url : String | UnsafeUrlForward.java:31:48:31:63 | ... + ... | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:30:27:30:36 | url | user-provided value |
-| UnsafeUrlForward.java:31:61:31:63 | url | UnsafeUrlForward.java:30:27:30:36 | url : String | UnsafeUrlForward.java:31:61:31:63 | url | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:30:27:30:36 | url | user-provided value |
-| UnsafeUrlForward.java:38:33:38:35 | url | UnsafeUrlForward.java:36:19:36:28 | url : String | UnsafeUrlForward.java:38:33:38:35 | url | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:36:19:36:28 | url | user-provided value |
-| UnsafeUrlForward.java:49:33:49:62 | ... + ... | UnsafeUrlForward.java:47:19:47:28 | url : String | UnsafeUrlForward.java:49:33:49:62 | ... + ... | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:47:19:47:28 | url | user-provided value |
-| UnsafeUrlForward.java:60:33:60:62 | ... + ... | UnsafeUrlForward.java:58:19:58:28 | url : String | UnsafeUrlForward.java:60:33:60:62 | ... + ... | Potentially untrusted URL forward due to $@. | UnsafeUrlForward.java:58:19:58:28 | url | user-provided value |
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.java b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.java
index 4018ed28948..0a00637cd44 100644
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.java
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.java
@@ -11,31 +11,31 @@ public class UnsafeUrlForward {
@GetMapping("/bad1")
public ModelAndView bad1(String url) {
- return new ModelAndView(url);
+ return new ModelAndView(url); // $ hasUnsafeUrlForward
}
@GetMapping("/bad2")
public ModelAndView bad2(String url) {
ModelAndView modelAndView = new ModelAndView();
- modelAndView.setViewName(url);
+ modelAndView.setViewName(url); // $ hasUnsafeUrlForward
return modelAndView;
}
@GetMapping("/bad3")
public String bad3(String url) {
- return "forward:" + url + "/swagger-ui/index.html";
+ return "forward:" + url + "/swagger-ui/index.html"; // $ hasUnsafeUrlForward
}
@GetMapping("/bad4")
public ModelAndView bad4(String url) {
- ModelAndView modelAndView = new ModelAndView("forward:" + url);
+ ModelAndView modelAndView = new ModelAndView("forward:" + url); // $ hasUnsafeUrlForward
return modelAndView;
}
@GetMapping("/bad5")
public void bad5(String url, HttpServletRequest request, HttpServletResponse response) {
try {
- request.getRequestDispatcher(url).include(request, response);
+ request.getRequestDispatcher(url).include(request, response); // $ hasUnsafeUrlForward
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
@@ -46,7 +46,7 @@ public class UnsafeUrlForward {
@GetMapping("/bad6")
public void bad6(String url, HttpServletRequest request, HttpServletResponse response) {
try {
- request.getRequestDispatcher("/WEB-INF/jsp/" + url + ".jsp").include(request, response);
+ request.getRequestDispatcher("/WEB-INF/jsp/" + url + ".jsp").include(request, response); // $ hasUnsafeUrlForward
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
@@ -57,7 +57,7 @@ public class UnsafeUrlForward {
@GetMapping("/bad7")
public void bad7(String url, HttpServletRequest request, HttpServletResponse response) {
try {
- request.getRequestDispatcher("/WEB-INF/jsp/" + url + ".jsp").forward(request, response);
+ request.getRequestDispatcher("/WEB-INF/jsp/" + url + ".jsp").forward(request, response); // $ hasUnsafeUrlForward
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.qlref b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.qlref
deleted file mode 100644
index 934a18cc6c7..00000000000
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.qlref
+++ /dev/null
@@ -1 +0,0 @@
-experimental/Security/CWE/CWE-552/UnsafeUrlForward.ql
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.expected b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.expected
new file mode 100644
index 00000000000..8ec8033d086
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.expected
@@ -0,0 +1,2 @@
+testFailures
+failures
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.ql b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.ql
new file mode 100644
index 00000000000..cf77edcf12a
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.ql
@@ -0,0 +1,18 @@
+import java
+import TestUtilities.InlineExpectationsTest
+import semmle.code.java.security.UnsafeUrlForwardQuery
+
+module UnsafeUrlForwardTest implements TestSig {
+ string getARelevantTag() { result = "hasUnsafeUrlForward" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "hasUnsafeUrlForward" and
+ exists(UnsafeUrlForwardFlow::PathNode sink | UnsafeUrlForwardFlow::flowPath(_, sink) |
+ location = sink.getNode().getLocation() and
+ element = sink.getNode().toString() and
+ value = ""
+ )
+ }
+}
+
+import MakeTest
From 915e106ab382aaa060e11b02e34d61c7434452c6 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Mon, 20 Nov 2023 18:10:07 -0500
Subject: [PATCH 041/497] Java: remove path-injection related models and tests
for now
---
...unsafeUrlForwardExperimentalMove.model.yml | 40 +--
.../code/java/security/UnsafeUrlForward.qll | 91 +-----
.../java/security/UnsafeUrlForwardQuery.qll | 24 +-
.../CWE-552/UnsafeLoadSpringResource.java | 155 ----------
.../security/CWE-552/UnsafeResourceGet.java | 270 ------------------
.../security/CWE-552/UnsafeResourceGet2.java | 58 ----
6 files changed, 12 insertions(+), 626 deletions(-)
delete mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeLoadSpringResource.java
delete mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet.java
delete mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet2.java
diff --git a/java/ql/lib/ext/unsafeUrlForwardExperimentalMove.model.yml b/java/ql/lib/ext/unsafeUrlForwardExperimentalMove.model.yml
index b48d891e692..27c1094d765 100644
--- a/java/ql/lib/ext/unsafeUrlForwardExperimentalMove.model.yml
+++ b/java/ql/lib/ext/unsafeUrlForwardExperimentalMove.model.yml
@@ -6,56 +6,18 @@ extensions:
- ["jakarta.servlet.http", "HttpServletRequest", True, "getServletPath", "", "", "ReturnValue", "remote", "manual"]
- ["javax.servlet.http", "HttpServletRequest", True, "getServletPath", "", "", "ReturnValue", "remote", "manual"]
- # # ! below added by me when debugging CVEs:
- # - ["org.springframework.cloud.config.server.resource", "ResourceController", True, "retrieve", "(String,String,String,ServletWebRequest,boolean)", "", "Parameter[3]", "remote", "manual"]
- # - ["org.springframework.web.context.request", "ServletWebRequest", True, "getContextPath", "()", "", "ReturnValue", "remote", "manual"]
-
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["java.util.concurrent", "TimeUnit", True, "sleep", "", "", "Argument[0]", "thread-pause", "manual"] # ! this seems like a typo; doesn't look like it's used in the query at all
- - ["org.springframework.core.io", "ClassPathResource", True, "getFilename", "", "", "Argument[this]", "get-resource", "manual"] # ! Note: `ClassPathResource` implements `Resource`, so it might make more sense to model some of these as `Resource` with subtype True.
- - ["org.springframework.core.io", "ClassPathResource", True, "getPath", "", "", "Argument[this]", "get-resource", "manual"]
- - ["org.springframework.core.io", "ClassPathResource", True, "getURL", "", "", "Argument[this]", "get-resource", "manual"]
- - ["org.springframework.core.io", "ClassPathResource", True, "resolveURL", "", "", "Argument[this]", "get-resource", "manual"]
- # # ! below added by me when debugging CVEs:
- # - ["org.springframework.cloud.config.server.resource", "ResourceController", True, "retrieve", "", "", "Argument[0]", "get-resource", "manual"] # don't need
- # # - ["org.springframework.cloud.config.server.resource", "ResourceController", True, "getFilePath", "", "", "Argument[0..3]", "get-resource", "manual"] # don't need
- # # - ["org.springframework.cloud.config.server.resource", "ResourceRepository", True, "findOne", "", "", "Argument[0..3]", "get-resource", "manual"] # convert to summary
- # # - ["org.springframework.core.io", "InputStreamSource", True, "getInputStream", "", "", "Argument[this]", "get-resource", "manual"] # convert to summary
- # - ["org.springframework.util", "StreamUtils", True, "copyToString", "", "", "Argument[0]", "get-resource", "manual"] # * public class with good docs
- # # - ["org.springframework.cloud.config.server.environment", "SearchPathLocator", True, "getLocations", "(String,String,String)", "", "Argument[0..2]", "get-resource", "manual"] # convert to summary
- # # - ["org.springframework.cloud.config.server.environment", "SearchPathLocator$Locations", True, "getLocations", "()", "", "Argument[this]", "get-resource", "manual"] # convert to summary
- # - ["org.springframework.core.io", "ResourceLoader", True, "getResource", "", "", "Argument[0]", "get-resource", "manual"] # * public interface with good docs, might be problematic for FPs based on fact that the ext contributor changed this to a taint step to avoid "exists" FPS (maybe there's another way to exclude those FPs though).
- # - ["javax.servlet", "ServletContext", True, "getResource", "", "", "Argument[0]", "get-resource", "manual"]
- # - ["javax.servlet", "ServletContext", True, "getResourceAsStream", "", "", "Argument[0]", "get-resource", "manual"]
- # - ["javax.servlet", "ServletContext", True, "getResourcePaths", "", "", "Argument[0]", "get-resource", "manual"]
- # - ["javax.servlet", "ServletContext", True, "getResource", "", "", "Argument[this]", "get-resource", "manual"]
- # - ["javax.servlet", "ServletContext", True, "getResourceAsStream", "", "", "Argument[this]", "get-resource", "manual"]
- # - ["javax.servlet", "ServletContext", True, "getResourcePaths", "", "", "Argument[this]", "get-resource", "manual"]
- # # - ["org.apache.tomcat.util.http", "RequestUtil", True, "normalize", "", "", "Argument[0]", "get-resource", "manual"]
-
- addsTo:
pack: codeql/java-all
extensible: summaryModel
data:
- - ["io.undertow.server.handlers.resource", "Resource", True, "getFile", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- - ["io.undertow.server.handlers.resource", "Resource", True, "getFilePath", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- - ["io.undertow.server.handlers.resource", "Resource", True, "getPath", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] # ! this as a taint step seems to contradict the fact that they did `ClassPathResource.getPath` as a sink for Spring...
- - ["java.nio.file", "Path", True, "normalize", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] # ! shouldn't this be a sanitizer instead??? Or no because WEB-INF ones don't care about normalization?
+ - ["java.nio.file", "Path", True, "normalize", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.nio.file", "Path", True, "resolve", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] # ! check if this and the below are already in the default models
- ["java.nio.file", "Path", True, "resolve", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.nio.file", "Path", True, "toString", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.nio.file", "Paths", True, "get", "", "", "Argument[0..1]", "ReturnValue", "taint", "manual"]
-
- - ["org.springframework.core.io", "ClassPathResource", False, "ClassPathResource", "", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- - ["org.springframework.core.io", "Resource", True, "createRelative", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- # # ! below added/modified by me when debugging CVEs:
- - ["org.springframework.core.io", "ResourceLoader", True, "getResource", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- # - ["org.springframework.cloud.config.server.resource", "ResourceRepository", True, "findOne", "", "", "Argument[0..3]", "ReturnValue", "taint", "manual"] # * public interface, but might be too specific, no easily findable docs...
- # - ["org.springframework.core.io", "InputStreamSource", True, "getInputStream", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] # * public interface with good docs, Note: other `getInputStream`s are remote source and/or taint step, so this as taint step versus sink probably is more consistent
- # - ["org.springframework.cloud.config.server.environment", "SearchPathLocator", True, "getLocations", "(String,String,String)", "", "Argument[0..2]", "ReturnValue", "taint", "manual"] # * public interface with docs: https://www.javadoc.io/static/org.springframework.cloud/spring-cloud-config-server/2.1.0.RELEASE/org/springframework/cloud/config/server/environment/SearchPathLocator.html
- # - ["org.springframework.cloud.config.server.environment", "SearchPathLocator$Locations", True, "getLocations", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] # ! is the `Locations` class package-private? Or does it inherit public from it's enclosing interface?
- # - ["org.springframework.cloud.config.server.resource", "ResourceController", True, "getFilePath", "", "", "Argument[0..3]", "ReturnValue", "taint", "manual"] # don't need
diff --git a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
index 48b4431015e..dd3e17aa832 100644
--- a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
@@ -22,96 +22,7 @@ private class RequestDispatcherSink extends UnsafeUrlForwardSink {
}
}
-/** The `getResource` method of `Class`. */
-class GetClassResourceMethod extends Method {
- GetClassResourceMethod() {
- this.getDeclaringType() instanceof TypeClass and
- this.hasName("getResource")
- }
-}
-
-/** The `getResourceAsStream` method of `Class`. */
-class GetClassResourceAsStreamMethod extends Method {
- GetClassResourceAsStreamMethod() {
- this.getDeclaringType() instanceof TypeClass and
- this.hasName("getResourceAsStream")
- }
-}
-
-/** The `getResource` method of `ClassLoader`. */
-class GetClassLoaderResourceMethod extends Method {
- GetClassLoaderResourceMethod() {
- this.getDeclaringType() instanceof ClassLoaderClass and
- this.hasName("getResource")
- }
-}
-
-/** The `getResourceAsStream` method of `ClassLoader`. */
-class GetClassLoaderResourceAsStreamMethod extends Method {
- GetClassLoaderResourceAsStreamMethod() {
- this.getDeclaringType() instanceof ClassLoaderClass and
- this.hasName("getResourceAsStream")
- }
-}
-
-/** The JBoss class `FileResourceManager`. */
-class FileResourceManager extends RefType {
- FileResourceManager() {
- this.hasQualifiedName("io.undertow.server.handlers.resource", "FileResourceManager")
- }
-}
-
-/** The JBoss method `getResource` of `FileResourceManager`. */
-class GetWildflyResourceMethod extends Method {
- GetWildflyResourceMethod() {
- this.getDeclaringType().getASupertype*() instanceof FileResourceManager and
- this.hasName("getResource")
- }
-}
-
-/** The JBoss class `VirtualFile`. */
-class VirtualFile extends RefType {
- VirtualFile() { this.hasQualifiedName("org.jboss.vfs", "VirtualFile") }
-}
-
-/** The JBoss method `getChild` of `FileResourceManager`. */
-class GetVirtualFileChildMethod extends Method {
- GetVirtualFileChildMethod() {
- this.getDeclaringType().getASupertype*() instanceof VirtualFile and
- this.hasName("getChild")
- }
-}
-
-/** An argument to `getResource()` or `getResourceAsStream()`. */
-private class GetResourceSink extends UnsafeUrlForwardSink {
- GetResourceSink() {
- sinkNode(this, "request-forgery")
- or
- sinkNode(this, "get-resource")
- or
- exists(MethodCall ma |
- (
- ma.getMethod() instanceof GetServletResourceAsStreamMethod or
- ma.getMethod() instanceof GetFacesResourceAsStreamMethod or
- ma.getMethod() instanceof GetClassResourceAsStreamMethod or
- ma.getMethod() instanceof GetClassLoaderResourceAsStreamMethod or
- ma.getMethod() instanceof GetVirtualFileChildMethod
- ) and
- ma.getArgument(0) = this.asExpr()
- )
- }
-}
-
-/** A sink for methods that load Spring resources. */
-private class SpringResourceSink extends UnsafeUrlForwardSink {
- SpringResourceSink() {
- exists(MethodCall ma |
- ma.getMethod() instanceof GetResourceUtilsMethod and
- ma.getArgument(0) = this.asExpr()
- )
- }
-}
-
+// TODO: look into `StaplerResponse.forward`, etc., and think about re-adding the MaD "request-forgery" sinks as a result
/** An argument to `new ModelAndView` or `ModelAndView.setViewName`. */
private class SpringModelAndViewSink extends UnsafeUrlForwardSink {
SpringModelAndViewSink() {
diff --git a/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll b/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
index 9ee3f2ab417..6cd419a5e13 100644
--- a/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
+++ b/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
@@ -1,3 +1,5 @@
+/** Provides configurations to be used in queries related to unsafe URL forwarding. */
+
import java
import semmle.code.java.security.UnsafeUrlForward
import semmle.code.java.dataflow.FlowSources
@@ -5,9 +7,13 @@ import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.Jsf
import semmle.code.java.security.PathSanitizer
+/**
+ * A taint-tracking configuration for untrusted user input in a URL forward or include.
+ */
module UnsafeUrlForwardFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof ThreatModelFlowSource and
+ // TODO: move below logic to class in UnsafeUrlForward.qll?
not exists(MethodCall ma, Method m | ma.getMethod() = m |
(
m instanceof HttpServletRequestGetRequestUriMethod or
@@ -25,21 +31,11 @@ module UnsafeUrlForwardFlowConfig implements DataFlow::ConfigSig {
node instanceof PathInjectionSanitizer
}
+ // TODO: check if the below is still needed after removing path-injection related sinks.
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
-
- predicate isAdditionalFlowStep(DataFlow::Node prev, DataFlow::Node succ) {
- exists(MethodCall ma |
- (
- ma.getMethod() instanceof GetServletResourceMethod or
- ma.getMethod() instanceof GetFacesResourceMethod or
- ma.getMethod() instanceof GetClassResourceMethod or
- ma.getMethod() instanceof GetClassLoaderResourceMethod or
- ma.getMethod() instanceof GetWildflyResourceMethod
- ) and
- ma.getArgument(0) = prev.asExpr() and
- ma = succ.asExpr()
- )
- }
}
+/**
+ * Taint-tracking flow for untrusted user input in a URL forward or include.
+ */
module UnsafeUrlForwardFlow = TaintTracking::Global;
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeLoadSpringResource.java b/java/ql/test/query-tests/security/CWE-552/UnsafeLoadSpringResource.java
deleted file mode 100644
index 363d84cabe9..00000000000
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeLoadSpringResource.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package com.example;
-
-import java.io.File;
-import java.io.FileReader;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.nio.file.Files;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.util.ResourceUtils;
-import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-/** Sample class of Spring RestController */
-@RestController
-public class UnsafeLoadSpringResource {
- @GetMapping("/file1")
- //BAD: Get resource from ClassPathResource without input validation
- public String getFileContent1(@RequestParam(name="fileName") String fileName) {
- // A request such as the following can disclose source code and application configuration
- // fileName=/../../WEB-INF/views/page.jsp
- // fileName=/com/example/package/SampleController.class
- ClassPathResource clr = new ClassPathResource(fileName);
- char[] buffer = new char[4096];
- StringBuilder out = new StringBuilder();
- try {
- Reader in = new FileReader(clr.getFilename()); // $ hasUnsafeUrlForward (path-inj?)
- for (int numRead; (numRead = in.read(buffer, 0, buffer.length)) > 0; ) {
- out.append(buffer, 0, numRead);
- }
- } catch (IOException ie) {
- ie.printStackTrace();
- }
- return out.toString();
- }
-
- @GetMapping("/file1a")
- //GOOD: Get resource from ClassPathResource with input path validation
- public String getFileContent1a(@RequestParam(name="fileName") String fileName) {
- String result = null;
- if (fileName.startsWith("/safe_dir") && !fileName.contains("..")) {
- ClassPathResource clr = new ClassPathResource(fileName);
- char[] buffer = new char[4096];
- StringBuilder out = new StringBuilder();
- try {
- Reader in = new InputStreamReader(clr.getInputStream(), "UTF-8");
- for (int numRead; (numRead = in.read(buffer, 0, buffer.length)) > 0; ) {
- out.append(buffer, 0, numRead);
- }
- } catch (IOException ie) {
- ie.printStackTrace();
- }
- result = out.toString();
- }
- return result;
- }
-
- @GetMapping("/file2")
- //BAD: Get resource from ResourceUtils without input validation
- public String getFileContent2(@RequestParam(name="fileName") String fileName) {
- String content = null;
-
- try {
- // A request such as the following can disclose source code and system configuration
- // fileName=/etc/hosts
- // fileName=file:/etc/hosts
- // fileName=/opt/appdir/WEB-INF/views/page.jsp
- File file = ResourceUtils.getFile(fileName); // $ hasUnsafeUrlForward (path-inj?)
- //Read File Content
- content = new String(Files.readAllBytes(file.toPath()));
- } catch (IOException ie) {
- ie.printStackTrace();
- }
- return content;
- }
-
- @GetMapping("/file2a")
- //GOOD: Get resource from ResourceUtils with input path validation
- public String getFileContent2a(@RequestParam(name="fileName") String fileName) {
- String content = null;
-
- if (fileName.startsWith("/safe_dir") && !fileName.contains("..")) {
- try {
- File file = ResourceUtils.getFile(fileName);
- //Read File Content
- content = new String(Files.readAllBytes(file.toPath()));
- } catch (IOException ie) {
- ie.printStackTrace();
- }
- }
- return content;
- }
-
- @Autowired
- ResourceLoader resourceLoader;
-
- @GetMapping("/file3")
- //BAD: Get resource from ResourceLoader (same as application context) without input validation
- // Note it is not detected without the generic `resource.getInputStream()` check
- public String getFileContent3(@RequestParam(name="fileName") String fileName) {
- String content = null;
-
- try {
- // A request such as the following can disclose source code and system configuration
- // fileName=/WEB-INF/views/page.jsp
- // fileName=/WEB-INF/classes/com/example/package/SampleController.class
- // fileName=file:/etc/hosts
- Resource resource = resourceLoader.getResource(fileName); // $ hasUnsafeUrlForward (path-inj?)
-
- char[] buffer = new char[4096];
- StringBuilder out = new StringBuilder();
-
- Reader in = new InputStreamReader(resource.getInputStream(), "UTF-8");
- for (int numRead; (numRead = in.read(buffer, 0, buffer.length)) > 0; ) {
- out.append(buffer, 0, numRead);
- }
- content = out.toString();
- } catch (IOException ie) {
- ie.printStackTrace();
- }
- return content;
- }
-
- @GetMapping("/file3a")
- //GOOD: Get resource from ResourceLoader (same as application context) with input path validation
- public String getFileContent3a(@RequestParam(name="fileName") String fileName) {
- String content = null;
-
- if (fileName.startsWith("/safe_dir") && !fileName.contains("..")) {
- try {
- Resource resource = resourceLoader.getResource(fileName);
-
- char[] buffer = new char[4096];
- StringBuilder out = new StringBuilder();
-
- Reader in = new InputStreamReader(resource.getInputStream(), "UTF-8");
- for (int numRead; (numRead = in.read(buffer, 0, buffer.length)) > 0; ) {
- out.append(buffer, 0, numRead);
- }
- content = out.toString();
- } catch (IOException ie) {
- ie.printStackTrace();
- }
- }
- return content;
- }
-}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet.java b/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet.java
deleted file mode 100644
index 053887984c6..00000000000
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet.java
+++ /dev/null
@@ -1,270 +0,0 @@
-package com.example;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.net.URI;
-import java.net.URL;
-import java.net.URISyntaxException;
-
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.ServletException;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-
-import io.undertow.server.handlers.resource.FileResourceManager;
-import io.undertow.server.handlers.resource.Resource;
-import org.jboss.vfs.VFS;
-import org.jboss.vfs.VirtualFile;
-
-public class UnsafeResourceGet extends HttpServlet {
- private static final String BASE_PATH = "/pages";
-
- @Override
- // BAD: getResource constructed from `ServletContext` without input validation
- protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestUrl = request.getParameter("requestURL");
- ServletOutputStream out = response.getOutputStream();
-
- ServletConfig cfg = getServletConfig();
- ServletContext sc = cfg.getServletContext();
-
- // A sample request /fake.jsp/../WEB-INF/web.xml can load the web.xml file
- URL url = sc.getResource(requestUrl);
-
- InputStream in = url.openStream(); // $ hasUnsafeUrlForward (SSRF)
- byte[] buf = new byte[4 * 1024]; // 4K buffer
- int bytesRead;
- while ((bytesRead = in.read(buf)) != -1) {
- out.write(buf, 0, bytesRead);
- }
- }
-
- // GOOD: getResource constructed from `ServletContext` with input validation
- protected void doGetGood(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestUrl = request.getParameter("requestURL");
- ServletOutputStream out = response.getOutputStream();
-
- ServletConfig cfg = getServletConfig();
- ServletContext sc = cfg.getServletContext();
-
- Path path = Paths.get(requestUrl).normalize().toRealPath();
- if (path.startsWith(BASE_PATH)) {
- URL url = sc.getResource(path.toString());
-
- InputStream in = url.openStream();
- byte[] buf = new byte[4 * 1024]; // 4K buffer
- int bytesRead;
- while ((bytesRead = in.read(buf)) != -1) {
- out.write(buf, 0, bytesRead);
- }
- }
- }
-
- // GOOD: getResource constructed from `ServletContext` with null check only
- protected void doGetGood2(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestUrl = request.getParameter("requestURL");
- PrintWriter writer = response.getWriter();
-
- ServletConfig cfg = getServletConfig();
- ServletContext sc = cfg.getServletContext();
-
- // A sample request /fake.jsp/../WEB-INF/web.xml can load the web.xml file
- URL url = sc.getResource(requestUrl);
- if (url == null) {
- writer.println("Requested source not found");
- }
- }
-
- // GOOD: getResource constructed from `ServletContext` with `equals` check
- protected void doGetGood3(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestUrl = request.getParameter("requestURL");
- ServletOutputStream out = response.getOutputStream();
-
- ServletContext sc = request.getServletContext();
-
- if (requestUrl.equals("/public/crossdomain.xml")) {
- URL url = sc.getResource(requestUrl);
-
- InputStream in = url.openStream();
- byte[] buf = new byte[4 * 1024]; // 4K buffer
- int bytesRead;
- while ((bytesRead = in.read(buf)) != -1) {
- out.write(buf, 0, bytesRead);
- }
- }
- }
-
- @Override
- // BAD: getResourceAsStream constructed from `ServletContext` without input validation
- protected void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestPath = request.getParameter("requestPath");
- ServletOutputStream out = response.getOutputStream();
-
- // A sample request /fake.jsp/../WEB-INF/web.xml can load the web.xml file
- InputStream in = request.getServletContext().getResourceAsStream(requestPath); // $ hasUnsafeUrlForward (path-inj?)
- byte[] buf = new byte[4 * 1024]; // 4K buffer
- int bytesRead;
- while ((bytesRead = in.read(buf)) != -1) {
- out.write(buf, 0, bytesRead);
- }
- }
-
- // GOOD: getResourceAsStream constructed from `ServletContext` with input validation
- protected void doPostGood(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestPath = request.getParameter("requestPath");
- ServletOutputStream out = response.getOutputStream();
-
- if (!requestPath.contains("..") && requestPath.startsWith("/trusted")) {
- InputStream in = request.getServletContext().getResourceAsStream(requestPath);
- byte[] buf = new byte[4 * 1024]; // 4K buffer
- int bytesRead;
- while ((bytesRead = in.read(buf)) != -1) {
- out.write(buf, 0, bytesRead);
- }
- }
- }
-
- @Override
- // BAD: getResource constructed from `Class` without input validation
- protected void doHead(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestUrl = request.getParameter("requestURL");
- ServletOutputStream out = response.getOutputStream();
-
- // A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file
- // Note the class is in two levels of subpackages and `Class.getResource` starts from its own directory
- URL url = getClass().getResource(requestUrl);
-
- InputStream in = url.openStream(); // $ hasUnsafeUrlForward (SSRF)
- byte[] buf = new byte[4 * 1024]; // 4K buffer
- int bytesRead;
- while ((bytesRead = in.read(buf)) != -1) {
- out.write(buf, 0, bytesRead);
- }
- }
-
- // GOOD: getResource constructed from `Class` with input validation
- protected void doHeadGood(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestUrl = request.getParameter("requestURL");
- ServletOutputStream out = response.getOutputStream();
-
- Path path = Paths.get(requestUrl).normalize().toRealPath();
- if (path.startsWith(BASE_PATH)) {
- URL url = getClass().getResource(path.toString());
-
- InputStream in = url.openStream();
- byte[] buf = new byte[4 * 1024]; // 4K buffer
- int bytesRead;
- while ((bytesRead = in.read(buf)) != -1) {
- out.write(buf, 0, bytesRead);
- }
- }
- }
-
- @Override
- // BAD: getResourceAsStream constructed from `ClassLoader` without input validation
- protected void doPut(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestPath = request.getParameter("requestPath");
- ServletOutputStream out = response.getOutputStream();
-
- ServletConfig cfg = getServletConfig();
- ServletContext sc = cfg.getServletContext();
-
- // A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file
- // Note the class is in two levels of subpackages and `ClassLoader.getResourceAsStream` starts from its own directory
- InputStream in = getClass().getClassLoader().getResourceAsStream(requestPath); // $ hasUnsafeUrlForward (path-inj?)
- byte[] buf = new byte[4 * 1024]; // 4K buffer
- int bytesRead;
- while ((bytesRead = in.read(buf)) != -1) {
- out.write(buf, 0, bytesRead);
- }
- }
-
- // GOOD: getResourceAsStream constructed from `ClassLoader` with input validation
- protected void doPutGood(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestPath = request.getParameter("requestPath");
- ServletOutputStream out = response.getOutputStream();
-
- ServletConfig cfg = getServletConfig();
- ServletContext sc = cfg.getServletContext();
-
- if (!requestPath.contains("..") && requestPath.startsWith("/trusted")) {
- InputStream in = getClass().getClassLoader().getResourceAsStream(requestPath);
- byte[] buf = new byte[4 * 1024]; // 4K buffer
- int bytesRead;
- while ((bytesRead = in.read(buf)) != -1) {
- out.write(buf, 0, bytesRead);
- }
- }
- }
-
- // BAD: getResource constructed from `ClassLoader` without input validation
- protected void doPutBad(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestUrl = request.getParameter("requestURL");
- ServletOutputStream out = response.getOutputStream();
-
- // A sample request /fake.jsp/../../../WEB-INF/web.xml can load the web.xml file
- // Note the class is in two levels of subpackages and `ClassLoader.getResource` starts from its own directory
- URL url = getClass().getClassLoader().getResource(requestUrl);
-
- InputStream in = url.openStream(); // $ hasUnsafeUrlForward (SSRF)
- byte[] buf = new byte[4 * 1024]; // 4K buffer
- int bytesRead;
- while ((bytesRead = in.read(buf)) != -1) {
- out.write(buf, 0, bytesRead);
- }
- }
-
- // BAD: getResource constructed using Undertow IO without input validation
- protected void doPutBad2(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestPath = request.getParameter("requestPath");
-
- try {
- FileResourceManager rm = new FileResourceManager(VFS.getChild(new URI("/usr/share")).getPhysicalFile());
- Resource rs = rm.getResource(requestPath);
-
- VirtualFile overlay = VFS.getChild(new URI("EAP_HOME/modules/"));
- // Do file operations
- overlay.getChild(rs.getPath()); // $ hasUnsafeUrlForward (path-inj?)
- } catch (URISyntaxException ue) {
- throw new IOException("Cannot parse the URI");
- }
- }
-
- // GOOD: getResource constructed using Undertow IO with input validation
- protected void doPutGood2(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String requestPath = request.getParameter("requestPath");
-
- try {
- FileResourceManager rm = new FileResourceManager(VFS.getChild(new URI("/usr/share")).getPhysicalFile());
- Resource rs = rm.getResource(requestPath);
-
- VirtualFile overlay = VFS.getChild(new URI("EAP_HOME/modules/"));
- String path = rs.getPath();
- if (path.startsWith("/trusted_path") && !path.contains("..")) {
- // Do file operations
- overlay.getChild(path);
- }
- } catch (URISyntaxException ue) {
- throw new IOException("Cannot parse the URI");
- }
- }
-}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet2.java b/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet2.java
deleted file mode 100644
index 0043bb06c67..00000000000
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeResourceGet2.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.example;
-
-import javax.faces.context.FacesContext;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Map;
-
-/** Sample class of JSF managed bean */
-public class UnsafeResourceGet2 {
- // BAD: getResourceAsStream constructed from `ExternalContext` without input validation
- public String parameterActionBad1() throws IOException {
- FacesContext fc = FacesContext.getCurrentInstance();
- Map params = fc.getExternalContext().getRequestParameterMap();
- String loadUrl = params.get("loadUrl");
-
- InputStreamReader isr = new InputStreamReader(fc.getExternalContext().getResourceAsStream(loadUrl)); // $ hasUnsafeUrlForward (path-inj?)
- BufferedReader br = new BufferedReader(isr);
- if(br.ready()) {
- //Do Stuff
- return "result";
- }
-
- return "home";
- }
-
- // BAD: getResource constructed from `ExternalContext` without input validation
- public String parameterActionBad2() throws IOException {
- FacesContext fc = FacesContext.getCurrentInstance();
- Map params = fc.getExternalContext().getRequestParameterMap();
- String loadUrl = params.get("loadUrl");
-
- URL url = fc.getExternalContext().getResource(loadUrl);
-
- InputStream in = url.openStream(); // $ hasUnsafeUrlForward (SSRF)
- //Do Stuff
- return "result";
- }
-
- // GOOD: getResource constructed from `ExternalContext` with input validation
- public String parameterActionGood1() throws IOException {
- FacesContext fc = FacesContext.getCurrentInstance();
- Map params = fc.getExternalContext().getRequestParameterMap();
- String loadUrl = params.get("loadUrl");
-
- if (loadUrl.equals("/public/crossdomain.xml")) {
- URL url = fc.getExternalContext().getResource(loadUrl);
-
- InputStream in = url.openStream();
- //Do Stuff
- return "result";
- }
-
- return "home";
- }
-}
From 2a682995aeadbb919d4c400b916c7737fae0b150 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Thu, 30 Nov 2023 11:16:39 -0500
Subject: [PATCH 042/497] Java: move MaD models to correct files, delete ones
that already exist
---
.../ql/lib/ext/jakarta.servlet.http.model.yml | 6 +++++
java/ql/lib/ext/javax.servlet.http.model.yml | 2 ++
...unsafeUrlForwardExperimentalMove.model.yml | 23 -------------------
3 files changed, 8 insertions(+), 23 deletions(-)
create mode 100644 java/ql/lib/ext/jakarta.servlet.http.model.yml
delete mode 100644 java/ql/lib/ext/unsafeUrlForwardExperimentalMove.model.yml
diff --git a/java/ql/lib/ext/jakarta.servlet.http.model.yml b/java/ql/lib/ext/jakarta.servlet.http.model.yml
new file mode 100644
index 00000000000..5a83b1ac08d
--- /dev/null
+++ b/java/ql/lib/ext/jakarta.servlet.http.model.yml
@@ -0,0 +1,6 @@
+extensions:
+ - addsTo:
+ pack: codeql/java-all
+ extensible: sourceModel
+ data:
+ - ["jakarta.servlet.http", "HttpServletRequest", True, "getServletPath", "", "", "ReturnValue", "remote", "manual"]
diff --git a/java/ql/lib/ext/javax.servlet.http.model.yml b/java/ql/lib/ext/javax.servlet.http.model.yml
index afac25e4bc8..ec35445d199 100644
--- a/java/ql/lib/ext/javax.servlet.http.model.yml
+++ b/java/ql/lib/ext/javax.servlet.http.model.yml
@@ -18,6 +18,8 @@ extensions:
- ["javax.servlet.http", "HttpServletRequest", False, "getRemoteUser", "()", "", "ReturnValue", "remote", "manual"]
- ["javax.servlet.http", "HttpServletRequest", False, "getRequestURI", "()", "", "ReturnValue", "remote", "manual"]
- ["javax.servlet.http", "HttpServletRequest", False, "getRequestURL", "()", "", "ReturnValue", "remote", "manual"]
+ - ["javax.servlet.http", "HttpServletRequest", False, "getServletPath", "()", "", "ReturnValue", "remote", "manual"]
+
- addsTo:
pack: codeql/java-all
extensible: sinkModel
diff --git a/java/ql/lib/ext/unsafeUrlForwardExperimentalMove.model.yml b/java/ql/lib/ext/unsafeUrlForwardExperimentalMove.model.yml
deleted file mode 100644
index 27c1094d765..00000000000
--- a/java/ql/lib/ext/unsafeUrlForwardExperimentalMove.model.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-extensions:
- - addsTo:
- pack: codeql/java-all
- extensible: sourceModel
- data:
- - ["jakarta.servlet.http", "HttpServletRequest", True, "getServletPath", "", "", "ReturnValue", "remote", "manual"]
- - ["javax.servlet.http", "HttpServletRequest", True, "getServletPath", "", "", "ReturnValue", "remote", "manual"]
-
- - addsTo:
- pack: codeql/java-all
- extensible: sinkModel
- data:
- - ["java.util.concurrent", "TimeUnit", True, "sleep", "", "", "Argument[0]", "thread-pause", "manual"] # ! this seems like a typo; doesn't look like it's used in the query at all
-
- - addsTo:
- pack: codeql/java-all
- extensible: summaryModel
- data:
- - ["java.nio.file", "Path", True, "normalize", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- - ["java.nio.file", "Path", True, "resolve", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] # ! check if this and the below are already in the default models
- - ["java.nio.file", "Path", True, "resolve", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- - ["java.nio.file", "Path", True, "toString", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- - ["java.nio.file", "Paths", True, "get", "", "", "Argument[0..1]", "ReturnValue", "taint", "manual"]
From 4ff884e26cad54486745861fe1145c6539418f8c Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Thu, 30 Nov 2023 11:31:39 -0500
Subject: [PATCH 043/497] Java: remove more path-injection related classes
(will maybe add some of these back in a separate PR)
---
java/ql/lib/semmle/code/java/Jsf.qll | 35 -------------------
.../lib/semmle/code/java/SpringResource.qll | 22 ------------
.../code/java/security/UnsafeUrlForward.qll | 2 --
.../java/security/UnsafeUrlForwardQuery.qll | 1 -
4 files changed, 60 deletions(-)
delete mode 100644 java/ql/lib/semmle/code/java/Jsf.qll
delete mode 100644 java/ql/lib/semmle/code/java/SpringResource.qll
diff --git a/java/ql/lib/semmle/code/java/Jsf.qll b/java/ql/lib/semmle/code/java/Jsf.qll
deleted file mode 100644
index 9023953add4..00000000000
--- a/java/ql/lib/semmle/code/java/Jsf.qll
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Provides classes and predicates for working with the Java Server Faces (JSF).
- */
-
-// TODO: COMBINE WITH EXISTING JSF-RELATED QLL FILES!
-import java
-
-/**
- * The JSF class `ExternalContext` for processing HTTP requests.
- */
-class ExternalContext extends RefType {
- ExternalContext() {
- this.hasQualifiedName(["javax.faces.context", "jakarta.faces.context"], "ExternalContext")
- }
-}
-
-/**
- * The method `getResource()` declared in JSF `ExternalContext`.
- */
-class GetFacesResourceMethod extends Method {
- GetFacesResourceMethod() {
- this.getDeclaringType().getASupertype*() instanceof ExternalContext and
- this.hasName("getResource")
- }
-}
-
-/**
- * The method `getResourceAsStream()` declared in JSF `ExternalContext`.
- */
-class GetFacesResourceAsStreamMethod extends Method {
- GetFacesResourceAsStreamMethod() {
- this.getDeclaringType().getASupertype*() instanceof ExternalContext and
- this.hasName("getResourceAsStream")
- }
-}
diff --git a/java/ql/lib/semmle/code/java/SpringResource.qll b/java/ql/lib/semmle/code/java/SpringResource.qll
deleted file mode 100644
index a7d3a3793b6..00000000000
--- a/java/ql/lib/semmle/code/java/SpringResource.qll
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * Provides classes for working with resource loading in Spring.
- */
-
-// TODO: COMBINE WITH EXISTING SPRING-RELATED QLL FILES!
-import java
-private import semmle.code.java.dataflow.FlowSources
-
-/** A utility class for resolving resource locations to files in the file system in the Spring framework. */
-class ResourceUtils extends Class {
- ResourceUtils() { this.hasQualifiedName("org.springframework.util", "ResourceUtils") }
-}
-
-/**
- * A method declared in `org.springframework.util.ResourceUtils` that loads Spring resources.
- */
-class GetResourceUtilsMethod extends Method {
- GetResourceUtilsMethod() {
- this.getDeclaringType().getASupertype*() instanceof ResourceUtils and
- this.hasName(["extractArchiveURL", "extractJarFileURL", "getFile", "getURL"])
- }
-}
diff --git a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
index dd3e17aa832..628397d07ef 100644
--- a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
@@ -1,10 +1,8 @@
import java
-private import semmle.code.java.Jsf
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.StringPrefixes
private import semmle.code.java.frameworks.javaee.ejb.EJBRestrictions
-private import semmle.code.java.SpringResource
/** A sink for unsafe URL forward vulnerabilities. */
abstract class UnsafeUrlForwardSink extends DataFlow::Node { }
diff --git a/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll b/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
index 6cd419a5e13..4231af1a90a 100644
--- a/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
+++ b/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
@@ -4,7 +4,6 @@ import java
import semmle.code.java.security.UnsafeUrlForward
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
-import semmle.code.java.Jsf
import semmle.code.java.security.PathSanitizer
/**
From 42e3825ea3b50ee362ae723c657744de85860e5e Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 5 Mar 2024 11:55:54 -0500
Subject: [PATCH 044/497] Java: convert RequestDispatcherSink to MaD
---
java/ql/lib/ext/jakarta.servlet.model.yml | 8 ++++++++
java/ql/lib/ext/javax.portlet.model.yml | 7 +++++++
java/ql/lib/ext/javax.servlet.model.yml | 3 +++
.../semmle/code/java/security/UnsafeUrlForward.qll | 11 +++--------
4 files changed, 21 insertions(+), 8 deletions(-)
create mode 100644 java/ql/lib/ext/jakarta.servlet.model.yml
create mode 100644 java/ql/lib/ext/javax.portlet.model.yml
diff --git a/java/ql/lib/ext/jakarta.servlet.model.yml b/java/ql/lib/ext/jakarta.servlet.model.yml
new file mode 100644
index 00000000000..fc1274cadaf
--- /dev/null
+++ b/java/ql/lib/ext/jakarta.servlet.model.yml
@@ -0,0 +1,8 @@
+extensions:
+ - addsTo:
+ pack: codeql/java-all
+ extensible: sinkModel
+ data:
+ # TODO: potentially switch to using Argument[this] of `RequestDispatcher.forward|include` as sink instead of the below.
+ - ["jakarta.servlet", "ServletContext", True, "getRequestDispatcher", "(String)", "", "Argument[0]", "url-forward", "manual"]
+ - ["jakarta.servlet", "ServletRequest", True, "getRequestDispatcher", "(String)", "", "Argument[0]", "url-forward", "manual"]
diff --git a/java/ql/lib/ext/javax.portlet.model.yml b/java/ql/lib/ext/javax.portlet.model.yml
new file mode 100644
index 00000000000..e39484abcb7
--- /dev/null
+++ b/java/ql/lib/ext/javax.portlet.model.yml
@@ -0,0 +1,7 @@
+extensions:
+ - addsTo:
+ pack: codeql/java-all
+ extensible: sinkModel
+ data:
+ # TODO: potentially switch to using Argument[this] of `PortletRequestDispatcher.forward|include` as sink instead of the below.
+ - ["javax.portlet", "PortletContext", True, "getRequestDispatcher", "(String)", "", "Argument[0]", "url-forward", "manual"]
diff --git a/java/ql/lib/ext/javax.servlet.model.yml b/java/ql/lib/ext/javax.servlet.model.yml
index 581863c74f7..7c405ac0de9 100644
--- a/java/ql/lib/ext/javax.servlet.model.yml
+++ b/java/ql/lib/ext/javax.servlet.model.yml
@@ -14,6 +14,9 @@ extensions:
extensible: sinkModel
data:
- ["javax.servlet", "ServletContext", True, "getResourceAsStream", "(String)", "", "Argument[0]", "path-injection", "ai-manual"]
+ # TODO: potentially switch to using Argument[this] of `RequestDispatcher.forward|include` as sink instead of the below.
+ - ["javax.servlet", "ServletContext", True, "getRequestDispatcher", "(String)", "", "Argument[0]", "url-forward", "manual"]
+ - ["javax.servlet", "ServletRequest", True, "getRequestDispatcher", "(String)", "", "Argument[0]", "url-forward", "manual"]
- addsTo:
pack: codeql/java-all
extensible: summaryModel
diff --git a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
index 628397d07ef..e7780ee971b 100644
--- a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
@@ -10,14 +10,9 @@ abstract class UnsafeUrlForwardSink extends DataFlow::Node { }
/** A sanitizer for unsafe URL forward vulnerabilities. */
abstract class UnsafeUrlForwardSanitizer extends DataFlow::Node { }
-/** An argument to `getRequestDispatcher`. */
-private class RequestDispatcherSink extends UnsafeUrlForwardSink {
- RequestDispatcherSink() {
- exists(MethodCall ma |
- ma.getMethod() instanceof GetRequestDispatcherMethod and
- ma.getArgument(0) = this.asExpr()
- )
- }
+/** A default sink representing methods susceptible to unsafe URL forwarding. */
+private class DefaultUnsafeUrlForwardSink extends UnsafeUrlForwardSink {
+ DefaultUnsafeUrlForwardSink() { sinkNode(this, "url-forward") }
}
// TODO: look into `StaplerResponse.forward`, etc., and think about re-adding the MaD "request-forgery" sinks as a result
From 8d66097483a8892d4a15c2232e63d883035a45f9 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Thu, 30 Nov 2023 13:50:51 -0500
Subject: [PATCH 045/497] Java: switch StaplerResponse.forward from
request-forgery sink to url-forward sink
---
java/ql/lib/ext/org.kohsuke.stapler.model.yml | 2 +-
java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/java/ql/lib/ext/org.kohsuke.stapler.model.yml b/java/ql/lib/ext/org.kohsuke.stapler.model.yml
index 63bbdbfd52a..ca9f08ba78c 100644
--- a/java/ql/lib/ext/org.kohsuke.stapler.model.yml
+++ b/java/ql/lib/ext/org.kohsuke.stapler.model.yml
@@ -9,7 +9,7 @@ extensions:
- ["org.kohsuke.stapler", "HttpResponses", True, "staticResource", "(URL,long)", "", "Argument[0]", "request-forgery", "manual"]
- ["org.kohsuke.stapler", "HttpResponses", True, "html", "(String)", "", "Argument[0]", "html-injection", "manual"]
- ["org.kohsuke.stapler", "HttpResponses", True, "literalHtml", "(String)", "", "Argument[0]", "html-injection", "manual"]
- - ["org.kohsuke.stapler", "StaplerResponse", True, "forward", "(Object,String,StaplerRequest)", "", "Argument[1]", "request-forgery", "manual"]
+ - ["org.kohsuke.stapler", "StaplerResponse", True, "forward", "(Object,String,StaplerRequest)", "", "Argument[1]", "url-forward", "manual"]
- ["org.kohsuke.stapler", "StaplerResponse", True, "sendRedirect2", "(String)", "", "Argument[0]", "url-redirection", "manual"]
- ["org.kohsuke.stapler", "StaplerResponse", True, "sendRedirect", "(int,String)", "", "Argument[1]", "url-redirection", "manual"]
- ["org.kohsuke.stapler", "StaplerResponse", True, "sendRedirect", "(String)", "", "Argument[0]", "url-redirection", "manual"]
diff --git a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
index e7780ee971b..0e96066c72e 100644
--- a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
@@ -15,7 +15,6 @@ private class DefaultUnsafeUrlForwardSink extends UnsafeUrlForwardSink {
DefaultUnsafeUrlForwardSink() { sinkNode(this, "url-forward") }
}
-// TODO: look into `StaplerResponse.forward`, etc., and think about re-adding the MaD "request-forgery" sinks as a result
/** An argument to `new ModelAndView` or `ModelAndView.setViewName`. */
private class SpringModelAndViewSink extends UnsafeUrlForwardSink {
SpringModelAndViewSink() {
From 1da1e896cbc8eb1b918c8c4950010b53146391a6 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 5 Mar 2024 12:25:19 -0500
Subject: [PATCH 046/497] Java: convert SpringModelAndViewSink to MaD
---
.../ext/org.springframework.web.portlet.model.yml | 7 +++++++
.../ext/org.springframework.web.servlet.model.yml | 7 +++++++
.../semmle/code/java/security/UnsafeUrlForward.qll | 12 ------------
shared/mad/codeql/mad/ModelValidation.qll | 4 ++--
4 files changed, 16 insertions(+), 14 deletions(-)
create mode 100644 java/ql/lib/ext/org.springframework.web.portlet.model.yml
create mode 100644 java/ql/lib/ext/org.springframework.web.servlet.model.yml
diff --git a/java/ql/lib/ext/org.springframework.web.portlet.model.yml b/java/ql/lib/ext/org.springframework.web.portlet.model.yml
new file mode 100644
index 00000000000..ba90b531c33
--- /dev/null
+++ b/java/ql/lib/ext/org.springframework.web.portlet.model.yml
@@ -0,0 +1,7 @@
+extensions:
+ - addsTo:
+ pack: codeql/java-all
+ extensible: sinkModel
+ data:
+ - ["org.springframework.web.portlet", "ModelAndView", False, "ModelAndView", "", "", "Argument[0]", "url-forward", "manual"]
+ - ["org.springframework.web.portlet", "ModelAndView", False, "setViewName", "", "", "Argument[0]", "url-forward", "manual"]
diff --git a/java/ql/lib/ext/org.springframework.web.servlet.model.yml b/java/ql/lib/ext/org.springframework.web.servlet.model.yml
new file mode 100644
index 00000000000..acdda3d569f
--- /dev/null
+++ b/java/ql/lib/ext/org.springframework.web.servlet.model.yml
@@ -0,0 +1,7 @@
+extensions:
+ - addsTo:
+ pack: codeql/java-all
+ extensible: sinkModel
+ data:
+ - ["org.springframework.web.servlet", "ModelAndView", False, "ModelAndView", "", "", "Argument[0]", "url-forward", "manual"]
+ - ["org.springframework.web.servlet", "ModelAndView", False, "setViewName", "", "", "Argument[0]", "url-forward", "manual"]
diff --git a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
index 0e96066c72e..cd65a6f6345 100644
--- a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
@@ -15,18 +15,6 @@ private class DefaultUnsafeUrlForwardSink extends UnsafeUrlForwardSink {
DefaultUnsafeUrlForwardSink() { sinkNode(this, "url-forward") }
}
-/** An argument to `new ModelAndView` or `ModelAndView.setViewName`. */
-private class SpringModelAndViewSink extends UnsafeUrlForwardSink {
- SpringModelAndViewSink() {
- exists(ClassInstanceExpr cie |
- cie.getConstructedType() instanceof ModelAndView and
- cie.getArgument(0) = this.asExpr()
- )
- or
- exists(SpringModelAndViewSetViewNameCall smavsvnc | smavsvnc.getArgument(0) = this.asExpr())
- }
-}
-
private class PrimitiveSanitizer extends UnsafeUrlForwardSanitizer {
PrimitiveSanitizer() {
this.getType() instanceof PrimitiveType or
diff --git a/shared/mad/codeql/mad/ModelValidation.qll b/shared/mad/codeql/mad/ModelValidation.qll
index bb3b8c174b9..20bcdd1908c 100644
--- a/shared/mad/codeql/mad/ModelValidation.qll
+++ b/shared/mad/codeql/mad/ModelValidation.qll
@@ -33,8 +33,8 @@ module KindValidation {
"bean-validation", "fragment-injection", "groovy-injection", "hostname-verification",
"information-leak", "intent-redirection", "jexl-injection", "jndi-injection",
"mvel-injection", "notification", "ognl-injection", "pending-intents",
- "response-splitting", "trust-boundary-violation", "template-injection", "xpath-injection",
- "xslt-injection",
+ "response-splitting", "trust-boundary-violation", "template-injection", "url-forward",
+ "xpath-injection", "xslt-injection",
// JavaScript-only currently, but may be shared in the future
"mongodb.sink", "nosql-injection", "unsafe-deserialization",
// Swift-only currently, but may be shared in the future
From 5a9d7552b3d92aba8cdee9a75ea95c02819bb4cf Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Thu, 30 Nov 2023 16:05:59 -0500
Subject: [PATCH 047/497] Java: add some comments and minor code reorg
---
.../code/java/security/UnsafeUrlForward.qll | 54 ++++++++++---------
.../java/security/UnsafeUrlForwardQuery.qll | 2 +-
2 files changed, 30 insertions(+), 26 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
index cd65a6f6345..4a529896f86 100644
--- a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
@@ -1,20 +1,40 @@
+/** Provides classes related to unsafe URL forwarding in Java. */
+
import java
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.StringPrefixes
-private import semmle.code.java.frameworks.javaee.ejb.EJBRestrictions
/** A sink for unsafe URL forward vulnerabilities. */
abstract class UnsafeUrlForwardSink extends DataFlow::Node { }
-/** A sanitizer for unsafe URL forward vulnerabilities. */
-abstract class UnsafeUrlForwardSanitizer extends DataFlow::Node { }
-
/** A default sink representing methods susceptible to unsafe URL forwarding. */
private class DefaultUnsafeUrlForwardSink extends UnsafeUrlForwardSink {
DefaultUnsafeUrlForwardSink() { sinkNode(this, "url-forward") }
}
+/**
+ * An expression appended (perhaps indirectly) to `"forward:"`, and which
+ * is reachable from a Spring entry point.
+ */
+private class SpringUrlForwardSink extends UnsafeUrlForwardSink {
+ SpringUrlForwardSink() {
+ // TODO: check if can use MaD "Annotated" for `SpringRequestMappingMethod` or if too complicated for MaD (probably too complicated).
+ any(SpringRequestMappingMethod sqmm).polyCalls*(this.getEnclosingCallable()) and
+ this.asExpr() = any(ForwardPrefix fp).getAnAppendedExpression()
+ }
+}
+
+// TODO: should this potentially be "include:" as well? Or does that not work similarly?
+private class ForwardPrefix extends InterestingPrefix {
+ ForwardPrefix() { this.getStringValue() = "forward:" }
+
+ override int getOffset() { result = 0 }
+}
+
+/** A sanitizer for unsafe URL forward vulnerabilities. */
+abstract class UnsafeUrlForwardSanitizer extends DataFlow::Node { }
+
private class PrimitiveSanitizer extends UnsafeUrlForwardSanitizer {
PrimitiveSanitizer() {
this.getType() instanceof PrimitiveType or
@@ -23,6 +43,11 @@ private class PrimitiveSanitizer extends UnsafeUrlForwardSanitizer {
}
}
+// TODO: double-check this sanitizer (and should I switch all "sanitizer" naming to "barrier" instead?)
+private class FollowsSanitizingPrefix extends UnsafeUrlForwardSanitizer {
+ FollowsSanitizingPrefix() { this.asExpr() = any(SanitizingPrefix fp).getAnAppendedExpression() }
+}
+
private class SanitizingPrefix extends InterestingPrefix {
SanitizingPrefix() {
not this.getStringValue().matches("/WEB-INF/%") and
@@ -31,24 +56,3 @@ private class SanitizingPrefix extends InterestingPrefix {
override int getOffset() { result = 0 }
}
-
-private class FollowsSanitizingPrefix extends UnsafeUrlForwardSanitizer {
- FollowsSanitizingPrefix() { this.asExpr() = any(SanitizingPrefix fp).getAnAppendedExpression() }
-}
-
-private class ForwardPrefix extends InterestingPrefix {
- ForwardPrefix() { this.getStringValue() = "forward:" }
-
- override int getOffset() { result = 0 }
-}
-
-/**
- * An expression appended (perhaps indirectly) to `"forward:"`, and which
- * is reachable from a Spring entry point.
- */
-private class SpringUrlForwardSink extends UnsafeUrlForwardSink {
- SpringUrlForwardSink() {
- any(SpringRequestMappingMethod sqmm).polyCalls*(this.getEnclosingCallable()) and
- this.asExpr() = any(ForwardPrefix fp).getAnAppendedExpression()
- }
-}
diff --git a/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll b/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
index 4231af1a90a..49670234582 100644
--- a/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
+++ b/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
@@ -12,7 +12,7 @@ import semmle.code.java.security.PathSanitizer
module UnsafeUrlForwardFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof ThreatModelFlowSource and
- // TODO: move below logic to class in UnsafeUrlForward.qll?
+ // TODO: move below logic to class in UnsafeUrlForward.qll? And check exactly why these were excluded.
not exists(MethodCall ma, Method m | ma.getMethod() = m |
(
m instanceof HttpServletRequestGetRequestUriMethod or
From 6e7c05467bddf44f0411920392b6886f680c5ecf Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Fri, 1 Dec 2023 08:29:17 -0500
Subject: [PATCH 048/497] Java: update query metadata and alert message
---
.../Security/CWE/CWE-552/UnsafeUrlForward.ql | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql b/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql
index 4e3326a831e..06686d5e0bd 100644
--- a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql
+++ b/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql
@@ -1,13 +1,16 @@
/**
- * @name Unsafe URL forward or include from a remote source
- * @description URL forward or include based on unvalidated user-input
- * may cause file information disclosure.
+ * @name URL forward from a remote source
+ * @description URL forward based on unvalidated user-input
+ * may cause file information disclosure or
+ * redirection to malicious web sites.
* @kind path-problem
* @problem.severity error
+ * @security-severity 6.1
* @precision high
- * @id java/unsafe-url-forward-include
+ * @id java/unvalidated-url-forward
* @tags security
- * external/cwe-552
+ * external/cwe/cwe-552
+ * external/cwe/cwe-601
*/
import java
@@ -16,5 +19,5 @@ import UnsafeUrlForwardFlow::PathGraph
from UnsafeUrlForwardFlow::PathNode source, UnsafeUrlForwardFlow::PathNode sink
where UnsafeUrlForwardFlow::flowPath(source, sink)
-select sink.getNode(), source, sink, "Potentially untrusted URL forward due to $@.",
- source.getNode(), "user-provided value"
+select sink.getNode(), source, sink, "Untrusted URL forward depends on a $@.", source.getNode(),
+ "user-provided value"
From 09bc21dbd36e4f0e4ab954d5f691bc440b2cb0c5 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Fri, 1 Dec 2023 08:56:20 -0500
Subject: [PATCH 049/497] Java: rename 'UnsafeUrlForward' to 'UrlForward'
---
.../{UnsafeUrlForward.qll => UrlForward.qll} | 22 +++++++++----------
...rlForwardQuery.qll => UrlForwardQuery.qll} | 18 +++++++--------
...{UnsafeUrlForward.java => UrlForward.java} | 2 +-
...nsafeUrlForward.qhelp => UrlForward.qhelp} | 2 +-
.../{UnsafeUrlForward.ql => UrlForward.ql} | 8 +++----
.../security/CWE-552/UnsafeRequestPath.java | 2 +-
.../CWE-552/UnsafeServletRequestDispatch.java | 8 +++----
.../security/CWE-552/UnsafeUrlForwardTest.ql | 18 ---------------
...dTest.expected => UrlForwardTest.expected} | 0
...afeUrlForward.java => UrlForwardTest.java} | 16 +++++++-------
.../security/CWE-552/UrlForwardTest.ql | 18 +++++++++++++++
11 files changed, 57 insertions(+), 57 deletions(-)
rename java/ql/lib/semmle/code/java/security/{UnsafeUrlForward.qll => UrlForward.qll} (66%)
rename java/ql/lib/semmle/code/java/security/{UnsafeUrlForwardQuery.qll => UrlForwardQuery.qll} (55%)
rename java/ql/src/Security/CWE/CWE-552/{UnsafeUrlForward.java => UrlForward.java} (97%)
rename java/ql/src/Security/CWE/CWE-552/{UnsafeUrlForward.qhelp => UrlForward.qhelp} (98%)
rename java/ql/src/Security/CWE/CWE-552/{UnsafeUrlForward.ql => UrlForward.ql} (71%)
delete mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.ql
rename java/ql/test/query-tests/security/CWE-552/{UnsafeUrlForwardTest.expected => UrlForwardTest.expected} (100%)
rename java/ql/test/query-tests/security/CWE-552/{UnsafeUrlForward.java => UrlForwardTest.java} (83%)
create mode 100644 java/ql/test/query-tests/security/CWE-552/UrlForwardTest.ql
diff --git a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
similarity index 66%
rename from java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
rename to java/ql/lib/semmle/code/java/security/UrlForward.qll
index 4a529896f86..aa21ed48aba 100644
--- a/java/ql/lib/semmle/code/java/security/UnsafeUrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -1,23 +1,23 @@
-/** Provides classes related to unsafe URL forwarding in Java. */
+/** Provides classes to reason about URL forward attacks. */
import java
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.StringPrefixes
-/** A sink for unsafe URL forward vulnerabilities. */
-abstract class UnsafeUrlForwardSink extends DataFlow::Node { }
+/** A URL forward sink. */
+abstract class UrlForwardSink extends DataFlow::Node { }
-/** A default sink representing methods susceptible to unsafe URL forwarding. */
-private class DefaultUnsafeUrlForwardSink extends UnsafeUrlForwardSink {
- DefaultUnsafeUrlForwardSink() { sinkNode(this, "url-forward") }
+/** A default sink representing methods susceptible to URL forwarding attacks. */
+private class DefaultUrlForwardSink extends UrlForwardSink {
+ DefaultUrlForwardSink() { sinkNode(this, "url-forward") }
}
/**
* An expression appended (perhaps indirectly) to `"forward:"`, and which
* is reachable from a Spring entry point.
*/
-private class SpringUrlForwardSink extends UnsafeUrlForwardSink {
+private class SpringUrlForwardSink extends UrlForwardSink {
SpringUrlForwardSink() {
// TODO: check if can use MaD "Annotated" for `SpringRequestMappingMethod` or if too complicated for MaD (probably too complicated).
any(SpringRequestMappingMethod sqmm).polyCalls*(this.getEnclosingCallable()) and
@@ -32,10 +32,10 @@ private class ForwardPrefix extends InterestingPrefix {
override int getOffset() { result = 0 }
}
-/** A sanitizer for unsafe URL forward vulnerabilities. */
-abstract class UnsafeUrlForwardSanitizer extends DataFlow::Node { }
+/** A URL forward sanitizer. */
+abstract class UrlForwardSanitizer extends DataFlow::Node { }
-private class PrimitiveSanitizer extends UnsafeUrlForwardSanitizer {
+private class PrimitiveSanitizer extends UrlForwardSanitizer {
PrimitiveSanitizer() {
this.getType() instanceof PrimitiveType or
this.getType() instanceof BoxedType or
@@ -44,7 +44,7 @@ private class PrimitiveSanitizer extends UnsafeUrlForwardSanitizer {
}
// TODO: double-check this sanitizer (and should I switch all "sanitizer" naming to "barrier" instead?)
-private class FollowsSanitizingPrefix extends UnsafeUrlForwardSanitizer {
+private class FollowsSanitizingPrefix extends UrlForwardSanitizer {
FollowsSanitizingPrefix() { this.asExpr() = any(SanitizingPrefix fp).getAnAppendedExpression() }
}
diff --git a/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll b/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll
similarity index 55%
rename from java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
rename to java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll
index 49670234582..dadf4be612f 100644
--- a/java/ql/lib/semmle/code/java/security/UnsafeUrlForwardQuery.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll
@@ -1,18 +1,18 @@
-/** Provides configurations to be used in queries related to unsafe URL forwarding. */
+/** Provides a taint-tracking configuration for reasoning about URL forwarding. */
import java
-import semmle.code.java.security.UnsafeUrlForward
+import semmle.code.java.security.UrlForward
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.security.PathSanitizer
/**
- * A taint-tracking configuration for untrusted user input in a URL forward or include.
+ * A taint-tracking configuration for reasoning about URL forwarding.
*/
-module UnsafeUrlForwardFlowConfig implements DataFlow::ConfigSig {
+module UrlForwardFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof ThreatModelFlowSource and
- // TODO: move below logic to class in UnsafeUrlForward.qll? And check exactly why these were excluded.
+ // TODO: move below logic to class in UrlForward.qll? And check exactly why these were excluded.
not exists(MethodCall ma, Method m | ma.getMethod() = m |
(
m instanceof HttpServletRequestGetRequestUriMethod or
@@ -23,10 +23,10 @@ module UnsafeUrlForwardFlowConfig implements DataFlow::ConfigSig {
)
}
- predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeUrlForwardSink }
+ predicate isSink(DataFlow::Node sink) { sink instanceof UrlForwardSink }
predicate isBarrier(DataFlow::Node node) {
- node instanceof UnsafeUrlForwardSanitizer or
+ node instanceof UrlForwardSanitizer or
node instanceof PathInjectionSanitizer
}
@@ -35,6 +35,6 @@ module UnsafeUrlForwardFlowConfig implements DataFlow::ConfigSig {
}
/**
- * Taint-tracking flow for untrusted user input in a URL forward or include.
+ * Taint-tracking flow for URL forwarding.
*/
-module UnsafeUrlForwardFlow = TaintTracking::Global;
+module UrlForwardFlow = TaintTracking::Global;
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.java b/java/ql/src/Security/CWE/CWE-552/UrlForward.java
similarity index 97%
rename from java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.java
rename to java/ql/src/Security/CWE/CWE-552/UrlForward.java
index d159c405736..53b959bb889 100644
--- a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.java
+++ b/java/ql/src/Security/CWE/CWE-552/UrlForward.java
@@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
-public class UnsafeUrlForward {
+public class UrlForward {
@GetMapping("/bad1")
public ModelAndView bad1(String url) {
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qhelp b/java/ql/src/Security/CWE/CWE-552/UrlForward.qhelp
similarity index 98%
rename from java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qhelp
rename to java/ql/src/Security/CWE/CWE-552/UrlForward.qhelp
index 2e425952edc..fa9ffd45c10 100644
--- a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.qhelp
+++ b/java/ql/src/Security/CWE/CWE-552/UrlForward.qhelp
@@ -27,7 +27,7 @@ without validating the input, which may cause file leakage. In the good1
ordinary forwarding requests are shown, which will not cause file leakage.
-
+
The following examples show an HTTP request parameter or request path being used directly in a
request dispatcher of Java EE without validating the input, which allows sensitive file exposure
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql b/java/ql/src/Security/CWE/CWE-552/UrlForward.ql
similarity index 71%
rename from java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql
rename to java/ql/src/Security/CWE/CWE-552/UrlForward.ql
index 06686d5e0bd..66d3d0dd1ca 100644
--- a/java/ql/src/Security/CWE/CWE-552/UnsafeUrlForward.ql
+++ b/java/ql/src/Security/CWE/CWE-552/UrlForward.ql
@@ -14,10 +14,10 @@
*/
import java
-import semmle.code.java.security.UnsafeUrlForwardQuery
-import UnsafeUrlForwardFlow::PathGraph
+import semmle.code.java.security.UrlForwardQuery
+import UrlForwardFlow::PathGraph
-from UnsafeUrlForwardFlow::PathNode source, UnsafeUrlForwardFlow::PathNode sink
-where UnsafeUrlForwardFlow::flowPath(source, sink)
+from UrlForwardFlow::PathNode source, UrlForwardFlow::PathNode sink
+where UrlForwardFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Untrusted URL forward depends on a $@.", source.getNode(),
"user-provided value"
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java b/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java
index 55afe84bc19..3d82e7d783e 100644
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java
@@ -20,7 +20,7 @@ public class UnsafeRequestPath implements Filter {
String path = ((HttpServletRequest) request).getServletPath();
// A sample payload "/%57EB-INF/web.xml" can bypass this `startsWith` check
if (path != null && !path.startsWith("/WEB-INF")) {
- request.getRequestDispatcher(path).forward(request, response); // $ hasUnsafeUrlForward
+ request.getRequestDispatcher(path).forward(request, response); // $ hasUrlForward
} else {
chain.doFilter(request, response);
}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java b/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java
index 9d501f2ec0d..66521c5897b 100644
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java
+++ b/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java
@@ -29,7 +29,7 @@ public class UnsafeServletRequestDispatch extends HttpServlet {
rd.forward(request, response);
} else {
ServletContext sc = cfg.getServletContext();
- RequestDispatcher rd = sc.getRequestDispatcher(returnURL); // $ hasUnsafeUrlForward
+ RequestDispatcher rd = sc.getRequestDispatcher(returnURL); // $ hasUrlForward
rd.forward(request, response);
}
}
@@ -45,7 +45,7 @@ public class UnsafeServletRequestDispatch extends HttpServlet {
RequestDispatcher rd = request.getRequestDispatcher("/Login.jsp");
rd.forward(request, response);
} else {
- RequestDispatcher rd = request.getRequestDispatcher(returnURL); // $ hasUnsafeUrlForward
+ RequestDispatcher rd = request.getRequestDispatcher(returnURL); // $ hasUrlForward
rd.forward(request, response);
}
}
@@ -73,7 +73,7 @@ public class UnsafeServletRequestDispatch extends HttpServlet {
// A sample payload "/pages/welcome.jsp/../WEB-INF/web.xml" can bypass the `startsWith` check
// The payload "/pages/welcome.jsp/../../%57EB-INF/web.xml" can bypass the check as well since RequestDispatcher will decode `%57` as `W`
if (path.startsWith(BASE_PATH)) {
- request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUnsafeUrlForward
+ request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
}
}
@@ -110,7 +110,7 @@ public class UnsafeServletRequestDispatch extends HttpServlet {
Path requestedPath = Paths.get(BASE_PATH).resolve(path).normalize();
if (!requestedPath.startsWith("/WEB-INF") && !requestedPath.startsWith("/META-INF")) {
- request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response); // $ MISSING: hasUnsafeUrlForward
+ request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response); // $ MISSING: hasUrlForward
}
}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.ql b/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.ql
deleted file mode 100644
index cf77edcf12a..00000000000
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.ql
+++ /dev/null
@@ -1,18 +0,0 @@
-import java
-import TestUtilities.InlineExpectationsTest
-import semmle.code.java.security.UnsafeUrlForwardQuery
-
-module UnsafeUrlForwardTest implements TestSig {
- string getARelevantTag() { result = "hasUnsafeUrlForward" }
-
- predicate hasActualResult(Location location, string element, string tag, string value) {
- tag = "hasUnsafeUrlForward" and
- exists(UnsafeUrlForwardFlow::PathNode sink | UnsafeUrlForwardFlow::flowPath(_, sink) |
- location = sink.getNode().getLocation() and
- element = sink.getNode().toString() and
- value = ""
- )
- }
-}
-
-import MakeTest
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.expected b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.expected
similarity index 100%
rename from java/ql/test/query-tests/security/CWE-552/UnsafeUrlForwardTest.expected
rename to java/ql/test/query-tests/security/CWE-552/UrlForwardTest.expected
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.java b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
similarity index 83%
rename from java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.java
rename to java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
index 0a00637cd44..2db1e812fb6 100644
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeUrlForward.java
+++ b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
@@ -7,35 +7,35 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
-public class UnsafeUrlForward {
+public class UrlForwardTest {
@GetMapping("/bad1")
public ModelAndView bad1(String url) {
- return new ModelAndView(url); // $ hasUnsafeUrlForward
+ return new ModelAndView(url); // $ hasUrlForward
}
@GetMapping("/bad2")
public ModelAndView bad2(String url) {
ModelAndView modelAndView = new ModelAndView();
- modelAndView.setViewName(url); // $ hasUnsafeUrlForward
+ modelAndView.setViewName(url); // $ hasUrlForward
return modelAndView;
}
@GetMapping("/bad3")
public String bad3(String url) {
- return "forward:" + url + "/swagger-ui/index.html"; // $ hasUnsafeUrlForward
+ return "forward:" + url + "/swagger-ui/index.html"; // $ hasUrlForward
}
@GetMapping("/bad4")
public ModelAndView bad4(String url) {
- ModelAndView modelAndView = new ModelAndView("forward:" + url); // $ hasUnsafeUrlForward
+ ModelAndView modelAndView = new ModelAndView("forward:" + url); // $ hasUrlForward
return modelAndView;
}
@GetMapping("/bad5")
public void bad5(String url, HttpServletRequest request, HttpServletResponse response) {
try {
- request.getRequestDispatcher(url).include(request, response); // $ hasUnsafeUrlForward
+ request.getRequestDispatcher(url).include(request, response); // $ hasUrlForward
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
@@ -46,7 +46,7 @@ public class UnsafeUrlForward {
@GetMapping("/bad6")
public void bad6(String url, HttpServletRequest request, HttpServletResponse response) {
try {
- request.getRequestDispatcher("/WEB-INF/jsp/" + url + ".jsp").include(request, response); // $ hasUnsafeUrlForward
+ request.getRequestDispatcher("/WEB-INF/jsp/" + url + ".jsp").include(request, response); // $ hasUrlForward
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
@@ -57,7 +57,7 @@ public class UnsafeUrlForward {
@GetMapping("/bad7")
public void bad7(String url, HttpServletRequest request, HttpServletResponse response) {
try {
- request.getRequestDispatcher("/WEB-INF/jsp/" + url + ".jsp").forward(request, response); // $ hasUnsafeUrlForward
+ request.getRequestDispatcher("/WEB-INF/jsp/" + url + ".jsp").forward(request, response); // $ hasUrlForward
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
diff --git a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.ql b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.ql
new file mode 100644
index 00000000000..4e62a35752b
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.ql
@@ -0,0 +1,18 @@
+import java
+import TestUtilities.InlineExpectationsTest
+import semmle.code.java.security.UrlForwardQuery
+
+module UrlForwardTest implements TestSig {
+ string getARelevantTag() { result = "hasUrlForward" }
+
+ predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "hasUrlForward" and
+ exists(UrlForwardFlow::PathNode sink | UrlForwardFlow::flowPath(_, sink) |
+ location = sink.getNode().getLocation() and
+ element = sink.getNode().toString() and
+ value = ""
+ )
+ }
+}
+
+import MakeTest
From c331393cfd3982f06098e7f1a0613124c0cb44f4 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Fri, 1 Dec 2023 12:14:27 -0500
Subject: [PATCH 050/497] Java: update qhelp
---
.../CWE/CWE-552/UnsafeLoadSpringResource.java | 21 -------
.../CWE/CWE-552/UnsafeResourceGet.java | 18 ------
.../CWE-552/UnsafeServletRequestDispatch.java | 11 ----
.../src/Security/CWE/CWE-552/UrlForward.java | 43 ++++----------
.../src/Security/CWE/CWE-552/UrlForward.qhelp | 58 ++++---------------
.../ql/src/Security/CWE/CWE-552/UrlForward.ql | 6 +-
6 files changed, 25 insertions(+), 132 deletions(-)
delete mode 100644 java/ql/src/Security/CWE/CWE-552/UnsafeLoadSpringResource.java
delete mode 100644 java/ql/src/Security/CWE/CWE-552/UnsafeResourceGet.java
delete mode 100644 java/ql/src/Security/CWE/CWE-552/UnsafeServletRequestDispatch.java
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeLoadSpringResource.java b/java/ql/src/Security/CWE/CWE-552/UnsafeLoadSpringResource.java
deleted file mode 100644
index ce462fe490e..00000000000
--- a/java/ql/src/Security/CWE/CWE-552/UnsafeLoadSpringResource.java
+++ /dev/null
@@ -1,21 +0,0 @@
-//BAD: no path validation in Spring resource loading
-@GetMapping("/file")
-public String getFileContent(@RequestParam(name="fileName") String fileName) {
- ClassPathResource clr = new ClassPathResource(fileName);
-
- File file = ResourceUtils.getFile(fileName);
-
- Resource resource = resourceLoader.getResource(fileName);
-}
-
-//GOOD: check for a trusted prefix, ensuring path traversal is not used to erase that prefix in Spring resource loading:
-@GetMapping("/file")
-public String getFileContent(@RequestParam(name="fileName") String fileName) {
- if (!fileName.contains("..") && fileName.hasPrefix("/public-content")) {
- ClassPathResource clr = new ClassPathResource(fileName);
-
- File file = ResourceUtils.getFile(fileName);
-
- Resource resource = resourceLoader.getResource(fileName);
- }
-}
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeResourceGet.java b/java/ql/src/Security/CWE/CWE-552/UnsafeResourceGet.java
deleted file mode 100644
index 8b3583bf59e..00000000000
--- a/java/ql/src/Security/CWE/CWE-552/UnsafeResourceGet.java
+++ /dev/null
@@ -1,18 +0,0 @@
-// BAD: no URI validation
-URL url = request.getServletContext().getResource(requestUrl);
-url = getClass().getResource(requestUrl);
-InputStream in = url.openStream();
-
-InputStream in = request.getServletContext().getResourceAsStream(requestPath);
-in = getClass().getClassLoader().getResourceAsStream(requestPath);
-
-// GOOD: check for a trusted prefix, ensuring path traversal is not used to erase that prefix:
-// (alternatively use `Path.normalize` instead of checking for `..`)
-if (!requestPath.contains("..") && requestPath.startsWith("/trusted")) {
- InputStream in = request.getServletContext().getResourceAsStream(requestPath);
-}
-
-Path path = Paths.get(requestUrl).normalize().toRealPath();
-if (path.startsWith("/trusted")) {
- URL url = request.getServletContext().getResource(path.toString());
-}
diff --git a/java/ql/src/Security/CWE/CWE-552/UnsafeServletRequestDispatch.java b/java/ql/src/Security/CWE/CWE-552/UnsafeServletRequestDispatch.java
deleted file mode 100644
index a2bbf3dfcd8..00000000000
--- a/java/ql/src/Security/CWE/CWE-552/UnsafeServletRequestDispatch.java
+++ /dev/null
@@ -1,11 +0,0 @@
-// BAD: no URI validation
-String returnURL = request.getParameter("returnURL");
-RequestDispatcher rd = sc.getRequestDispatcher(returnURL);
-rd.forward(request, response);
-
-// GOOD: check for a trusted prefix, ensuring path traversal is not used to erase that prefix:
-// (alternatively use `Path.normalize` instead of checking for `..`)
-if (!returnURL.contains("..") && returnURL.hasPrefix("/pages")) { ... }
-// Also GOOD: check for a forbidden prefix, ensuring URL-encoding is not used to evade the check:
-// (alternatively use `URLDecoder.decode` before `hasPrefix`)
-if (returnURL.hasPrefix("/internal") && !returnURL.contains("%")) { ... }
diff --git a/java/ql/src/Security/CWE/CWE-552/UrlForward.java b/java/ql/src/Security/CWE/CWE-552/UrlForward.java
index 53b959bb889..db701fbcd9a 100644
--- a/java/ql/src/Security/CWE/CWE-552/UrlForward.java
+++ b/java/ql/src/Security/CWE/CWE-552/UrlForward.java
@@ -1,38 +1,17 @@
-import java.io.IOException;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.servlet.ModelAndView;
+public class UrlForward extends HttpServlet {
+ private static final String VALID_FORWARD = "https://cwe.mitre.org/data/definitions/552.html";
-@Controller
-public class UrlForward {
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ ServletConfig cfg = getServletConfig();
+ ServletContext sc = cfg.getServletContext();
- @GetMapping("/bad1")
- public ModelAndView bad1(String url) {
- return new ModelAndView(url);
- }
+ // BAD: a request parameter is incorporated without validation into a URL forward
+ sc.getRequestDispatcher(request.getParameter("target")).forward(request, response);
- @GetMapping("/bad2")
- public void bad2(String url, HttpServletRequest request, HttpServletResponse response) {
- try {
- request.getRequestDispatcher("/WEB-INF/jsp/" + url + ".jsp").include(request, response);
- } catch (ServletException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- @GetMapping("/good1")
- public void good1(String url, HttpServletRequest request, HttpServletResponse response) {
- try {
- request.getRequestDispatcher("/index.jsp?token=" + url).forward(request, response);
- } catch (ServletException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
+ // GOOD: the request parameter is validated against a known fixed string
+ if (VALID_FORWARD.equals(request.getParameter("target"))) {
+ sc.getRequestDispatcher(VALID_FORWARD).forward(request, response);
}
}
}
diff --git a/java/ql/src/Security/CWE/CWE-552/UrlForward.qhelp b/java/ql/src/Security/CWE/CWE-552/UrlForward.qhelp
index fa9ffd45c10..2b06a851a2b 100644
--- a/java/ql/src/Security/CWE/CWE-552/UrlForward.qhelp
+++ b/java/ql/src/Security/CWE/CWE-552/UrlForward.qhelp
@@ -5,66 +5,32 @@
-
Constructing a server-side redirect path with user input could allow an attacker to download application binaries
-(including application classes or jar files) or view arbitrary files within protected directories.
+
Directly incorporating user input into a URL forward request without validating the input
+can cause file information disclosure by allowing an attacker to access unauthorized URLs.
-
Unsanitized user provided data must not be used to construct the path for URL forwarding. In order to prevent
-untrusted URL forwarding, it is recommended to avoid concatenating user input directly into the forwarding URL.
-Instead, user input should be checked against allowed (e.g., must come within user_content/) or disallowed
-(e.g. must not come within /internal) paths, ensuring that neither path traversal using ../
-or URL encoding are used to evade these checks.
-
+
To guard against untrusted URL forwarding, it is advisable to avoid putting user input
+directly into a forwarded URL. Instead, maintain a list of authorized
+URLs on the server; then choose from that list based on the user input provided.
-
The following examples show the bad case and the good case respectively.
-The bad methods show an HTTP request parameter being used directly in a URL forward
-without validating the input, which may cause file leakage. In the good1 method,
-ordinary forwarding requests are shown, which will not cause file leakage.
+
The following example shows an HTTP request parameter being used directly in a URL forward
+without validating the input, which may cause file information disclosure.
+It also shows how to remedy the problem by validating the user input against a known fixed string.
-
The following examples show an HTTP request parameter or request path being used directly in a
-request dispatcher of Java EE without validating the input, which allows sensitive file exposure
-attacks. It also shows how to remedy the problem by validating the user input.
-
-
-
-
-
The following examples show an HTTP request parameter or request path being used directly to
-retrieve a resource of a Java EE application without validating the input, which allows sensitive
-file exposure attacks. It also shows how to remedy the problem by validating the user input.
-
-
-
-
-
The following examples show an HTTP request parameter being used directly to retrieve a resource
- of a Java Spring application without validating the input, which allows sensitive file exposure
- attacks. It also shows how to remedy the problem by validating the user input.
-
+
diff --git a/java/ql/src/Security/CWE/CWE-552/UrlForward.ql b/java/ql/src/Security/CWE/CWE-552/UrlForward.ql
index 66d3d0dd1ca..95c540049a2 100644
--- a/java/ql/src/Security/CWE/CWE-552/UrlForward.ql
+++ b/java/ql/src/Security/CWE/CWE-552/UrlForward.ql
@@ -1,16 +1,14 @@
/**
* @name URL forward from a remote source
* @description URL forward based on unvalidated user-input
- * may cause file information disclosure or
- * redirection to malicious web sites.
+ * may cause file information disclosure.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.1
+ * @security-severity 7.5
* @precision high
* @id java/unvalidated-url-forward
* @tags security
* external/cwe/cwe-552
- * external/cwe/cwe-601
*/
import java
From 5fa63ab5c22adc24b62cdfdc4efe12e578ede3bf Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Mon, 4 Dec 2023 10:31:47 -0500
Subject: [PATCH 051/497] Java: update/add some TODO comments
---
.../semmle/code/java/security/UrlForward.qll | 31 ++++++++++---------
.../code/java/security/UrlForwardQuery.qll | 9 +++---
2 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index aa21ed48aba..7e68f07987b 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -8,48 +8,49 @@ private import semmle.code.java.dataflow.StringPrefixes
/** A URL forward sink. */
abstract class UrlForwardSink extends DataFlow::Node { }
-/** A default sink representing methods susceptible to URL forwarding attacks. */
+/**
+ * A default sink representing methods susceptible to URL
+ * forwarding attacks.
+ */
private class DefaultUrlForwardSink extends UrlForwardSink {
DefaultUrlForwardSink() { sinkNode(this, "url-forward") }
}
/**
- * An expression appended (perhaps indirectly) to `"forward:"`, and which
- * is reachable from a Spring entry point.
+ * An expression appended (perhaps indirectly) to `"forward:"`
+ * and reachable from a Spring entry point.
*/
private class SpringUrlForwardSink extends UrlForwardSink {
SpringUrlForwardSink() {
- // TODO: check if can use MaD "Annotated" for `SpringRequestMappingMethod` or if too complicated for MaD (probably too complicated).
- any(SpringRequestMappingMethod sqmm).polyCalls*(this.getEnclosingCallable()) and
+ any(SpringRequestMappingMethod srmm).polyCalls*(this.getEnclosingCallable()) and
this.asExpr() = any(ForwardPrefix fp).getAnAppendedExpression()
}
}
-// TODO: should this potentially be "include:" as well? Or does that not work similarly?
private class ForwardPrefix extends InterestingPrefix {
ForwardPrefix() { this.getStringValue() = "forward:" }
override int getOffset() { result = 0 }
}
-/** A URL forward sanitizer. */
-abstract class UrlForwardSanitizer extends DataFlow::Node { }
+/** A URL forward barrier. */
+abstract class UrlForwardBarrier extends DataFlow::Node { }
-private class PrimitiveSanitizer extends UrlForwardSanitizer {
- PrimitiveSanitizer() {
+private class PrimitiveBarrier extends UrlForwardBarrier {
+ PrimitiveBarrier() {
this.getType() instanceof PrimitiveType or
this.getType() instanceof BoxedType or
this.getType() instanceof NumberType
}
}
-// TODO: double-check this sanitizer (and should I switch all "sanitizer" naming to "barrier" instead?)
-private class FollowsSanitizingPrefix extends UrlForwardSanitizer {
- FollowsSanitizingPrefix() { this.asExpr() = any(SanitizingPrefix fp).getAnAppendedExpression() }
+private class FollowsBarrierPrefix extends UrlForwardBarrier {
+ FollowsBarrierPrefix() { this.asExpr() = any(BarrierPrefix fp).getAnAppendedExpression() }
}
-private class SanitizingPrefix extends InterestingPrefix {
- SanitizingPrefix() {
+private class BarrierPrefix extends InterestingPrefix {
+ BarrierPrefix() {
+ // TODO: why not META-INF here as well? (and are `/` correct?)
not this.getStringValue().matches("/WEB-INF/%") and
not this.getStringValue() = "forward:"
}
diff --git a/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll b/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll
index dadf4be612f..c92467490f3 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll
@@ -12,25 +12,24 @@ import semmle.code.java.security.PathSanitizer
module UrlForwardFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof ThreatModelFlowSource and
- // TODO: move below logic to class in UrlForward.qll? And check exactly why these were excluded.
- not exists(MethodCall ma, Method m | ma.getMethod() = m |
+ // excluded due to FPs
+ not exists(MethodCall mc, Method m | mc.getMethod() = m |
(
m instanceof HttpServletRequestGetRequestUriMethod or
m instanceof HttpServletRequestGetRequestUrlMethod or
m instanceof HttpServletRequestGetPathMethod
) and
- ma = source.asExpr()
+ mc = source.asExpr()
)
}
predicate isSink(DataFlow::Node sink) { sink instanceof UrlForwardSink }
predicate isBarrier(DataFlow::Node node) {
- node instanceof UrlForwardSanitizer or
+ node instanceof UrlForwardBarrier or
node instanceof PathInjectionSanitizer
}
- // TODO: check if the below is still needed after removing path-injection related sinks.
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
}
From e75c96c0f9be67d4423446177dedc808a1ec9239 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Sun, 10 Dec 2023 22:03:11 -0500
Subject: [PATCH 052/497] Java: combine test cases; add test for
StaplerResponse.forward
---
.../security/CWE-552/UnsafeRequestPath.java | 52 -----
.../CWE-552/UnsafeServletRequestDispatch.java | 131 -------------
.../security/CWE-552/UrlForwardTest.java | 180 +++++++++++++++++-
.../test/query-tests/security/CWE-552/options | 2 +-
4 files changed, 180 insertions(+), 185 deletions(-)
delete mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java
delete mode 100644 java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java b/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java
deleted file mode 100644
index 3d82e7d783e..00000000000
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeRequestPath.java
+++ /dev/null
@@ -1,52 +0,0 @@
-import java.io.IOException;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-// @WebFilter("/*")
-public class UnsafeRequestPath implements Filter {
- private static final String BASE_PATH = "/pages";
-
- @Override
- // BAD: Request dispatcher from servlet path without check
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
- String path = ((HttpServletRequest) request).getServletPath();
- // A sample payload "/%57EB-INF/web.xml" can bypass this `startsWith` check
- if (path != null && !path.startsWith("/WEB-INF")) {
- request.getRequestDispatcher(path).forward(request, response); // $ hasUrlForward
- } else {
- chain.doFilter(request, response);
- }
- }
-
- // GOOD: Request dispatcher from servlet path with check
- public void doFilter2(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
- String path = ((HttpServletRequest) request).getServletPath();
-
- if (path.startsWith(BASE_PATH) && !path.contains("..")) {
- request.getRequestDispatcher(path).forward(request, response);
- } else {
- chain.doFilter(request, response);
- }
- }
-
- // GOOD: Request dispatcher from servlet path with whitelisted string comparison
- public void doFilter3(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
- String path = ((HttpServletRequest) request).getServletPath();
-
- if (path.equals("/comaction")) {
- request.getRequestDispatcher(path).forward(request, response);
- } else {
- chain.doFilter(request, response);
- }
- }
-}
diff --git a/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java b/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java
deleted file mode 100644
index 66521c5897b..00000000000
--- a/java/ql/test/query-tests/security/CWE-552/UnsafeServletRequestDispatch.java
+++ /dev/null
@@ -1,131 +0,0 @@
-import java.io.IOException;
-import java.net.URLDecoder;
-import java.io.File;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-
-public class UnsafeServletRequestDispatch extends HttpServlet {
- private static final String BASE_PATH = "/pages";
-
- @Override
- // BAD: Request dispatcher constructed from `ServletContext` without input validation
- protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String action = request.getParameter("action");
- String returnURL = request.getParameter("returnURL");
-
- ServletConfig cfg = getServletConfig();
- if (action.equals("Login")) {
- ServletContext sc = cfg.getServletContext();
- RequestDispatcher rd = sc.getRequestDispatcher("/Login.jsp");
- rd.forward(request, response);
- } else {
- ServletContext sc = cfg.getServletContext();
- RequestDispatcher rd = sc.getRequestDispatcher(returnURL); // $ hasUrlForward
- rd.forward(request, response);
- }
- }
-
- @Override
- // BAD: Request dispatcher constructed from `HttpServletRequest` without input validation
- protected void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String action = request.getParameter("action");
- String returnURL = request.getParameter("returnURL");
-
- if (action.equals("Login")) {
- RequestDispatcher rd = request.getRequestDispatcher("/Login.jsp");
- rd.forward(request, response);
- } else {
- RequestDispatcher rd = request.getRequestDispatcher(returnURL); // $ hasUrlForward
- rd.forward(request, response);
- }
- }
-
- @Override
- // GOOD: Request dispatcher with a whitelisted URI
- protected void doPut(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String action = request.getParameter("action");
-
- if (action.equals("Login")) {
- RequestDispatcher rd = request.getRequestDispatcher("/Login.jsp");
- rd.forward(request, response);
- } else if (action.equals("Register")) {
- RequestDispatcher rd = request.getRequestDispatcher("/Register.jsp");
- rd.forward(request, response);
- }
- }
-
- // BAD: Request dispatcher without path traversal check
- protected void doHead2(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String path = request.getParameter("path");
-
- // A sample payload "/pages/welcome.jsp/../WEB-INF/web.xml" can bypass the `startsWith` check
- // The payload "/pages/welcome.jsp/../../%57EB-INF/web.xml" can bypass the check as well since RequestDispatcher will decode `%57` as `W`
- if (path.startsWith(BASE_PATH)) {
- request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
- }
- }
-
- // GOOD: Request dispatcher with path traversal check
- protected void doHead3(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String path = request.getParameter("path");
-
- if (path.startsWith(BASE_PATH) && !path.contains("..")) {
- request.getServletContext().getRequestDispatcher(path).include(request, response);
- }
- }
-
- // GOOD: Request dispatcher with path normalization and comparison
- protected void doHead4(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String path = request.getParameter("path");
- Path requestedPath = Paths.get(BASE_PATH).resolve(path).normalize();
-
- // /pages/welcome.jsp/../../WEB-INF/web.xml becomes /WEB-INF/web.xml
- // /pages/welcome.jsp/../../%57EB-INF/web.xml becomes /%57EB-INF/web.xml
- if (requestedPath.startsWith(BASE_PATH)) {
- request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response);
- }
- }
-
- // FN: Request dispatcher with negation check and path normalization, but without URL decoding
- // When promoting this query, consider using FlowStates to make `getRequestDispatcher` a sink
- // only if a URL-decoding step has NOT been crossed (i.e. make URLDecoder.decode change the
- // state to a different value than the one required at the sink).
- protected void doHead5(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String path = request.getParameter("path");
- Path requestedPath = Paths.get(BASE_PATH).resolve(path).normalize();
-
- if (!requestedPath.startsWith("/WEB-INF") && !requestedPath.startsWith("/META-INF")) {
- request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response); // $ MISSING: hasUrlForward
- }
- }
-
- // GOOD: Request dispatcher with path traversal check and URL decoding
- protected void doHead6(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String path = request.getParameter("path");
- boolean hasEncoding = path.contains("%");
- while (hasEncoding) {
- path = URLDecoder.decode(path, "UTF-8");
- hasEncoding = path.contains("%");
- }
-
- if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
- request.getServletContext().getRequestDispatcher(path).include(request, response);
- }
- }
-}
diff --git a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
index 2db1e812fb6..e41bc65848e 100644
--- a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
+++ b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
@@ -1,14 +1,29 @@
import java.io.IOException;
+import java.net.URLDecoder;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
+import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerResponse;
@Controller
-public class UrlForwardTest {
+public class UrlForwardTest extends HttpServlet implements Filter {
+ // (1) ORIGINAL
@GetMapping("/bad1")
public ModelAndView bad1(String url) {
return new ModelAndView(url); // $ hasUrlForward
@@ -75,4 +90,167 @@ public class UrlForwardTest {
e.printStackTrace();
}
}
+
+ // (2) UnsafeRequestPath
+ private static final String BASE_PATH = "/pages";
+
+ @Override
+ // BAD: Request dispatcher from servlet path without check
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ String path = ((HttpServletRequest) request).getServletPath();
+ // A sample payload "/%57EB-INF/web.xml" can bypass this `startsWith` check
+ if (path != null && !path.startsWith("/WEB-INF")) {
+ request.getRequestDispatcher(path).forward(request, response); // $ hasUrlForward
+ } else {
+ chain.doFilter(request, response);
+ }
+ }
+
+ // GOOD: Request dispatcher from servlet path with check
+ public void doFilter2(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ String path = ((HttpServletRequest) request).getServletPath();
+
+ if (path.startsWith(BASE_PATH) && !path.contains("..")) {
+ request.getRequestDispatcher(path).forward(request, response);
+ } else {
+ chain.doFilter(request, response);
+ }
+ }
+
+ // GOOD: Request dispatcher from servlet path with whitelisted string comparison
+ public void doFilter3(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ String path = ((HttpServletRequest) request).getServletPath();
+
+ if (path.equals("/comaction")) {
+ request.getRequestDispatcher(path).forward(request, response);
+ } else {
+ chain.doFilter(request, response);
+ }
+ }
+
+ // (3) UnsafeServletRequestDispatch
+ @Override
+ // BAD: Request dispatcher constructed from `ServletContext` without input validation
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String action = request.getParameter("action");
+ String returnURL = request.getParameter("returnURL");
+
+ ServletConfig cfg = getServletConfig();
+ if (action.equals("Login")) {
+ ServletContext sc = cfg.getServletContext();
+ RequestDispatcher rd = sc.getRequestDispatcher("/Login.jsp");
+ rd.forward(request, response);
+ } else {
+ ServletContext sc = cfg.getServletContext();
+ RequestDispatcher rd = sc.getRequestDispatcher(returnURL); // $ hasUrlForward
+ rd.forward(request, response);
+ }
+ }
+
+ @Override
+ // BAD: Request dispatcher constructed from `HttpServletRequest` without input validation
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String action = request.getParameter("action");
+ String returnURL = request.getParameter("returnURL");
+
+ if (action.equals("Login")) {
+ RequestDispatcher rd = request.getRequestDispatcher("/Login.jsp");
+ rd.forward(request, response);
+ } else {
+ RequestDispatcher rd = request.getRequestDispatcher(returnURL); // $ hasUrlForward
+ rd.forward(request, response);
+ }
+ }
+
+ @Override
+ // GOOD: Request dispatcher with a whitelisted URI
+ protected void doPut(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String action = request.getParameter("action");
+
+ if (action.equals("Login")) {
+ RequestDispatcher rd = request.getRequestDispatcher("/Login.jsp");
+ rd.forward(request, response);
+ } else if (action.equals("Register")) {
+ RequestDispatcher rd = request.getRequestDispatcher("/Register.jsp");
+ rd.forward(request, response);
+ }
+ }
+
+ // BAD: Request dispatcher without path traversal check
+ protected void doHead2(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path");
+
+ // A sample payload "/pages/welcome.jsp/../WEB-INF/web.xml" can bypass the `startsWith` check
+ // The payload "/pages/welcome.jsp/../../%57EB-INF/web.xml" can bypass the check as well since RequestDispatcher will decode `%57` as `W`
+ if (path.startsWith(BASE_PATH)) {
+ request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
+ }
+ }
+
+ // GOOD: Request dispatcher with path traversal check
+ protected void doHead3(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path");
+
+ if (path.startsWith(BASE_PATH) && !path.contains("..")) {
+ request.getServletContext().getRequestDispatcher(path).include(request, response);
+ }
+ }
+
+ // GOOD: Request dispatcher with path normalization and comparison
+ protected void doHead4(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path");
+ Path requestedPath = Paths.get(BASE_PATH).resolve(path).normalize();
+
+ // /pages/welcome.jsp/../../WEB-INF/web.xml becomes /WEB-INF/web.xml
+ // /pages/welcome.jsp/../../%57EB-INF/web.xml becomes /%57EB-INF/web.xml
+ if (requestedPath.startsWith(BASE_PATH)) {
+ request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response);
+ }
+ }
+
+ // FN: Request dispatcher with negation check and path normalization, but without URL decoding
+ // When promoting this query, consider using FlowStates to make `getRequestDispatcher` a sink
+ // only if a URL-decoding step has NOT been crossed (i.e. make URLDecoder.decode change the
+ // state to a different value than the one required at the sink).
+ // TODO: but does this need to take into account URLDecoder.decode in a loop...?
+ protected void doHead5(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path");
+ Path requestedPath = Paths.get(BASE_PATH).resolve(path).normalize();
+
+ if (!requestedPath.startsWith("/WEB-INF") && !requestedPath.startsWith("/META-INF")) {
+ request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response); // $ MISSING: hasUrlForward
+ }
+ }
+
+ // GOOD: Request dispatcher with path traversal check and URL decoding
+ protected void doHead6(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path");
+ boolean hasEncoding = path.contains("%");
+ while (hasEncoding) {
+ path = URLDecoder.decode(path, "UTF-8");
+ hasEncoding = path.contains("%");
+ }
+
+ if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
+ request.getServletContext().getRequestDispatcher(path).include(request, response);
+ }
+ }
+
+ // New Tests (i.e. Added by me)
+ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object obj) throws IOException, ServletException {
+ String url = req.getParameter("target");
+ rsp.forward(obj, url, req); // $ hasUrlForward
+ }
+
}
diff --git a/java/ql/test/query-tests/security/CWE-552/options b/java/ql/test/query-tests/security/CWE-552/options
index 025b888db02..bda9516fb58 100644
--- a/java/ql/test/query-tests/security/CWE-552/options
+++ b/java/ql/test/query-tests/security/CWE-552/options
@@ -1 +1 @@
-//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.3.8/:${testdir}/../../../stubs/javax-faces-2.3/:${testdir}/../../../stubs/undertow-io-2.2/:${testdir}/../../../stubs/jboss-vfs-3.2/:${testdir}/../../../stubs/springframework-5.3.8/
+//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.3.8/:${testdir}/../../../stubs/javax-faces-2.3/:${testdir}/../../../stubs/undertow-io-2.2/:${testdir}/../../../stubs/jboss-vfs-3.2/:${testdir}/../../../stubs/stapler-1.263/:${testdir}/../../../stubs/apache-commons-fileupload-1.4/:${testdir}/../../../stubs/apache-commons-beanutils/:${testdir}/../../../stubs/saxon-xqj-9.x/:${testdir}/../../../stubs/apache-commons-lang/:${testdir}/../../../stubs/javax-servlet-2.5/
From c8ec301793067bb1d9d6c9f5e9ccacc59d086f01 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Sun, 10 Dec 2023 22:12:08 -0500
Subject: [PATCH 053/497] Java: add change note
---
java/ql/src/change-notes/2023-12-12-url-forward-query.md | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 java/ql/src/change-notes/2023-12-12-url-forward-query.md
diff --git a/java/ql/src/change-notes/2023-12-12-url-forward-query.md b/java/ql/src/change-notes/2023-12-12-url-forward-query.md
new file mode 100644
index 00000000000..4efc4b7c4e0
--- /dev/null
+++ b/java/ql/src/change-notes/2023-12-12-url-forward-query.md
@@ -0,0 +1,4 @@
+---
+category: newQuery
+---
+* The query `java/unsafe-url-forward-dispatch-load` has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally submitted as an experimental query [by @haby0](https://github.com/github/codeql/pull/6240) and [by @luchua-bc](https://github.com/github/codeql/pull/7286).
From 911a61df2234dc5f9519e3238159f2e7f53f1d3f Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 5 Mar 2024 11:08:24 -0500
Subject: [PATCH 054/497] Java: initial update of barrier and test cases to
remove FN
---
.../code/java/security/PathSanitizer.qll | 7 +-
.../semmle/code/java/security/UrlForward.qll | 110 +++++++++++++-
.../code/java/security/UrlForwardQuery.qll | 5 +-
.../security/CWE-552/UrlForwardTest.java | 141 ++++++++++++++++--
4 files changed, 240 insertions(+), 23 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/security/PathSanitizer.qll b/java/ql/lib/semmle/code/java/security/PathSanitizer.qll
index 4ca08f5becc..f3c54629efd 100644
--- a/java/ql/lib/semmle/code/java/security/PathSanitizer.qll
+++ b/java/ql/lib/semmle/code/java/security/PathSanitizer.qll
@@ -64,7 +64,8 @@ private predicate exactPathMatchGuard(Guard g, Expr e, boolean branch) {
)
}
-private class ExactPathMatchSanitizer extends PathInjectionSanitizer {
+// TODO: switch back to private if possible
+class ExactPathMatchSanitizer extends PathInjectionSanitizer {
ExactPathMatchSanitizer() {
this = DataFlow::BarrierGuard::getABarrierNode()
or
@@ -151,7 +152,8 @@ private class DotDotCheckSanitizer extends PathInjectionSanitizer {
}
}
-private class BlockListGuard extends PathGuard instanceof MethodCall {
+// TODO: switch back to private if possible
+class BlockListGuard extends PathGuard instanceof MethodCall {
BlockListGuard() {
(isStringPartialMatch(this) or isPathPrefixMatch(this)) and
isDisallowedWord(super.getAnArgument())
@@ -228,6 +230,7 @@ private predicate isStringPartialMatch(MethodCall ma) {
exists(RefType t | t = ma.getMethod().getDeclaringType() |
t instanceof TypeString or t instanceof StringsKt
) and
+ // TODO ! Why not use `StringPartialMatchMethod` for the below?
getSourceMethod(ma.getMethod())
.hasName(["contains", "matches", "regionMatches", "indexOf", "lastIndexOf"])
}
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index 7e68f07987b..073507fe33a 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -4,6 +4,9 @@ import java
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.StringPrefixes
+private import semmle.code.java.security.PathSanitizer
+private import semmle.code.java.dataflow.DataFlow
+private import semmle.code.java.controlflow.Guards
/** A URL forward sink. */
abstract class UrlForwardSink extends DataFlow::Node { }
@@ -44,16 +47,121 @@ private class PrimitiveBarrier extends UrlForwardBarrier {
}
}
+// TODO: should this also take URL encoding/decoding into account?
+// TODO: and PathSanitization in general?
private class FollowsBarrierPrefix extends UrlForwardBarrier {
FollowsBarrierPrefix() { this.asExpr() = any(BarrierPrefix fp).getAnAppendedExpression() }
}
private class BarrierPrefix extends InterestingPrefix {
BarrierPrefix() {
- // TODO: why not META-INF here as well? (and are `/` correct?)
not this.getStringValue().matches("/WEB-INF/%") and
not this.getStringValue() = "forward:"
}
override int getOffset() { result = 0 }
}
+
+private class UrlPathBarrier extends UrlForwardBarrier {
+ UrlPathBarrier() {
+ this instanceof PathInjectionSanitizer and
+ (
+ this instanceof ExactPathMatchSanitizer //TODO: still need a better solution for this edge case...
+ or
+ // TODO: these don't enforce order of checks and PathSanitization... make bypass test cases.
+ this instanceof NoEncodingBarrier
+ or
+ this instanceof FullyDecodesBarrier
+ )
+ }
+}
+
+abstract class UrlDecodeCall extends MethodCall { }
+
+private class DefaultUrlDecodeCall extends UrlDecodeCall {
+ DefaultUrlDecodeCall() {
+ this.getMethod().hasQualifiedName("java.net", "URLDecoder", "decode") or // TODO: reuse existing class? Or make this a class?
+ this.getMethod().hasQualifiedName("org.eclipse.jetty.util.URIUtil", "URIUtil", "decodePath")
+ }
+}
+
+// TODO: this can probably be named/designed better...
+abstract class RepeatedStmt extends Stmt { }
+
+private class DefaultRepeatedStmt extends RepeatedStmt {
+ DefaultRepeatedStmt() { this instanceof LoopStmt }
+}
+
+abstract class CheckEncodingCall extends MethodCall { }
+
+private class DefaultCheckEncodingCall extends CheckEncodingCall {
+ DefaultCheckEncodingCall() {
+ // TODO: indexOf?, etc.
+ this.getMethod().hasQualifiedName("java.lang", "String", "contains") and // TODO: reuse existing class? Or make this a class?
+ this.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "%"
+ }
+}
+
+// TODO: better naming?
+// TODO: check if any URL decoding implementations _fully_ decode... or if all need to be called in a loop?
+// TODO: make this extendable instead of `RepeatedStmt`?
+private class RepeatedUrlDecodeCall extends MethodCall {
+ RepeatedUrlDecodeCall() {
+ this instanceof UrlDecodeCall and
+ this.getAnEnclosingStmt() instanceof RepeatedStmt
+ }
+}
+
+private class CheckEncodingGuard extends Guard instanceof MethodCall {
+ CheckEncodingGuard() { this instanceof CheckEncodingCall }
+
+ Expr getCheckedExpr() { result = this.(MethodCall).getQualifier() }
+}
+
+private predicate noEncodingGuard(Guard g, Expr e, boolean branch) {
+ g instanceof CheckEncodingGuard and
+ e = g.(CheckEncodingGuard).getCheckedExpr() and
+ branch = false
+ or
+ // branch = false and
+ // g instanceof AssignExpr and // AssignExpr
+ // exists(CheckEncodingCall call | g.(AssignExpr).getSource() = call | e = call.getQualifier())
+ branch = false and
+ g.(Expr).getType() instanceof BooleanType and // AssignExpr
+ (
+ exists(CheckEncodingCall call, AssignExpr ae |
+ ae.getSource() = call and
+ e = call.getQualifier() and
+ g = ae.getDest()
+ )
+ or
+ exists(CheckEncodingCall call, LocalVariableDeclExpr vde |
+ vde.getInitOrPatternSource() = call and
+ e = call.getQualifier() and
+ g = vde.getAnAccess() //and
+ //vde.getVariable() = g
+ )
+ )
+}
+
+// TODO: check edge case of !contains(%), make sure that behaves as expected at least.
+private class NoEncodingBarrier extends DataFlow::Node {
+ NoEncodingBarrier() { this = DataFlow::BarrierGuard::getABarrierNode() }
+}
+
+private predicate fullyDecodesGuard(Expr e) {
+ exists(CheckEncodingGuard g, RepeatedUrlDecodeCall decodeCall |
+ e = g.getCheckedExpr() and
+ g.controls(decodeCall.getBasicBlock(), true)
+ )
+}
+
+private class FullyDecodesBarrier extends DataFlow::Node {
+ FullyDecodesBarrier() {
+ exists(Variable v, Expr e | this.asExpr() = v.getAnAccess() |
+ fullyDecodesGuard(e) and
+ e = v.getAnAccess() and
+ e.getBasicBlock().bbDominates(this.asExpr().getBasicBlock())
+ )
+ }
+}
diff --git a/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll b/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll
index c92467490f3..71d41f42dee 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll
@@ -25,10 +25,7 @@ module UrlForwardFlowConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof UrlForwardSink }
- predicate isBarrier(DataFlow::Node node) {
- node instanceof UrlForwardBarrier or
- node instanceof PathInjectionSanitizer
- }
+ predicate isBarrier(DataFlow::Node node) { node instanceof UrlForwardBarrier }
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
}
diff --git a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
index e41bc65848e..c7a9d82b1a0 100644
--- a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
+++ b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
@@ -112,8 +112,9 @@ public class UrlForwardTest extends HttpServlet implements Filter {
throws IOException, ServletException {
String path = ((HttpServletRequest) request).getServletPath();
+ // actually BAD since could potentially bypass with ".." encoded as "%2e%2e"?
if (path.startsWith(BASE_PATH) && !path.contains("..")) {
- request.getRequestDispatcher(path).forward(request, response);
+ request.getRequestDispatcher(path).forward(request, response); // $ hasUrlForward
} else {
chain.doFilter(request, response);
}
@@ -124,6 +125,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
throws IOException, ServletException {
String path = ((HttpServletRequest) request).getServletPath();
+ // this is still good, should not flag here..., url-decoding first doesn't matter if looking for exact match... :(
if (path.equals("/comaction")) {
request.getRequestDispatcher(path).forward(request, response);
} else {
@@ -199,8 +201,9 @@ public class UrlForwardTest extends HttpServlet implements Filter {
throws ServletException, IOException {
String path = request.getParameter("path");
+ // actually BAD since could potentially bypass with ".." encoded as "%2e%2e"?
if (path.startsWith(BASE_PATH) && !path.contains("..")) {
- request.getServletContext().getRequestDispatcher(path).include(request, response);
+ request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
}
}
@@ -212,34 +215,43 @@ public class UrlForwardTest extends HttpServlet implements Filter {
// /pages/welcome.jsp/../../WEB-INF/web.xml becomes /WEB-INF/web.xml
// /pages/welcome.jsp/../../%57EB-INF/web.xml becomes /%57EB-INF/web.xml
+ // actually BAD since could potentially bypass with ".." encoded as "%2e%2e": "/pages/welcome.jsp/%2e%2e/%2e%2e/WEB-INF/web.xml" becomes /pages/welcome.jsp/%2e%2e/%2e%2e/WEB-INF/web.xml, which will pass this check and potentially be problematic if decoded later?
if (requestedPath.startsWith(BASE_PATH)) {
- request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response);
+ request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response); // $ hasUrlForward
}
}
- // FN: Request dispatcher with negation check and path normalization, but without URL decoding
- // When promoting this query, consider using FlowStates to make `getRequestDispatcher` a sink
- // only if a URL-decoding step has NOT been crossed (i.e. make URLDecoder.decode change the
- // state to a different value than the one required at the sink).
- // TODO: but does this need to take into account URLDecoder.decode in a loop...?
+ // BAD (original FN): Request dispatcher with negation check and path normalization, but without URL decoding
protected void doHead5(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
Path requestedPath = Paths.get(BASE_PATH).resolve(path).normalize();
if (!requestedPath.startsWith("/WEB-INF") && !requestedPath.startsWith("/META-INF")) {
- request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response); // $ MISSING: hasUrlForward
+ request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response); // $ hasUrlForward
}
}
- // GOOD: Request dispatcher with path traversal check and URL decoding
- protected void doHead6(HttpServletRequest request, HttpServletResponse response)
+ // BAD (I added to test decode with no loop): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
+ protected void doHead7(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
- boolean hasEncoding = path.contains("%");
- while (hasEncoding) {
- path = URLDecoder.decode(path, "UTF-8");
- hasEncoding = path.contains("%");
+ path = URLDecoder.decode(path, "UTF-8");
+
+ if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
+ request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
+ }
+ }
+
+ // GOOD: Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
+ protected void doHead6(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path"); // v
+
+ if (path.contains("%")){ // v.getAnAccess()
+ while (path.contains("%")) {
+ path = URLDecoder.decode(path, "UTF-8");
+ }
}
if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
@@ -247,10 +259,107 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
}
- // New Tests (i.e. Added by me)
+ // GOOD: Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
+ protected void doHead8(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path"); // v
+ while (path.contains("%")) {
+ path = URLDecoder.decode(path, "UTF-8");
+ }
+
+ if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
+ request.getServletContext().getRequestDispatcher(path).include(request, response);
+ }
+ }
+
+ // FP now....
+ // GOOD: Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
+ protected void doHead9(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path"); // v
+ boolean hasEncoding = path.contains("%");
+ while (hasEncoding) {
+ path = URLDecoder.decode(path, "UTF-8");
+ hasEncoding = path.contains("%");
+ }
+
+ if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
+ request.getServletContext().getRequestDispatcher(path).include(request, response); // $ SPURIOUS: hasUrlForward
+ }
+ }
+
+ // New Tests
public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object obj) throws IOException, ServletException {
String url = req.getParameter("target");
rsp.forward(obj, url, req); // $ hasUrlForward
}
+ // Other Tests for edge cases:
+ // // GOOD (I added): Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
+ // // testing `if` stmt requirement for BB controlling
+ // protected void doHead12(HttpServletRequest request, HttpServletResponse response)
+ // throws ServletException, IOException {
+ // String path = request.getParameter("path");
+ // if (path.contains("%")) {
+ // while (path.contains("%")) {
+ // path = URLDecoder.decode(path, "UTF-8");
+ // }
+ // }
+ // if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
+ // request.getServletContext().getRequestDispatcher(path).include(request, response);
+ // }
+ // }
+ // // BAD (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
+ // // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
+ // // having previously been checked against a block-list of forbidden values."
+ // protected void doHead8(HttpServletRequest request, HttpServletResponse response)
+ // throws ServletException, IOException {
+ // String path = request.getParameter("path");
+
+ // if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
+ // boolean hasEncoding = path.contains("%"); // BAD: doesn't do anything with the check...
+ // request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
+ // }
+ // }
+ // // BAD (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
+ // // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
+ // // having previously been checked against a block-list of forbidden values."
+ // protected void doHead9(HttpServletRequest request, HttpServletResponse response)
+ // throws ServletException, IOException {
+ // String path = request.getParameter("path");
+
+ // boolean hasEncoding = path.contains("%"); // BAD: doesn't do anything with the check... and check comes BEFORE blocklist so guard should not trigger
+ // if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
+ // request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
+ // }
+ // }
+
+ // // BAD (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
+ // // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
+ // // having previously been checked against a block-list of forbidden values."
+ // protected void doHead10(HttpServletRequest request, HttpServletResponse response)
+ // throws ServletException, IOException {
+ // String path = request.getParameter("path");
+
+ // if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
+ // if (path.contains("%")){ // BAD: wrong check
+ // request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
+ // }
+ // }
+ // }
+
+ // // "GOOD" (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
+ // // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
+ // // having previously been checked against a block-list of forbidden values."
+ // protected void doHead11(HttpServletRequest request, HttpServletResponse response)
+ // throws ServletException, IOException {
+ // String path = request.getParameter("path");
+
+ // if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
+ // if (!path.contains("%")){ // GOOD: right check
+ // request.getServletContext().getRequestDispatcher(path).include(request, response);
+ // }
+ // }
+ // }
+
}
From f573032b2e74ccf8165650b83602b08a8f2af126 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 5 Mar 2024 13:56:35 -0500
Subject: [PATCH 055/497] Java: remove todo comments from ext files
---
java/ql/lib/ext/jakarta.servlet.model.yml | 1 -
java/ql/lib/ext/javax.portlet.model.yml | 1 -
java/ql/lib/ext/javax.servlet.model.yml | 1 -
3 files changed, 3 deletions(-)
diff --git a/java/ql/lib/ext/jakarta.servlet.model.yml b/java/ql/lib/ext/jakarta.servlet.model.yml
index fc1274cadaf..be2feeb3c37 100644
--- a/java/ql/lib/ext/jakarta.servlet.model.yml
+++ b/java/ql/lib/ext/jakarta.servlet.model.yml
@@ -3,6 +3,5 @@ extensions:
pack: codeql/java-all
extensible: sinkModel
data:
- # TODO: potentially switch to using Argument[this] of `RequestDispatcher.forward|include` as sink instead of the below.
- ["jakarta.servlet", "ServletContext", True, "getRequestDispatcher", "(String)", "", "Argument[0]", "url-forward", "manual"]
- ["jakarta.servlet", "ServletRequest", True, "getRequestDispatcher", "(String)", "", "Argument[0]", "url-forward", "manual"]
diff --git a/java/ql/lib/ext/javax.portlet.model.yml b/java/ql/lib/ext/javax.portlet.model.yml
index e39484abcb7..15d10886624 100644
--- a/java/ql/lib/ext/javax.portlet.model.yml
+++ b/java/ql/lib/ext/javax.portlet.model.yml
@@ -3,5 +3,4 @@ extensions:
pack: codeql/java-all
extensible: sinkModel
data:
- # TODO: potentially switch to using Argument[this] of `PortletRequestDispatcher.forward|include` as sink instead of the below.
- ["javax.portlet", "PortletContext", True, "getRequestDispatcher", "(String)", "", "Argument[0]", "url-forward", "manual"]
diff --git a/java/ql/lib/ext/javax.servlet.model.yml b/java/ql/lib/ext/javax.servlet.model.yml
index 7c405ac0de9..d27011c6e12 100644
--- a/java/ql/lib/ext/javax.servlet.model.yml
+++ b/java/ql/lib/ext/javax.servlet.model.yml
@@ -14,7 +14,6 @@ extensions:
extensible: sinkModel
data:
- ["javax.servlet", "ServletContext", True, "getResourceAsStream", "(String)", "", "Argument[0]", "path-injection", "ai-manual"]
- # TODO: potentially switch to using Argument[this] of `RequestDispatcher.forward|include` as sink instead of the below.
- ["javax.servlet", "ServletContext", True, "getRequestDispatcher", "(String)", "", "Argument[0]", "url-forward", "manual"]
- ["javax.servlet", "ServletRequest", True, "getRequestDispatcher", "(String)", "", "Argument[0]", "url-forward", "manual"]
- addsTo:
From 2708e53c7f3b54f1755596513aad1b444457ee9b Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 5 Mar 2024 14:02:41 -0500
Subject: [PATCH 056/497] Java: remove redundant imports
---
java/ql/lib/semmle/code/java/security/UrlForward.qll | 1 -
java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll | 1 -
2 files changed, 2 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index 073507fe33a..79f8e5f2b28 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -5,7 +5,6 @@ private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.StringPrefixes
private import semmle.code.java.security.PathSanitizer
-private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.controlflow.Guards
/** A URL forward sink. */
diff --git a/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll b/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll
index 71d41f42dee..30de4ef8354 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll
@@ -3,7 +3,6 @@
import java
import semmle.code.java.security.UrlForward
import semmle.code.java.dataflow.FlowSources
-import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.security.PathSanitizer
/**
From 43b49628fc54cd2de38768e14ff9f22720852919 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 5 Mar 2024 14:36:43 -0500
Subject: [PATCH 057/497] Java: use new 'SimpleTypeSanitizer', and update some
non-extending subtype relationships
---
.../semmle/code/java/security/UrlForward.qll | 17 ++++-------------
1 file changed, 4 insertions(+), 13 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index 79f8e5f2b28..d19b8c163fd 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -6,6 +6,7 @@ private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.StringPrefixes
private import semmle.code.java.security.PathSanitizer
private import semmle.code.java.controlflow.Guards
+private import semmle.code.java.security.Sanitizers
/** A URL forward sink. */
abstract class UrlForwardSink extends DataFlow::Node { }
@@ -38,13 +39,7 @@ private class ForwardPrefix extends InterestingPrefix {
/** A URL forward barrier. */
abstract class UrlForwardBarrier extends DataFlow::Node { }
-private class PrimitiveBarrier extends UrlForwardBarrier {
- PrimitiveBarrier() {
- this.getType() instanceof PrimitiveType or
- this.getType() instanceof BoxedType or
- this.getType() instanceof NumberType
- }
-}
+private class PrimitiveBarrier extends UrlForwardBarrier instanceof SimpleTypeSanitizer { }
// TODO: should this also take URL encoding/decoding into account?
// TODO: and PathSanitization in general?
@@ -87,9 +82,7 @@ private class DefaultUrlDecodeCall extends UrlDecodeCall {
// TODO: this can probably be named/designed better...
abstract class RepeatedStmt extends Stmt { }
-private class DefaultRepeatedStmt extends RepeatedStmt {
- DefaultRepeatedStmt() { this instanceof LoopStmt }
-}
+private class DefaultRepeatedStmt extends RepeatedStmt instanceof LoopStmt { }
abstract class CheckEncodingCall extends MethodCall { }
@@ -111,9 +104,7 @@ private class RepeatedUrlDecodeCall extends MethodCall {
}
}
-private class CheckEncodingGuard extends Guard instanceof MethodCall {
- CheckEncodingGuard() { this instanceof CheckEncodingCall }
-
+private class CheckEncodingGuard extends Guard instanceof MethodCall, CheckEncodingCall {
Expr getCheckedExpr() { result = this.(MethodCall).getQualifier() }
}
From d9772c1880bb269c0c8e61db3beae8587bae8822 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 5 Mar 2024 15:04:43 -0500
Subject: [PATCH 058/497] Java: update change note
---
java/ql/src/change-notes/2023-12-12-url-forward-query.md | 4 ----
java/ql/src/change-notes/2024-03-06-url-forward-query.md | 4 ++++
2 files changed, 4 insertions(+), 4 deletions(-)
delete mode 100644 java/ql/src/change-notes/2023-12-12-url-forward-query.md
create mode 100644 java/ql/src/change-notes/2024-03-06-url-forward-query.md
diff --git a/java/ql/src/change-notes/2023-12-12-url-forward-query.md b/java/ql/src/change-notes/2023-12-12-url-forward-query.md
deleted file mode 100644
index 4efc4b7c4e0..00000000000
--- a/java/ql/src/change-notes/2023-12-12-url-forward-query.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-category: newQuery
----
-* The query `java/unsafe-url-forward-dispatch-load` has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally submitted as an experimental query [by @haby0](https://github.com/github/codeql/pull/6240) and [by @luchua-bc](https://github.com/github/codeql/pull/7286).
diff --git a/java/ql/src/change-notes/2024-03-06-url-forward-query.md b/java/ql/src/change-notes/2024-03-06-url-forward-query.md
new file mode 100644
index 00000000000..46028bda4f2
--- /dev/null
+++ b/java/ql/src/change-notes/2024-03-06-url-forward-query.md
@@ -0,0 +1,4 @@
+---
+category: newQuery
+---
+* The query `java/unsafe-url-forward-dispatch-load` has been promoted from experimental to the main query pack as `java/unvalidated-url-forward`. Its results will now appear by default. This query was originally submitted as an experimental query [by @haby0](https://github.com/github/codeql/pull/6240) and [by @luchua-bc](https://github.com/github/codeql/pull/7286).
From d220b3a298044753382b0677d054e51da23a1246 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Sun, 10 Mar 2024 14:42:46 -0400
Subject: [PATCH 059/497] Java: some updates to test cases
---
.../code/java/security/PathSanitizer.qll | 9 +-
.../semmle/code/java/security/UrlForward.qll | 19 +--
.../security/CWE-552/UrlForwardTest.java | 159 +++++++++---------
3 files changed, 88 insertions(+), 99 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/security/PathSanitizer.qll b/java/ql/lib/semmle/code/java/security/PathSanitizer.qll
index f3c54629efd..77803e3e27d 100644
--- a/java/ql/lib/semmle/code/java/security/PathSanitizer.qll
+++ b/java/ql/lib/semmle/code/java/security/PathSanitizer.qll
@@ -64,7 +64,10 @@ private predicate exactPathMatchGuard(Guard g, Expr e, boolean branch) {
)
}
-// TODO: switch back to private if possible
+/**
+ * A sanitizer that protects against path injection vulnerabilities
+ * by checking for a matching path.
+ */
class ExactPathMatchSanitizer extends PathInjectionSanitizer {
ExactPathMatchSanitizer() {
this = DataFlow::BarrierGuard::getABarrierNode()
@@ -152,8 +155,7 @@ private class DotDotCheckSanitizer extends PathInjectionSanitizer {
}
}
-// TODO: switch back to private if possible
-class BlockListGuard extends PathGuard instanceof MethodCall {
+private class BlockListGuard extends PathGuard instanceof MethodCall {
BlockListGuard() {
(isStringPartialMatch(this) or isPathPrefixMatch(this)) and
isDisallowedWord(super.getAnArgument())
@@ -230,7 +232,6 @@ private predicate isStringPartialMatch(MethodCall ma) {
exists(RefType t | t = ma.getMethod().getDeclaringType() |
t instanceof TypeString or t instanceof StringsKt
) and
- // TODO ! Why not use `StringPartialMatchMethod` for the below?
getSourceMethod(ma.getMethod())
.hasName(["contains", "matches", "regionMatches", "indexOf", "lastIndexOf"])
}
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index d19b8c163fd..f7001023689 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -50,23 +50,20 @@ private class FollowsBarrierPrefix extends UrlForwardBarrier {
private class BarrierPrefix extends InterestingPrefix {
BarrierPrefix() {
not this.getStringValue().matches("/WEB-INF/%") and
- not this.getStringValue() = "forward:"
+ not this instanceof ForwardPrefix
}
override int getOffset() { result = 0 }
}
-private class UrlPathBarrier extends UrlForwardBarrier {
+private class UrlPathBarrier extends UrlForwardBarrier instanceof PathInjectionSanitizer {
UrlPathBarrier() {
- this instanceof PathInjectionSanitizer and
- (
- this instanceof ExactPathMatchSanitizer //TODO: still need a better solution for this edge case...
- or
- // TODO: these don't enforce order of checks and PathSanitization... make bypass test cases.
- this instanceof NoEncodingBarrier
- or
- this instanceof FullyDecodesBarrier
- )
+ this instanceof ExactPathMatchSanitizer //TODO: still need a better solution for this edge case...
+ or
+ // TODO: these don't enforce order of checks and PathSanitization... make bypass test cases.
+ this instanceof NoEncodingBarrier
+ or
+ this instanceof FullyDecodesBarrier
}
}
diff --git a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
index c7a9d82b1a0..9b94f3f5724 100644
--- a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
+++ b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
@@ -23,7 +23,7 @@ import org.kohsuke.stapler.StaplerResponse;
@Controller
public class UrlForwardTest extends HttpServlet implements Filter {
- // (1) ORIGINAL
+ // Spring-related test cases
@GetMapping("/bad1")
public ModelAndView bad1(String url) {
return new ModelAndView(url); // $ hasUrlForward
@@ -91,7 +91,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
}
- // (2) UnsafeRequestPath
+ // Non-Spring test cases (UnsafeRequest*Path*)
private static final String BASE_PATH = "/pages";
@Override
@@ -107,12 +107,12 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
}
- // GOOD: Request dispatcher from servlet path with check
+ // BAD: Request dispatcher from servlet path with check that does not decode
+ // the user-supplied path; could bypass check with ".." encoded as "%2e%2e".
public void doFilter2(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
String path = ((HttpServletRequest) request).getServletPath();
- // actually BAD since could potentially bypass with ".." encoded as "%2e%2e"?
if (path.startsWith(BASE_PATH) && !path.contains("..")) {
request.getRequestDispatcher(path).forward(request, response); // $ hasUrlForward
} else {
@@ -125,7 +125,6 @@ public class UrlForwardTest extends HttpServlet implements Filter {
throws IOException, ServletException {
String path = ((HttpServletRequest) request).getServletPath();
- // this is still good, should not flag here..., url-decoding first doesn't matter if looking for exact match... :(
if (path.equals("/comaction")) {
request.getRequestDispatcher(path).forward(request, response);
} else {
@@ -133,7 +132,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
}
- // (3) UnsafeServletRequestDispatch
+ // Non-Spring test cases (UnsafeServletRequest*Dispatch*)
@Override
// BAD: Request dispatcher constructed from `ServletContext` without input validation
protected void doGet(HttpServletRequest request, HttpServletResponse response)
@@ -190,41 +189,41 @@ public class UrlForwardTest extends HttpServlet implements Filter {
String path = request.getParameter("path");
// A sample payload "/pages/welcome.jsp/../WEB-INF/web.xml" can bypass the `startsWith` check
- // The payload "/pages/welcome.jsp/../../%57EB-INF/web.xml" can bypass the check as well since RequestDispatcher will decode `%57` as `W`
if (path.startsWith(BASE_PATH)) {
request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
}
}
- // GOOD: Request dispatcher with path traversal check
+ // BAD: Request dispatcher with path traversal check that does not decode
+ // the user-supplied path; could bypass check with ".." encoded as "%2e%2e".
protected void doHead3(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
- // actually BAD since could potentially bypass with ".." encoded as "%2e%2e"?
if (path.startsWith(BASE_PATH) && !path.contains("..")) {
request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
}
}
- // GOOD: Request dispatcher with path normalization and comparison
+ // BAD: Request dispatcher with path normalization and comparison, but
+ // does not decode before normalization.
protected void doHead4(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
+
+ // Since not decoded before normalization, "%2e%2e" can remain in the path
Path requestedPath = Paths.get(BASE_PATH).resolve(path).normalize();
- // /pages/welcome.jsp/../../WEB-INF/web.xml becomes /WEB-INF/web.xml
- // /pages/welcome.jsp/../../%57EB-INF/web.xml becomes /%57EB-INF/web.xml
- // actually BAD since could potentially bypass with ".." encoded as "%2e%2e": "/pages/welcome.jsp/%2e%2e/%2e%2e/WEB-INF/web.xml" becomes /pages/welcome.jsp/%2e%2e/%2e%2e/WEB-INF/web.xml, which will pass this check and potentially be problematic if decoded later?
if (requestedPath.startsWith(BASE_PATH)) {
request.getServletContext().getRequestDispatcher(requestedPath.toString()).forward(request, response); // $ hasUrlForward
}
}
- // BAD (original FN): Request dispatcher with negation check and path normalization, but without URL decoding
+ // BAD: Request dispatcher with negation check and path normalization, but without URL decoding.
protected void doHead5(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
+ // Since not decoded before normalization, "/%57EB-INF" can remain in the path and pass the `startsWith` check.
Path requestedPath = Paths.get(BASE_PATH).resolve(path).normalize();
if (!requestedPath.startsWith("/WEB-INF") && !requestedPath.startsWith("/META-INF")) {
@@ -232,7 +231,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
}
- // BAD (I added to test decode with no loop): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
+ // BAD: Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
protected void doHead7(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
@@ -246,9 +245,9 @@ public class UrlForwardTest extends HttpServlet implements Filter {
// GOOD: Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
protected void doHead6(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
- String path = request.getParameter("path"); // v
+ String path = request.getParameter("path"); // TODO: remove this debugging comment: // v
- if (path.contains("%")){ // v.getAnAccess()
+ if (path.contains("%")){ // TODO: remove this debugging comment: // v.getAnAccess()
while (path.contains("%")) {
path = URLDecoder.decode(path, "UTF-8");
}
@@ -259,10 +258,53 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
}
+ // GOOD: Request dispatcher with URL encoding check and path traversal check
+ protected void doHead16(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path");
+
+ if (!path.contains("%")){
+ if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
+ request.getServletContext().getRequestDispatcher(path).include(request, response);
+ }
+ }
+ }
+
+ // TODO: clean-up
+ // BAD (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
+ // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
+ // having previously been checked against a block-list of forbidden values."
+ protected void doHead10(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path");
+ if (path.contains("%")){ // BAD: wrong check
+ if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
+ // if (path.contains("%")){ // BAD: wrong check
+ request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
+ // }
+ }
+ }
+ }
+
+ // TODO: clean-up
+ // "GOOD" (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
+ // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
+ // having previously been checked against a block-list of forbidden values."
+ protected void doHead11(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String path = request.getParameter("path");
+
+ if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
+ if (!path.contains("%")){ // GOOD: right check
+ request.getServletContext().getRequestDispatcher(path).include(request, response);
+ }
+ }
+ }
+
// GOOD: Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
protected void doHead8(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
- String path = request.getParameter("path"); // v
+ String path = request.getParameter("path"); // TODO: remove this debugging comment: // v
while (path.contains("%")) {
path = URLDecoder.decode(path, "UTF-8");
}
@@ -272,6 +314,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
}
+ // TODO: see if can fix?
// FP now....
// GOOD: Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
protected void doHead9(HttpServletRequest request, HttpServletResponse response)
@@ -288,78 +331,26 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
}
- // New Tests
+ // BAD: `StaplerResponse.forward` without any checks
public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object obj) throws IOException, ServletException {
String url = req.getParameter("target");
rsp.forward(obj, url, req); // $ hasUrlForward
}
- // Other Tests for edge cases:
- // // GOOD (I added): Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
- // // testing `if` stmt requirement for BB controlling
- // protected void doHead12(HttpServletRequest request, HttpServletResponse response)
- // throws ServletException, IOException {
- // String path = request.getParameter("path");
- // if (path.contains("%")) {
- // while (path.contains("%")) {
- // path = URLDecoder.decode(path, "UTF-8");
- // }
- // }
- // if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
- // request.getServletContext().getRequestDispatcher(path).include(request, response);
- // }
- // }
- // // BAD (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
- // // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
- // // having previously been checked against a block-list of forbidden values."
- // protected void doHead8(HttpServletRequest request, HttpServletResponse response)
- // throws ServletException, IOException {
- // String path = request.getParameter("path");
+ // QHelp example
+ private static final String VALID_FORWARD = "https://cwe.mitre.org/data/definitions/552.html";
- // if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
- // boolean hasEncoding = path.contains("%"); // BAD: doesn't do anything with the check...
- // request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
- // }
- // }
- // // BAD (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
- // // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
- // // having previously been checked against a block-list of forbidden values."
- // protected void doHead9(HttpServletRequest request, HttpServletResponse response)
- // throws ServletException, IOException {
- // String path = request.getParameter("path");
+ protected void doGet2(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ ServletConfig cfg = getServletConfig();
+ ServletContext sc = cfg.getServletContext();
- // boolean hasEncoding = path.contains("%"); // BAD: doesn't do anything with the check... and check comes BEFORE blocklist so guard should not trigger
- // if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
- // request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
- // }
- // }
-
- // // BAD (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
- // // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
- // // having previously been checked against a block-list of forbidden values."
- // protected void doHead10(HttpServletRequest request, HttpServletResponse response)
- // throws ServletException, IOException {
- // String path = request.getParameter("path");
-
- // if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
- // if (path.contains("%")){ // BAD: wrong check
- // request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
- // }
- // }
- // }
-
- // // "GOOD" (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
- // // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
- // // having previously been checked against a block-list of forbidden values."
- // protected void doHead11(HttpServletRequest request, HttpServletResponse response)
- // throws ServletException, IOException {
- // String path = request.getParameter("path");
-
- // if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
- // if (!path.contains("%")){ // GOOD: right check
- // request.getServletContext().getRequestDispatcher(path).include(request, response);
- // }
- // }
- // }
+ // BAD: a request parameter is incorporated without validation into a URL forward
+ sc.getRequestDispatcher(request.getParameter("target")).forward(request, response); // $ hasUrlForward
+ // GOOD: the request parameter is validated against a known fixed string
+ if (VALID_FORWARD.equals(request.getParameter("target"))) {
+ sc.getRequestDispatcher(VALID_FORWARD).forward(request, response);
+ }
+ }
}
From 052452b18666e793783032da33fd1863e5d7121f Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Sun, 10 Mar 2024 15:54:11 -0400
Subject: [PATCH 060/497] Java: create UrlDecodeMethod
---
.../lib/semmle/code/java/frameworks/Networking.qll | 13 +++++++++++++
.../ql/lib/semmle/code/java/security/UrlForward.qll | 7 ++-----
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/frameworks/Networking.qll b/java/ql/lib/semmle/code/java/frameworks/Networking.qll
index c473cc9fc09..f86cecd5b4e 100644
--- a/java/ql/lib/semmle/code/java/frameworks/Networking.qll
+++ b/java/ql/lib/semmle/code/java/frameworks/Networking.qll
@@ -24,6 +24,11 @@ class TypeUrl extends RefType {
TypeUrl() { this.hasQualifiedName("java.net", "URL") }
}
+/** The type `java.net.URLDecoder`. */
+class TypeUrlDecoder extends RefType {
+ TypeUrlDecoder() { this.hasQualifiedName("java.net", "URLDecoder") }
+}
+
/** The type `java.net.URI`. */
class TypeUri extends RefType {
TypeUri() { this.hasQualifiedName("java.net", "URI") }
@@ -157,6 +162,14 @@ class UrlOpenConnectionMethod extends Method {
}
}
+/** The method `java.net.URLDecoder::decode`. */
+class UrlDecodeMethod extends Method {
+ UrlDecodeMethod() {
+ this.getDeclaringType() instanceof TypeUrlDecoder and
+ this.getName() = "decode"
+ }
+}
+
/** The method `javax.net.SocketFactory::createSocket`. */
class CreateSocketMethod extends Method {
CreateSocketMethod() {
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index f7001023689..be9bfb91043 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -41,8 +41,6 @@ abstract class UrlForwardBarrier extends DataFlow::Node { }
private class PrimitiveBarrier extends UrlForwardBarrier instanceof SimpleTypeSanitizer { }
-// TODO: should this also take URL encoding/decoding into account?
-// TODO: and PathSanitization in general?
private class FollowsBarrierPrefix extends UrlForwardBarrier {
FollowsBarrierPrefix() { this.asExpr() = any(BarrierPrefix fp).getAnAppendedExpression() }
}
@@ -58,9 +56,8 @@ private class BarrierPrefix extends InterestingPrefix {
private class UrlPathBarrier extends UrlForwardBarrier instanceof PathInjectionSanitizer {
UrlPathBarrier() {
- this instanceof ExactPathMatchSanitizer //TODO: still need a better solution for this edge case...
+ this instanceof ExactPathMatchSanitizer
or
- // TODO: these don't enforce order of checks and PathSanitization... make bypass test cases.
this instanceof NoEncodingBarrier
or
this instanceof FullyDecodesBarrier
@@ -71,7 +68,7 @@ abstract class UrlDecodeCall extends MethodCall { }
private class DefaultUrlDecodeCall extends UrlDecodeCall {
DefaultUrlDecodeCall() {
- this.getMethod().hasQualifiedName("java.net", "URLDecoder", "decode") or // TODO: reuse existing class? Or make this a class?
+ this.getMethod() instanceof UrlDecodeMethod or
this.getMethod().hasQualifiedName("org.eclipse.jetty.util.URIUtil", "URIUtil", "decodePath")
}
}
From 042dcf9cd961e2b24b30220b8f7618221022f339 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Sun, 10 Mar 2024 16:50:41 -0400
Subject: [PATCH 061/497] Java: some updates to UrlPathBarrier code
---
java/ql/lib/semmle/code/java/JDK.qll | 7 ++
.../semmle/code/java/security/UrlForward.qll | 69 +++++++++----------
2 files changed, 38 insertions(+), 38 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/JDK.qll b/java/ql/lib/semmle/code/java/JDK.qll
index 7623cc87393..55d420dbcae 100644
--- a/java/ql/lib/semmle/code/java/JDK.qll
+++ b/java/ql/lib/semmle/code/java/JDK.qll
@@ -38,6 +38,13 @@ class StringLengthMethod extends Method {
StringLengthMethod() { this.hasName("length") and this.getDeclaringType() instanceof TypeString }
}
+/** The `contains()` method of the class `java.lang.String`. */
+class StringContainsMethod extends Method {
+ StringContainsMethod() {
+ this.hasName("contains") and this.getDeclaringType() instanceof TypeString
+ }
+}
+
/**
* The methods on the class `java.lang.String` that are used to perform partial matches with a specified substring or char.
*/
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index be9bfb91043..8f1b978cbfc 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -58,12 +58,13 @@ private class UrlPathBarrier extends UrlForwardBarrier instanceof PathInjectionS
UrlPathBarrier() {
this instanceof ExactPathMatchSanitizer
or
- this instanceof NoEncodingBarrier
+ this instanceof NoUrlEncodingBarrier
or
- this instanceof FullyDecodesBarrier
+ this instanceof FullyDecodesUrlBarrier
}
}
+/** A call to a method that decodes a URL. */
abstract class UrlDecodeCall extends MethodCall { }
private class DefaultUrlDecodeCall extends UrlDecodeCall {
@@ -73,77 +74,69 @@ private class DefaultUrlDecodeCall extends UrlDecodeCall {
}
}
-// TODO: this can probably be named/designed better...
-abstract class RepeatedStmt extends Stmt { }
+/** A repeated call to a method that decodes a URL. */
+abstract class RepeatedUrlDecodeCall extends MethodCall { }
-private class DefaultRepeatedStmt extends RepeatedStmt instanceof LoopStmt { }
+private class DefaultRepeatedUrlDecodeCall extends RepeatedUrlDecodeCall {
+ DefaultRepeatedUrlDecodeCall() {
+ this instanceof UrlDecodeCall and
+ this.getAnEnclosingStmt() instanceof LoopStmt
+ }
+}
-abstract class CheckEncodingCall extends MethodCall { }
+/** A method call that checks a string for URL encoding. */
+abstract class CheckUrlEncodingCall extends MethodCall { }
-private class DefaultCheckEncodingCall extends CheckEncodingCall {
- DefaultCheckEncodingCall() {
- // TODO: indexOf?, etc.
- this.getMethod().hasQualifiedName("java.lang", "String", "contains") and // TODO: reuse existing class? Or make this a class?
+private class DefaultCheckUrlEncodingCall extends CheckUrlEncodingCall {
+ DefaultCheckUrlEncodingCall() {
+ this.getMethod() instanceof StringContainsMethod and
this.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "%"
}
}
-// TODO: better naming?
-// TODO: check if any URL decoding implementations _fully_ decode... or if all need to be called in a loop?
-// TODO: make this extendable instead of `RepeatedStmt`?
-private class RepeatedUrlDecodeCall extends MethodCall {
- RepeatedUrlDecodeCall() {
- this instanceof UrlDecodeCall and
- this.getAnEnclosingStmt() instanceof RepeatedStmt
- }
-}
-
-private class CheckEncodingGuard extends Guard instanceof MethodCall, CheckEncodingCall {
+private class CheckUrlEncodingGuard extends Guard instanceof CheckUrlEncodingCall {
Expr getCheckedExpr() { result = this.(MethodCall).getQualifier() }
}
-private predicate noEncodingGuard(Guard g, Expr e, boolean branch) {
- g instanceof CheckEncodingGuard and
- e = g.(CheckEncodingGuard).getCheckedExpr() and
+private predicate noUrlEncodingGuard(Guard g, Expr e, boolean branch) {
+ g instanceof CheckUrlEncodingGuard and
+ e = g.(CheckUrlEncodingGuard).getCheckedExpr() and
branch = false
or
- // branch = false and
- // g instanceof AssignExpr and // AssignExpr
- // exists(CheckEncodingCall call | g.(AssignExpr).getSource() = call | e = call.getQualifier())
branch = false and
- g.(Expr).getType() instanceof BooleanType and // AssignExpr
+ g.(Expr).getType() instanceof BooleanType and // TODO: remove debugging comment: // AssignExpr
(
- exists(CheckEncodingCall call, AssignExpr ae |
+ exists(CheckUrlEncodingCall call, AssignExpr ae |
ae.getSource() = call and
e = call.getQualifier() and
g = ae.getDest()
)
or
- exists(CheckEncodingCall call, LocalVariableDeclExpr vde |
+ exists(CheckUrlEncodingCall call, LocalVariableDeclExpr vde |
vde.getInitOrPatternSource() = call and
e = call.getQualifier() and
g = vde.getAnAccess() //and
//vde.getVariable() = g
+ // TODO: remove debugging comments above
)
)
}
-// TODO: check edge case of !contains(%), make sure that behaves as expected at least.
-private class NoEncodingBarrier extends DataFlow::Node {
- NoEncodingBarrier() { this = DataFlow::BarrierGuard::getABarrierNode() }
+private class NoUrlEncodingBarrier extends DataFlow::Node {
+ NoUrlEncodingBarrier() { this = DataFlow::BarrierGuard::getABarrierNode() }
}
-private predicate fullyDecodesGuard(Expr e) {
- exists(CheckEncodingGuard g, RepeatedUrlDecodeCall decodeCall |
+private predicate fullyDecodesUrlGuard(Expr e) {
+ exists(CheckUrlEncodingGuard g, RepeatedUrlDecodeCall decodeCall |
e = g.getCheckedExpr() and
g.controls(decodeCall.getBasicBlock(), true)
)
}
-private class FullyDecodesBarrier extends DataFlow::Node {
- FullyDecodesBarrier() {
+private class FullyDecodesUrlBarrier extends DataFlow::Node {
+ FullyDecodesUrlBarrier() {
exists(Variable v, Expr e | this.asExpr() = v.getAnAccess() |
- fullyDecodesGuard(e) and
+ fullyDecodesUrlGuard(e) and
e = v.getAnAccess() and
e.getBasicBlock().bbDominates(this.asExpr().getBasicBlock())
)
From a8075969d886bc86ef60b12f10bdf551f4145eba Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Sun, 10 Mar 2024 18:33:00 -0400
Subject: [PATCH 062/497] Java: add QLDocs to UrlPathBarrier code
---
.../semmle/code/java/security/UrlForward.qll | 21 +++++++++++--------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index 8f1b978cbfc..d4cad4e2f54 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -41,10 +41,12 @@ abstract class UrlForwardBarrier extends DataFlow::Node { }
private class PrimitiveBarrier extends UrlForwardBarrier instanceof SimpleTypeSanitizer { }
+// TODO: QLDoc
private class FollowsBarrierPrefix extends UrlForwardBarrier {
FollowsBarrierPrefix() { this.asExpr() = any(BarrierPrefix fp).getAnAppendedExpression() }
}
+// TODO: QLDoc and fix broadness of this prefix check...
private class BarrierPrefix extends InterestingPrefix {
BarrierPrefix() {
not this.getStringValue().matches("/WEB-INF/%") and
@@ -54,6 +56,7 @@ private class BarrierPrefix extends InterestingPrefix {
override int getOffset() { result = 0 }
}
+/** A barrier that protects against path injection vulnerabilities while accounting for URL encoding. */
private class UrlPathBarrier extends UrlForwardBarrier instanceof PathInjectionSanitizer {
UrlPathBarrier() {
this instanceof ExactPathMatchSanitizer
@@ -77,11 +80,8 @@ private class DefaultUrlDecodeCall extends UrlDecodeCall {
/** A repeated call to a method that decodes a URL. */
abstract class RepeatedUrlDecodeCall extends MethodCall { }
-private class DefaultRepeatedUrlDecodeCall extends RepeatedUrlDecodeCall {
- DefaultRepeatedUrlDecodeCall() {
- this instanceof UrlDecodeCall and
- this.getAnEnclosingStmt() instanceof LoopStmt
- }
+private class DefaultRepeatedUrlDecodeCall extends RepeatedUrlDecodeCall instanceof UrlDecodeCall {
+ DefaultRepeatedUrlDecodeCall() { this.getAnEnclosingStmt() instanceof LoopStmt }
}
/** A method call that checks a string for URL encoding. */
@@ -94,17 +94,19 @@ private class DefaultCheckUrlEncodingCall extends CheckUrlEncodingCall {
}
}
+/** A guard that looks for a method call that checks for URL encoding. */
private class CheckUrlEncodingGuard extends Guard instanceof CheckUrlEncodingCall {
Expr getCheckedExpr() { result = this.(MethodCall).getQualifier() }
}
+/** Holds if `g` is guard for a URL that does not contain URL encoding. */
private predicate noUrlEncodingGuard(Guard g, Expr e, boolean branch) {
g instanceof CheckUrlEncodingGuard and
e = g.(CheckUrlEncodingGuard).getCheckedExpr() and
branch = false
or
branch = false and
- g.(Expr).getType() instanceof BooleanType and // TODO: remove debugging comment: // AssignExpr
+ g.(Expr).getType() instanceof BooleanType and
(
exists(CheckUrlEncodingCall call, AssignExpr ae |
ae.getSource() = call and
@@ -115,17 +117,17 @@ private predicate noUrlEncodingGuard(Guard g, Expr e, boolean branch) {
exists(CheckUrlEncodingCall call, LocalVariableDeclExpr vde |
vde.getInitOrPatternSource() = call and
e = call.getQualifier() and
- g = vde.getAnAccess() //and
- //vde.getVariable() = g
- // TODO: remove debugging comments above
+ g = vde.getAnAccess()
)
)
}
+/** A barrier for URLs that do not contain URL encoding. */
private class NoUrlEncodingBarrier extends DataFlow::Node {
NoUrlEncodingBarrier() { this = DataFlow::BarrierGuard::getABarrierNode() }
}
+/** Holds if `g` is guard for a URL that is fully decoded. */
private predicate fullyDecodesUrlGuard(Expr e) {
exists(CheckUrlEncodingGuard g, RepeatedUrlDecodeCall decodeCall |
e = g.getCheckedExpr() and
@@ -133,6 +135,7 @@ private predicate fullyDecodesUrlGuard(Expr e) {
)
}
+/** A barrier for URLs that are fully decoded. */
private class FullyDecodesUrlBarrier extends DataFlow::Node {
FullyDecodesUrlBarrier() {
exists(Variable v, Expr e | this.asExpr() = v.getAnAccess() |
From a002674587b255694088bed6768b8c16cf6ffac9 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Sun, 10 Mar 2024 21:22:35 -0400
Subject: [PATCH 063/497] Java: clean up comments on test cases
---
.../security/CWE-552/UrlForwardTest.java | 59 ++++++++-----------
1 file changed, 26 insertions(+), 33 deletions(-)
diff --git a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
index 9b94f3f5724..e66b5c899c7 100644
--- a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
+++ b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
@@ -23,7 +23,7 @@ import org.kohsuke.stapler.StaplerResponse;
@Controller
public class UrlForwardTest extends HttpServlet implements Filter {
- // Spring-related test cases
+ // Spring `ModelAndView` test cases
@GetMapping("/bad1")
public ModelAndView bad1(String url) {
return new ModelAndView(url); // $ hasUrlForward
@@ -36,6 +36,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
return modelAndView;
}
+ // Spring `"forward:"` prefix test cases
@GetMapping("/bad3")
public String bad3(String url) {
return "forward:" + url + "/swagger-ui/index.html"; // $ hasUrlForward
@@ -47,6 +48,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
return modelAndView;
}
+ // `RequestDispatcher` test cases from a Spring `GetMapping` entry point
@GetMapping("/bad5")
public void bad5(String url, HttpServletRequest request, HttpServletResponse response) {
try {
@@ -91,7 +93,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
}
- // Non-Spring test cases (UnsafeRequest*Path*)
+ // `RequestDispatcher` test cases from non-Spring entry points
private static final String BASE_PATH = "/pages";
@Override
@@ -132,7 +134,6 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
}
- // Non-Spring test cases (UnsafeServletRequest*Dispatch*)
@Override
// BAD: Request dispatcher constructed from `ServletContext` without input validation
protected void doGet(HttpServletRequest request, HttpServletResponse response)
@@ -184,7 +185,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
// BAD: Request dispatcher without path traversal check
- protected void doHead2(HttpServletRequest request, HttpServletResponse response)
+ protected void doHead1(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
@@ -196,7 +197,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
// BAD: Request dispatcher with path traversal check that does not decode
// the user-supplied path; could bypass check with ".." encoded as "%2e%2e".
- protected void doHead3(HttpServletRequest request, HttpServletResponse response)
+ protected void doHead2(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
@@ -207,7 +208,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
// BAD: Request dispatcher with path normalization and comparison, but
// does not decode before normalization.
- protected void doHead4(HttpServletRequest request, HttpServletResponse response)
+ protected void doHead3(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
@@ -220,7 +221,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
// BAD: Request dispatcher with negation check and path normalization, but without URL decoding.
- protected void doHead5(HttpServletRequest request, HttpServletResponse response)
+ protected void doHead4(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
// Since not decoded before normalization, "/%57EB-INF" can remain in the path and pass the `startsWith` check.
@@ -232,7 +233,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
// BAD: Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
- protected void doHead7(HttpServletRequest request, HttpServletResponse response)
+ protected void doHead5(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
path = URLDecoder.decode(path, "UTF-8");
@@ -245,9 +246,9 @@ public class UrlForwardTest extends HttpServlet implements Filter {
// GOOD: Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
protected void doHead6(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
- String path = request.getParameter("path"); // TODO: remove this debugging comment: // v
+ String path = request.getParameter("path");
- if (path.contains("%")){ // TODO: remove this debugging comment: // v.getAnAccess()
+ if (path.contains("%")){
while (path.contains("%")) {
path = URLDecoder.decode(path, "UTF-8");
}
@@ -259,7 +260,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
// GOOD: Request dispatcher with URL encoding check and path traversal check
- protected void doHead16(HttpServletRequest request, HttpServletResponse response)
+ protected void doHead7(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
@@ -270,41 +271,33 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
}
- // TODO: clean-up
- // BAD (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
- // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
- // having previously been checked against a block-list of forbidden values."
- protected void doHead10(HttpServletRequest request, HttpServletResponse response)
+ // BAD: Request dispatcher without URL decoding before WEB-INF and path traversal checks
+ protected void doHead8(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
- if (path.contains("%")){ // BAD: wrong check
- if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
- // if (path.contains("%")){ // BAD: wrong check
+ if (path.contains("%")){ // incorrect check
+ if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
request.getServletContext().getRequestDispatcher(path).include(request, response); // $ hasUrlForward
- // }
+ }
}
}
- }
- // TODO: clean-up
- // "GOOD" (I added): Request dispatcher with path traversal check and single URL decoding; may be vulnerable to double-encoding
- // Tests urlEncoding BarrierGuard "a guard that considers a string safe because it is checked for URL encoding sequences,
- // having previously been checked against a block-list of forbidden values."
- protected void doHead11(HttpServletRequest request, HttpServletResponse response)
+ // GOOD: Request dispatcher with WEB-INF, path traversal, and URL encoding checks
+ protected void doHead9(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = request.getParameter("path");
if (!path.startsWith("/WEB-INF/") && !path.contains("..")) {
- if (!path.contains("%")){ // GOOD: right check
+ if (!path.contains("%")){ // correct check
request.getServletContext().getRequestDispatcher(path).include(request, response);
}
}
}
// GOOD: Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
- protected void doHead8(HttpServletRequest request, HttpServletResponse response)
+ protected void doHead10(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
- String path = request.getParameter("path"); // TODO: remove this debugging comment: // v
+ String path = request.getParameter("path");
while (path.contains("%")) {
path = URLDecoder.decode(path, "UTF-8");
}
@@ -314,12 +307,12 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
}
- // TODO: see if can fix?
- // FP now....
// GOOD: Request dispatcher with path traversal check and URL decoding in a loop to avoid double-encoding bypass
- protected void doHead9(HttpServletRequest request, HttpServletResponse response)
+ protected void doHead11(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
- String path = request.getParameter("path"); // v
+ String path = request.getParameter("path");
+ // FP: we don't currently handle the scenario where the
+ // `path.contains("%")` check is stored in a variable.
boolean hasEncoding = path.contains("%");
while (hasEncoding) {
path = URLDecoder.decode(path, "UTF-8");
From 7310c155e24a238316224adf9cff9204f174d843 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Sun, 10 Mar 2024 21:29:00 -0400
Subject: [PATCH 064/497] Java: rename SpringUrlForwardSink
---
java/ql/lib/semmle/code/java/security/UrlForward.qll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index d4cad4e2f54..76ef139b7b2 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -23,8 +23,8 @@ private class DefaultUrlForwardSink extends UrlForwardSink {
* An expression appended (perhaps indirectly) to `"forward:"`
* and reachable from a Spring entry point.
*/
-private class SpringUrlForwardSink extends UrlForwardSink {
- SpringUrlForwardSink() {
+private class SpringUrlForwardPrefixSink extends UrlForwardSink {
+ SpringUrlForwardPrefixSink() {
any(SpringRequestMappingMethod srmm).polyCalls*(this.getEnclosingCallable()) and
this.asExpr() = any(ForwardPrefix fp).getAnAppendedExpression()
}
From c5a59d6c514cbe2c8985ada441bdd5203b9c615e Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Sun, 10 Mar 2024 23:27:22 -0400
Subject: [PATCH 065/497] Java: add QLDoc
---
java/ql/lib/semmle/code/java/security/UrlForward.qll | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index 76ef139b7b2..e72f3ab2117 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -41,12 +41,11 @@ abstract class UrlForwardBarrier extends DataFlow::Node { }
private class PrimitiveBarrier extends UrlForwardBarrier instanceof SimpleTypeSanitizer { }
-// TODO: QLDoc
+/** A barrier for URLs appended to a prefix. */
private class FollowsBarrierPrefix extends UrlForwardBarrier {
FollowsBarrierPrefix() { this.asExpr() = any(BarrierPrefix fp).getAnAppendedExpression() }
}
-// TODO: QLDoc and fix broadness of this prefix check...
private class BarrierPrefix extends InterestingPrefix {
BarrierPrefix() {
not this.getStringValue().matches("/WEB-INF/%") and
From e99cea340bcf8902bf133c8913cf867d943475c9 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 12 Mar 2024 12:21:22 -0400
Subject: [PATCH 066/497] Java: update UrlPathBarrier to include
FollowsBarrierPrefix
---
.../semmle/code/java/security/UrlForward.qll | 17 ++++-----
.../security/CWE-552/UrlForwardTest.java | 36 ++++++++++++++++++-
2 files changed, 44 insertions(+), 9 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index e72f3ab2117..8c7f8d55eb0 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -41,8 +41,7 @@ abstract class UrlForwardBarrier extends DataFlow::Node { }
private class PrimitiveBarrier extends UrlForwardBarrier instanceof SimpleTypeSanitizer { }
-/** A barrier for URLs appended to a prefix. */
-private class FollowsBarrierPrefix extends UrlForwardBarrier {
+private class FollowsBarrierPrefix extends DataFlow::Node {
FollowsBarrierPrefix() { this.asExpr() = any(BarrierPrefix fp).getAnAppendedExpression() }
}
@@ -55,14 +54,16 @@ private class BarrierPrefix extends InterestingPrefix {
override int getOffset() { result = 0 }
}
-/** A barrier that protects against path injection vulnerabilities while accounting for URL encoding. */
+/**
+ * A barrier that protects against path injection vulnerabilities while accounting
+ * for URL encoding and concatenated prefixes.
+ */
private class UrlPathBarrier extends UrlForwardBarrier instanceof PathInjectionSanitizer {
UrlPathBarrier() {
- this instanceof ExactPathMatchSanitizer
- or
- this instanceof NoUrlEncodingBarrier
- or
- this instanceof FullyDecodesUrlBarrier
+ this instanceof ExactPathMatchSanitizer or
+ this instanceof NoUrlEncodingBarrier or
+ this instanceof FullyDecodesUrlBarrier or
+ this instanceof FollowsBarrierPrefix
}
}
diff --git a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
index e66b5c899c7..6d1c0580cb6 100644
--- a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
+++ b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
@@ -85,7 +85,41 @@ public class UrlForwardTest extends HttpServlet implements Filter {
@GetMapping("/good1")
public void good1(String url, HttpServletRequest request, HttpServletResponse response) {
try {
- request.getRequestDispatcher("/index.jsp?token=" + url).forward(request, response);
+ request.getRequestDispatcher("/index.jsp?token=" + url).forward(request, response); // $ SPURIOUS: hasUrlForward
+ } catch (ServletException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // BAD: appended to a prefix without path sanitization
+ @GetMapping("/bad8")
+ public void bad8(String urlPath, HttpServletRequest request, HttpServletResponse response) {
+ try {
+ String url = "/pages" + urlPath;
+ request.getRequestDispatcher(url).forward(request, response); // $ hasUrlForward
+ } catch (ServletException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // GOOD: appended to a prefix with path sanitization
+ @GetMapping("/good2")
+ public void good2(String urlPath, HttpServletRequest request, HttpServletResponse response) {
+ try {
+ while (urlPath.contains("%")) {
+ urlPath = URLDecoder.decode(urlPath, "UTF-8");
+ }
+
+ if (!urlPath.contains("..") && !urlPath.startsWith("/WEB-INF")) {
+ // Note: path injection sanitizer does not account for string concatenation instead of a `startswith` check
+ String url = "/pages" + urlPath;
+ request.getRequestDispatcher(url).forward(request, response);
+ }
+
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
From 04d27f2d65e9fa1833731889404e57c33f9a22f0 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 12 Mar 2024 20:44:53 -0400
Subject: [PATCH 067/497] Java: adjust prefix barriers
---
.../semmle/code/java/security/UrlForward.qll | 43 ++++++++++++++-----
.../security/CWE-552/UrlForwardTest.java | 10 ++++-
2 files changed, 41 insertions(+), 12 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index 8c7f8d55eb0..5ea36d7c6b8 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -41,29 +41,50 @@ abstract class UrlForwardBarrier extends DataFlow::Node { }
private class PrimitiveBarrier extends UrlForwardBarrier instanceof SimpleTypeSanitizer { }
-private class FollowsBarrierPrefix extends DataFlow::Node {
- FollowsBarrierPrefix() { this.asExpr() = any(BarrierPrefix fp).getAnAppendedExpression() }
+/**
+ * A barrier for values appended to a "redirect:" prefix.
+ * These results are excluded because they should be handled
+ * by the `java/unvalidated-url-redirection` query instead.
+ */
+private class RedirectPrefixBarrier extends UrlForwardBarrier {
+ RedirectPrefixBarrier() { this.asExpr() = any(RedirectPrefix fp).getAnAppendedExpression() }
}
-private class BarrierPrefix extends InterestingPrefix {
- BarrierPrefix() {
- not this.getStringValue().matches("/WEB-INF/%") and
- not this instanceof ForwardPrefix
- }
+private class RedirectPrefix extends InterestingPrefix {
+ RedirectPrefix() { this.getStringValue() = "redirect:" }
override int getOffset() { result = 0 }
}
/**
- * A barrier that protects against path injection vulnerabilities while accounting
- * for URL encoding and concatenated prefixes.
+ * A value that is the result of prepending a string that prevents
+ * any value from controlling the path of a URL.
+ */
+private class FollowsBarrierPrefix extends UrlForwardBarrier {
+ FollowsBarrierPrefix() { this.asExpr() = any(BarrierPrefix fp).getAnAppendedExpression() }
+}
+
+private class BarrierPrefix extends InterestingPrefix {
+ int offset;
+
+ BarrierPrefix() {
+ // Matches strings that look like when prepended to untrusted input, they will restrict
+ // the path of a URL: for example, anything containing `?` or `#`.
+ exists(this.getStringValue().regexpFind("[?#]", 0, offset))
+ }
+
+ override int getOffset() { result = offset }
+}
+
+/**
+ * A barrier that protects against path injection vulnerabilities
+ * while accounting for URL encoding.
*/
private class UrlPathBarrier extends UrlForwardBarrier instanceof PathInjectionSanitizer {
UrlPathBarrier() {
this instanceof ExactPathMatchSanitizer or
this instanceof NoUrlEncodingBarrier or
- this instanceof FullyDecodesUrlBarrier or
- this instanceof FollowsBarrierPrefix
+ this instanceof FullyDecodesUrlBarrier
}
}
diff --git a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
index 6d1c0580cb6..19bd739c294 100644
--- a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
+++ b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
@@ -48,6 +48,14 @@ public class UrlForwardTest extends HttpServlet implements Filter {
return modelAndView;
}
+ // Not relevant for this query since redirecting instead of forwarding
+ // This result should be found by the `java/unvalidated-url-redirection` query instead.
+ @GetMapping("/redirect")
+ public ModelAndView redirect(String url) {
+ ModelAndView modelAndView = new ModelAndView("redirect:" + url);
+ return modelAndView;
+ }
+
// `RequestDispatcher` test cases from a Spring `GetMapping` entry point
@GetMapping("/bad5")
public void bad5(String url, HttpServletRequest request, HttpServletResponse response) {
@@ -85,7 +93,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
@GetMapping("/good1")
public void good1(String url, HttpServletRequest request, HttpServletResponse response) {
try {
- request.getRequestDispatcher("/index.jsp?token=" + url).forward(request, response); // $ SPURIOUS: hasUrlForward
+ request.getRequestDispatcher("/index.jsp?token=" + url).forward(request, response);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
From 5ac453eb38813b14f0e62c2215486581c3943b87 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Wed, 13 Mar 2024 09:36:42 -0400
Subject: [PATCH 068/497] Java: add spurious test case for StringBuilder.append
---
.../security/CWE-552/UrlForwardTest.java | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
index 19bd739c294..5d1d19d4be5 100644
--- a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
+++ b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
@@ -388,4 +388,25 @@ public class UrlForwardTest extends HttpServlet implements Filter {
sc.getRequestDispatcher(VALID_FORWARD).forward(request, response);
}
}
+
+ // Test `StringBuilder.append` sequence with `?` appended before the user input
+ private static final String LOGIN_URL = "/UI/Login";
+
+ public void doPost2(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ StringBuilder forwardUrl = new StringBuilder(200);
+ forwardUrl.append(LOGIN_URL);
+
+ String queryString = request.getQueryString();
+
+ // should be sanitized due to the `?` appended
+ forwardUrl.append('?').append(queryString);
+
+ String fUrl = forwardUrl.toString();
+
+ ServletConfig config = getServletConfig();
+
+ RequestDispatcher dispatcher = config.getServletContext().getRequestDispatcher(fUrl); // $ SPURIOUS: hasUrlForward
+ dispatcher.forward(request, response);
+ }
}
From 1b01f26d09dc118c3796846ceaa975525c3ccf6f Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Wed, 13 Mar 2024 16:27:25 -0400
Subject: [PATCH 069/497] Java: adjust BarrierPrefix to handle prepended chars
---
java/ql/lib/semmle/code/java/security/UrlForward.qll | 2 ++
.../ql/test/query-tests/security/CWE-552/UrlForwardTest.java | 5 ++---
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index 5ea36d7c6b8..b8cc6821abf 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -71,6 +71,8 @@ private class BarrierPrefix extends InterestingPrefix {
// Matches strings that look like when prepended to untrusted input, they will restrict
// the path of a URL: for example, anything containing `?` or `#`.
exists(this.getStringValue().regexpFind("[?#]", 0, offset))
+ or
+ this.(CharacterLiteral).getValue() = ["?", "#"] and offset = 0
}
override int getOffset() { result = offset }
diff --git a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
index 5d1d19d4be5..f0e982c7400 100644
--- a/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
+++ b/java/ql/test/query-tests/security/CWE-552/UrlForwardTest.java
@@ -389,7 +389,7 @@ public class UrlForwardTest extends HttpServlet implements Filter {
}
}
- // Test `StringBuilder.append` sequence with `?` appended before the user input
+ // GOOD: char `?` appended before the user input
private static final String LOGIN_URL = "/UI/Login";
public void doPost2(HttpServletRequest request, HttpServletResponse response)
@@ -399,14 +399,13 @@ public class UrlForwardTest extends HttpServlet implements Filter {
String queryString = request.getQueryString();
- // should be sanitized due to the `?` appended
forwardUrl.append('?').append(queryString);
String fUrl = forwardUrl.toString();
ServletConfig config = getServletConfig();
- RequestDispatcher dispatcher = config.getServletContext().getRequestDispatcher(fUrl); // $ SPURIOUS: hasUrlForward
+ RequestDispatcher dispatcher = config.getServletContext().getRequestDispatcher(fUrl);
dispatcher.forward(request, response);
}
}
From fc8caa66c8ac4cb9b6a9a31f5ea24d0b50d3297a Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 23 Feb 2024 11:35:50 +0100
Subject: [PATCH 070/497] Python: Prepare for general content in type-tracker
Due to the char-pred of Content, this change should keep exactly the
same behavior as before.
---
.../python/dataflow/new/TypeTracking.qll | 14 +++---
.../new/internal/TypeTrackingImpl.qll | 45 +++++--------------
2 files changed, 21 insertions(+), 38 deletions(-)
diff --git a/python/ql/lib/semmle/python/dataflow/new/TypeTracking.qll b/python/ql/lib/semmle/python/dataflow/new/TypeTracking.qll
index 4f1810f059e..9d0bcb3c487 100644
--- a/python/ql/lib/semmle/python/dataflow/new/TypeTracking.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/TypeTracking.qll
@@ -5,6 +5,7 @@
private import internal.TypeTrackingImpl as Impl
import Impl::Shared::TypeTracking
+private import semmle.python.dataflow.new.internal.DataFlowPublic as DataFlowPublic
/** A string that may appear as the name of an attribute or access path. */
class AttributeName = Impl::TypeTrackingInput::Content;
@@ -40,7 +41,11 @@ class TypeTracker extends Impl::TypeTracker {
* Holds if this is the starting point of type tracking, and the value starts in the attribute named `attrName`.
* The type tracking only ends after the attribute has been loaded.
*/
- predicate startInAttr(string attrName) { this.startInContent(attrName) }
+ predicate startInAttr(string attrName) {
+ exists(DataFlowPublic::AttributeContent content | content.getAttribute() = attrName |
+ this.startInContent(content)
+ )
+ }
/**
* INTERNAL. DO NOT USE.
@@ -48,9 +53,8 @@ class TypeTracker extends Impl::TypeTracker {
* Gets the attribute associated with this type tracker.
*/
string getAttr() {
- result = this.getContent().asSome()
- or
- this.getContent().isNone() and
- result = ""
+ if this.getContent().asSome() instanceof DataFlowPublic::AttributeContent
+ then result = this.getContent().asSome().(DataFlowPublic::AttributeContent).getAttribute()
+ else result = ""
}
}
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
index 1a9bdb5202e..8b6e53c8b74 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
@@ -97,24 +97,14 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
private module TypeTrackerSummaryFlow = SummaryTypeTracker::SummaryFlow;
-/**
- * Gets the name of a possible piece of content. For Python, this is currently only attribute names,
- * using the name of the attribute for the corresponding content.
- */
-private string getPossibleContentName() {
- Stages::TypeTracking::ref() and // the TypeTracking::append() etc. predicates that we want to cache depend on this predicate, so we can place the `ref()` call here to get around identical files.
- result = any(DataFlowPublic::AttrRef a).getAttributeName()
-}
-
module TypeTrackingInput implements Shared::TypeTrackingInput {
class Node = DataFlowPublic::Node;
class LocalSourceNode = DataFlowPublic::LocalSourceNode;
- class Content instanceof string {
- Content() { this = getPossibleContentName() }
-
- string toString() { result = this }
+ class Content extends DataFlowPublic::Content {
+ // this char-pred is just a temporary restriction while transitioning to more general content
+ Content() { this instanceof DataFlowPublic::AttributeContent }
}
/**
@@ -181,46 +171,35 @@ module TypeTrackingInput implements Shared::TypeTrackingInput {
* Holds if `nodeFrom` is being written to the `content` content of the object in `nodeTo`.
*/
predicate storeStep(Node nodeFrom, Node nodeTo, Content content) {
- exists(DataFlowPublic::AttrWrite a |
- a.mayHaveAttributeName(content) and
+ exists(DataFlowPublic::AttrWrite a, string attrName |
+ content.(DataFlowPublic::AttributeContent).getAttribute() = attrName and
+ a.mayHaveAttributeName(attrName) and
nodeFrom = a.getValue() and
nodeTo = a.getObject()
)
or
- exists(DataFlowPublic::ContentSet contents |
- contents.(DataFlowPublic::AttributeContent).getAttribute() = content
- |
- TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, contents)
- )
+ TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, content)
}
/**
* Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`.
*/
predicate loadStep(Node nodeFrom, LocalSourceNode nodeTo, Content content) {
- exists(DataFlowPublic::AttrRead a |
- a.mayHaveAttributeName(content) and
+ exists(DataFlowPublic::AttrRead a, string attrName |
+ content.(DataFlowPublic::AttributeContent).getAttribute() = attrName and
+ a.mayHaveAttributeName(attrName) and
nodeFrom = a.getObject() and
nodeTo = a
)
or
- exists(DataFlowPublic::ContentSet contents |
- contents.(DataFlowPublic::AttributeContent).getAttribute() = content
- |
- TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, contents)
- )
+ TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, content)
}
/**
* Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
*/
predicate loadStoreStep(Node nodeFrom, Node nodeTo, Content loadContent, Content storeContent) {
- exists(DataFlowPublic::ContentSet loadContents, DataFlowPublic::ContentSet storeContents |
- loadContents.(DataFlowPublic::AttributeContent).getAttribute() = loadContent and
- storeContents.(DataFlowPublic::AttributeContent).getAttribute() = storeContent
- |
- TypeTrackerSummaryFlow::basicLoadStoreStep(nodeFrom, nodeTo, loadContents, storeContents)
- )
+ TypeTrackerSummaryFlow::basicLoadStoreStep(nodeFrom, nodeTo, loadContent, storeContent)
}
/**
From 636cf611ae8d5f9ac3025bacff6e028902e89f88 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 23 Feb 2024 11:36:47 +0100
Subject: [PATCH 071/497] Python: Allow general content in type-tracker
This should not result in many changes, since store/load steps are still
only implemented for attributes.
---
.../semmle/python/dataflow/new/internal/TypeTrackingImpl.qll | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
index 8b6e53c8b74..81c1f369561 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
@@ -102,10 +102,7 @@ module TypeTrackingInput implements Shared::TypeTrackingInput {
class LocalSourceNode = DataFlowPublic::LocalSourceNode;
- class Content extends DataFlowPublic::Content {
- // this char-pred is just a temporary restriction while transitioning to more general content
- Content() { this instanceof DataFlowPublic::AttributeContent }
- }
+ class Content = DataFlowPublic::Content;
/**
* A label to use for `WithContent` and `WithoutContent` steps, restricting
From 7721fb33314cee322fd4b7ac3c8bd5bfe8b2e353 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 23 Feb 2024 11:44:08 +0100
Subject: [PATCH 072/497] Python: Setup shared read/store steps
---
.../dataflow/new/internal/DataFlowPrivate.qll | 14 ++++++++++++++
.../dataflow/new/internal/TypeTrackingImpl.qll | 4 ++++
2 files changed, 18 insertions(+)
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
index 47f41d0cd05..5ccfa251634 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
@@ -641,11 +641,18 @@ predicate jumpStepNotSharedWithTypeTracker(Node nodeFrom, Node nodeTo) {
//--------
// Field flow
//--------
+/**
+ * Subset of `storeStep` that should be shared with type-tracking.
+ */
+predicate storeStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) { none() }
+
/**
* Holds if data can flow from `nodeFrom` to `nodeTo` via an assignment to
* content `c`.
*/
predicate storeStep(Node nodeFrom, ContentSet c, Node nodeTo) {
+ storeStepCommon(nodeFrom, c, nodeTo)
+ or
listStoreStep(nodeFrom, c, nodeTo)
or
setStoreStep(nodeFrom, c, nodeTo)
@@ -891,10 +898,17 @@ predicate attributeStoreStep(Node nodeFrom, AttributeContent c, Node nodeTo) {
)
}
+/**
+ * Subset of `readStep` that should be shared with type-tracking.
+ */
+predicate readStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) { none() }
+
/**
* Holds if data can flow from `nodeFrom` to `nodeTo` via a read of content `c`.
*/
predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) {
+ readStepCommon(nodeFrom, c, nodeTo)
+ or
subscriptReadStep(nodeFrom, c, nodeTo)
or
iterableUnpackingReadStep(nodeFrom, c, nodeTo)
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
index 81c1f369561..68779208de9 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
@@ -175,6 +175,8 @@ module TypeTrackingInput implements Shared::TypeTrackingInput {
nodeTo = a.getObject()
)
or
+ DataFlowPrivate::storeStepCommon(nodeFrom, content, nodeTo)
+ or
TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, content)
}
@@ -189,6 +191,8 @@ module TypeTrackingInput implements Shared::TypeTrackingInput {
nodeTo = a
)
or
+ DataFlowPrivate::readStepCommon(nodeFrom, content, nodeTo)
+ or
TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, content)
}
From a95bb7c86b1b9047fd5bcc6adf77ee195074a8c5 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 23 Feb 2024 13:24:48 +0100
Subject: [PATCH 073/497] Python: Expand function reference in content test
---
.../CallGraph/InlineCallGraphTest.expected | 3 +-
.../CallGraph/code/func_ref_in_content.py | 53 +++++++++++++++++++
.../CallGraph/code/tuple_function_return.py | 15 ------
3 files changed, 55 insertions(+), 16 deletions(-)
create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
delete mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/tuple_function_return.py
diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
index 55774486be0..504c5251a1a 100644
--- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
+++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
@@ -15,8 +15,9 @@ pointsTo_found_typeTracker_notFound
| code/func_defined_outside_class.py:39:11:39:21 | ControlFlowNode for _gen() | B._gen |
| code/func_defined_outside_class.py:42:1:42:7 | ControlFlowNode for Attribute() | B._gen.func |
| code/func_defined_outside_class.py:43:1:43:7 | ControlFlowNode for Attribute() | B._gen.func |
+| code/func_ref_in_content.py:17:1:17:4 | ControlFlowNode for f2() | func |
+| code/func_ref_in_content.py:20:1:20:4 | ControlFlowNode for f3() | func |
| code/funky_regression.py:15:9:15:17 | ControlFlowNode for Attribute() | Wat.f2 |
-| code/tuple_function_return.py:15:1:15:4 | ControlFlowNode for f2() | func |
| code/type_tracking_limitation.py:8:1:8:3 | ControlFlowNode for x() | my_func |
typeTracker_found_pointsTo_notFound
| code/callable_as_argument.py:29:5:29:12 | ControlFlowNode for Attribute() | test_class.InsideTestFunc.sm |
diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
new file mode 100644
index 00000000000..b89a013f5b1
--- /dev/null
+++ b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
@@ -0,0 +1,53 @@
+def func():
+ print("func()")
+
+def return_func():
+ return func
+
+f1 = return_func() # $ pt,tt=return_func
+f1() # $ pt,tt=func
+
+
+def return_func_in_tuple():
+ return (func, 42)
+
+tup = return_func_in_tuple() # $ pt,tt=return_func_in_tuple
+
+f2, _ = tup
+f2() # $ pt=func MISSING: tt
+
+f3 = tup[0]
+f3() # $ pt=func MISSING: tt
+
+
+def return_func_in_dict():
+ return {'func': func, 'val': 42}
+
+dct = return_func_in_dict() # $ pt,tt=return_func_in_dict
+
+f4 = dct['func']
+f4() # $ MISSING: tt=func
+
+
+def return_func_in_dict_update():
+ d = {}
+ d["func"] = func
+ return d
+
+dct2 = return_func_in_dict_update() # $ pt,tt=return_func_in_dict_update
+
+f5 = dct2['func']
+f5() # $ MISSING: tt=func
+
+
+def return_func_in_list():
+ return [func, 42]
+
+lst = return_func_in_list() # $ pt,tt=return_func_in_list
+
+f6 = lst[0]
+f6() # $ MISSING: pt,tt=func
+
+if eval("False"): # don't run this, but fool analysis to still consider it (doesn't wok if you just to `if False:`)
+ f7 = lst[1]
+ f7()
diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/tuple_function_return.py b/python/ql/test/experimental/library-tests/CallGraph/code/tuple_function_return.py
deleted file mode 100644
index f87b1aa23e8..00000000000
--- a/python/ql/test/experimental/library-tests/CallGraph/code/tuple_function_return.py
+++ /dev/null
@@ -1,15 +0,0 @@
-def func():
- print("func()")
-
-def return_func():
- return func
-
-def return_func_in_tuple():
- return (func, 42)
-
-f1 = return_func() # $ pt,tt=return_func
-f1() # $ pt,tt=func
-
-
-f2, _ = return_func_in_tuple() # $ pt,tt=return_func_in_tuple
-f2() # $ pt=func MISSING: tt
From ece8245a4be1f05fffc2e9cd7acd5e387729538e Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 23 Feb 2024 13:39:49 +0100
Subject: [PATCH 074/497] Python: type-track through tuple content
---
.../python/dataflow/new/internal/DataFlowPrivate.qll | 12 ++++++------
.../CallGraph/InlineCallGraphTest.expected | 1 -
.../CallGraph/code/func_ref_in_content.py | 2 +-
3 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
index 5ccfa251634..22fb979f9dc 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
@@ -644,7 +644,9 @@ predicate jumpStepNotSharedWithTypeTracker(Node nodeFrom, Node nodeTo) {
/**
* Subset of `storeStep` that should be shared with type-tracking.
*/
-predicate storeStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) { none() }
+predicate storeStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
+ tupleStoreStep(nodeFrom, c, nodeTo)
+}
/**
* Holds if data can flow from `nodeFrom` to `nodeTo` via an assignment to
@@ -657,8 +659,6 @@ predicate storeStep(Node nodeFrom, ContentSet c, Node nodeTo) {
or
setStoreStep(nodeFrom, c, nodeTo)
or
- tupleStoreStep(nodeFrom, c, nodeTo)
- or
dictStoreStep(nodeFrom, c, nodeTo)
or
moreDictStoreSteps(nodeFrom, c, nodeTo)
@@ -901,7 +901,9 @@ predicate attributeStoreStep(Node nodeFrom, AttributeContent c, Node nodeTo) {
/**
* Subset of `readStep` that should be shared with type-tracking.
*/
-predicate readStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) { none() }
+predicate readStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
+ subscriptReadStep(nodeFrom, c, nodeTo)
+}
/**
* Holds if data can flow from `nodeFrom` to `nodeTo` via a read of content `c`.
@@ -909,8 +911,6 @@ predicate readStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) { none() }
predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) {
readStepCommon(nodeFrom, c, nodeTo)
or
- subscriptReadStep(nodeFrom, c, nodeTo)
- or
iterableUnpackingReadStep(nodeFrom, c, nodeTo)
or
matchReadStep(nodeFrom, c, nodeTo)
diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
index 504c5251a1a..667ebf28d75 100644
--- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
+++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
@@ -16,7 +16,6 @@ pointsTo_found_typeTracker_notFound
| code/func_defined_outside_class.py:42:1:42:7 | ControlFlowNode for Attribute() | B._gen.func |
| code/func_defined_outside_class.py:43:1:43:7 | ControlFlowNode for Attribute() | B._gen.func |
| code/func_ref_in_content.py:17:1:17:4 | ControlFlowNode for f2() | func |
-| code/func_ref_in_content.py:20:1:20:4 | ControlFlowNode for f3() | func |
| code/funky_regression.py:15:9:15:17 | ControlFlowNode for Attribute() | Wat.f2 |
| code/type_tracking_limitation.py:8:1:8:3 | ControlFlowNode for x() | my_func |
typeTracker_found_pointsTo_notFound
diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
index b89a013f5b1..87abb4198e9 100644
--- a/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
+++ b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
@@ -17,7 +17,7 @@ f2, _ = tup
f2() # $ pt=func MISSING: tt
f3 = tup[0]
-f3() # $ pt=func MISSING: tt
+f3() # $ tt,pt=func
def return_func_in_dict():
From 73fe596753357032044842f90816421ddd16490c Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 23 Feb 2024 13:57:57 +0100
Subject: [PATCH 075/497] Python: type-tracking through dictionary construction
---
.../semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 4 ++--
.../library-tests/CallGraph/InlineCallGraphTest.expected | 1 +
.../library-tests/CallGraph/code/func_ref_in_content.py | 2 +-
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
index 22fb979f9dc..3b589da37d6 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
@@ -646,6 +646,8 @@ predicate jumpStepNotSharedWithTypeTracker(Node nodeFrom, Node nodeTo) {
*/
predicate storeStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
tupleStoreStep(nodeFrom, c, nodeTo)
+ or
+ dictStoreStep(nodeFrom, c, nodeTo)
}
/**
@@ -659,8 +661,6 @@ predicate storeStep(Node nodeFrom, ContentSet c, Node nodeTo) {
or
setStoreStep(nodeFrom, c, nodeTo)
or
- dictStoreStep(nodeFrom, c, nodeTo)
- or
moreDictStoreSteps(nodeFrom, c, nodeTo)
or
comprehensionStoreStep(nodeFrom, c, nodeTo)
diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
index 667ebf28d75..ab97d594a4e 100644
--- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
+++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
@@ -38,6 +38,7 @@ typeTracker_found_pointsTo_notFound
| code/class_super.py:101:1:101:7 | ControlFlowNode for Attribute() | Z.foo |
| code/class_super.py:108:1:108:8 | ControlFlowNode for Attribute() | Z.foo |
| code/def_in_function.py:22:5:22:11 | ControlFlowNode for Attribute() | test.A.foo |
+| code/func_ref_in_content.py:29:1:29:4 | ControlFlowNode for f4() | func |
| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | A.foo |
| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | ASub.foo |
| code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | A.foo |
diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
index 87abb4198e9..57b11915c51 100644
--- a/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
+++ b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
@@ -26,7 +26,7 @@ def return_func_in_dict():
dct = return_func_in_dict() # $ pt,tt=return_func_in_dict
f4 = dct['func']
-f4() # $ MISSING: tt=func
+f4() # $ tt=func
def return_func_in_dict_update():
From dac2b57bb029e345f79e0337f5ab1ba2a2137db7 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 23 Feb 2024 14:51:38 +0100
Subject: [PATCH 076/497] Python: type-track through dict-updates
---
.../dataflow/new/internal/DataFlowPrivate.qll | 4 ++--
.../dataflow/new/internal/TypeTrackingImpl.qll | 13 ++++++++++++-
.../CallGraph/InlineCallGraphTest.expected | 1 +
.../CallGraph/code/func_ref_in_content.py | 2 +-
4 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
index 3b589da37d6..98841726a74 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
@@ -648,6 +648,8 @@ predicate storeStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
tupleStoreStep(nodeFrom, c, nodeTo)
or
dictStoreStep(nodeFrom, c, nodeTo)
+ or
+ moreDictStoreSteps(nodeFrom, c, nodeTo)
}
/**
@@ -661,8 +663,6 @@ predicate storeStep(Node nodeFrom, ContentSet c, Node nodeTo) {
or
setStoreStep(nodeFrom, c, nodeTo)
or
- moreDictStoreSteps(nodeFrom, c, nodeTo)
- or
comprehensionStoreStep(nodeFrom, c, nodeTo)
or
iterableUnpackingStoreStep(nodeFrom, c, nodeTo)
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
index 68779208de9..8b3e1a95ef1 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
@@ -175,7 +175,18 @@ module TypeTrackingInput implements Shared::TypeTrackingInput {
nodeTo = a.getObject()
)
or
- DataFlowPrivate::storeStepCommon(nodeFrom, content, nodeTo)
+ // type-tracking doesn't really handle PostUpdateNodes, so for some assignment steps
+ // like `my_dict["foo"] = foo` the data-flow step targets the PostUpdateNode for
+ // `my_dict`, where we want to translate that into a type-tracking step that targets
+ // the normal/non-PostUpdateNode for `my_dict`.
+ exists(DataFlowPublic::Node storeTarget |
+ DataFlowPrivate::storeStepCommon(nodeFrom, content, storeTarget)
+ |
+ not storeTarget instanceof DataFlowPrivate::SyntheticPostUpdateNode and
+ nodeTo = storeTarget
+ or
+ nodeTo = storeTarget.(DataFlowPrivate::SyntheticPostUpdateNode).getPreUpdateNode()
+ )
or
TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, content)
}
diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
index ab97d594a4e..378b2c64957 100644
--- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
+++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
@@ -39,6 +39,7 @@ typeTracker_found_pointsTo_notFound
| code/class_super.py:108:1:108:8 | ControlFlowNode for Attribute() | Z.foo |
| code/def_in_function.py:22:5:22:11 | ControlFlowNode for Attribute() | test.A.foo |
| code/func_ref_in_content.py:29:1:29:4 | ControlFlowNode for f4() | func |
+| code/func_ref_in_content.py:40:1:40:4 | ControlFlowNode for f5() | func |
| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | A.foo |
| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | ASub.foo |
| code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | A.foo |
diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
index 57b11915c51..4bea545cb0f 100644
--- a/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
+++ b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
@@ -37,7 +37,7 @@ def return_func_in_dict_update():
dct2 = return_func_in_dict_update() # $ pt,tt=return_func_in_dict_update
f5 = dct2['func']
-f5() # $ MISSING: tt=func
+f5() # $ tt=func
def return_func_in_list():
From 0cf3fe4a4c5d7772d2efefa0d45cf2d89e46c160 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 23 Feb 2024 14:59:07 +0100
Subject: [PATCH 077/497] Python: Expand dict update tests
---
.../CallGraph/InlineCallGraphTest.expected | 8 +++++---
.../CallGraph/code/func_ref_in_content.py | 10 ++++++++++
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
index 378b2c64957..c5b7d6dc473 100644
--- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
+++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
@@ -15,7 +15,7 @@ pointsTo_found_typeTracker_notFound
| code/func_defined_outside_class.py:39:11:39:21 | ControlFlowNode for _gen() | B._gen |
| code/func_defined_outside_class.py:42:1:42:7 | ControlFlowNode for Attribute() | B._gen.func |
| code/func_defined_outside_class.py:43:1:43:7 | ControlFlowNode for Attribute() | B._gen.func |
-| code/func_ref_in_content.py:17:1:17:4 | ControlFlowNode for f2() | func |
+| code/func_ref_in_content.py:20:1:20:4 | ControlFlowNode for f2() | func |
| code/funky_regression.py:15:9:15:17 | ControlFlowNode for Attribute() | Wat.f2 |
| code/type_tracking_limitation.py:8:1:8:3 | ControlFlowNode for x() | my_func |
typeTracker_found_pointsTo_notFound
@@ -38,8 +38,10 @@ typeTracker_found_pointsTo_notFound
| code/class_super.py:101:1:101:7 | ControlFlowNode for Attribute() | Z.foo |
| code/class_super.py:108:1:108:8 | ControlFlowNode for Attribute() | Z.foo |
| code/def_in_function.py:22:5:22:11 | ControlFlowNode for Attribute() | test.A.foo |
-| code/func_ref_in_content.py:29:1:29:4 | ControlFlowNode for f4() | func |
-| code/func_ref_in_content.py:40:1:40:4 | ControlFlowNode for f5() | func |
+| code/func_ref_in_content.py:32:1:32:4 | ControlFlowNode for f4() | func |
+| code/func_ref_in_content.py:46:1:46:4 | ControlFlowNode for f5() | func |
+| code/func_ref_in_content.py:48:1:48:15 | ControlFlowNode for Subscript() | func2 |
+| code/func_ref_in_content.py:50:1:50:19 | ControlFlowNode for Subscript() | func2 |
| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | A.foo |
| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | ASub.foo |
| code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | A.foo |
diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
index 4bea545cb0f..b249ec0b2e9 100644
--- a/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
+++ b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
@@ -1,6 +1,9 @@
def func():
print("func()")
+def func2():
+ print("func2()")
+
def return_func():
return func
@@ -32,6 +35,9 @@ f4() # $ tt=func
def return_func_in_dict_update():
d = {}
d["func"] = func
+ d["func2"] = func2
+ d["contested"] = func
+ d["contested"] = func2
return d
dct2 = return_func_in_dict_update() # $ pt,tt=return_func_in_dict_update
@@ -39,6 +45,10 @@ dct2 = return_func_in_dict_update() # $ pt,tt=return_func_in_dict_update
f5 = dct2['func']
f5() # $ tt=func
+dct2['func2']() # $ tt=func2
+
+dct2['contested']() # $ tt=func2 SPURIOUS: tt=func
+
def return_func_in_list():
return [func, 42]
From 92729dbbd659bdac0c8f9e31699161806fb80e73 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 23 Feb 2024 15:27:10 +0100
Subject: [PATCH 078/497] Python: Support iterable unpacking in type-tracking
---
.../python/dataflow/new/internal/DataFlowPrivate.qll | 8 ++++----
.../library-tests/CallGraph/InlineCallGraphTest.expected | 1 -
.../library-tests/CallGraph/code/func_ref_in_content.py | 2 +-
3 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
index 98841726a74..f2a52377544 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
@@ -650,6 +650,8 @@ predicate storeStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
dictStoreStep(nodeFrom, c, nodeTo)
or
moreDictStoreSteps(nodeFrom, c, nodeTo)
+ or
+ iterableUnpackingStoreStep(nodeFrom, c, nodeTo)
}
/**
@@ -665,8 +667,6 @@ predicate storeStep(Node nodeFrom, ContentSet c, Node nodeTo) {
or
comprehensionStoreStep(nodeFrom, c, nodeTo)
or
- iterableUnpackingStoreStep(nodeFrom, c, nodeTo)
- or
attributeStoreStep(nodeFrom, c, nodeTo)
or
matchStoreStep(nodeFrom, c, nodeTo)
@@ -903,6 +903,8 @@ predicate attributeStoreStep(Node nodeFrom, AttributeContent c, Node nodeTo) {
*/
predicate readStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
subscriptReadStep(nodeFrom, c, nodeTo)
+ or
+ iterableUnpackingReadStep(nodeFrom, c, nodeTo)
}
/**
@@ -911,8 +913,6 @@ predicate readStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) {
readStepCommon(nodeFrom, c, nodeTo)
or
- iterableUnpackingReadStep(nodeFrom, c, nodeTo)
- or
matchReadStep(nodeFrom, c, nodeTo)
or
forReadStep(nodeFrom, c, nodeTo)
diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
index c5b7d6dc473..ef82a9ad20c 100644
--- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
+++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected
@@ -15,7 +15,6 @@ pointsTo_found_typeTracker_notFound
| code/func_defined_outside_class.py:39:11:39:21 | ControlFlowNode for _gen() | B._gen |
| code/func_defined_outside_class.py:42:1:42:7 | ControlFlowNode for Attribute() | B._gen.func |
| code/func_defined_outside_class.py:43:1:43:7 | ControlFlowNode for Attribute() | B._gen.func |
-| code/func_ref_in_content.py:20:1:20:4 | ControlFlowNode for f2() | func |
| code/funky_regression.py:15:9:15:17 | ControlFlowNode for Attribute() | Wat.f2 |
| code/type_tracking_limitation.py:8:1:8:3 | ControlFlowNode for x() | my_func |
typeTracker_found_pointsTo_notFound
diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
index b249ec0b2e9..24518ace088 100644
--- a/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
+++ b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
@@ -17,7 +17,7 @@ def return_func_in_tuple():
tup = return_func_in_tuple() # $ pt,tt=return_func_in_tuple
f2, _ = tup
-f2() # $ pt=func MISSING: tt
+f2() # $ pt,tt=func
f3 = tup[0]
f3() # $ tt,pt=func
From 8a7ffac19c9162fdfbde38aa859fc114ad927ba6 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 1 Mar 2024 12:13:43 +0100
Subject: [PATCH 079/497] Python: Accept consistency failure
---
.../CallGraph/CONSISTENCY/TypeTrackingConsistency.expected | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 python/ql/test/experimental/library-tests/CallGraph/CONSISTENCY/TypeTrackingConsistency.expected
diff --git a/python/ql/test/experimental/library-tests/CallGraph/CONSISTENCY/TypeTrackingConsistency.expected b/python/ql/test/experimental/library-tests/CallGraph/CONSISTENCY/TypeTrackingConsistency.expected
new file mode 100644
index 00000000000..6aed7c83813
--- /dev/null
+++ b/python/ql/test/experimental/library-tests/CallGraph/CONSISTENCY/TypeTrackingConsistency.expected
@@ -0,0 +1,2 @@
+| code/func_ref_in_content.py:19:1:19:5 | IterableElement | Unreachable node in step of kind store Tuple element at index 0. |
+| code/func_ref_in_content.py:19:1:19:5 | IterableElement | Unreachable node in step of kind store Tuple element at index 1. |
From 4d78762ba85ddb1373488ef1b0f45fc2a9f9b2a3 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 1 Mar 2024 12:14:14 +0100
Subject: [PATCH 080/497] Python: Ignore consistency failure
---
python/ql/consistency-queries/TypeTrackingConsistency.ql | 7 +++++++
.../CallGraph/CONSISTENCY/TypeTrackingConsistency.expected | 2 --
2 files changed, 7 insertions(+), 2 deletions(-)
delete mode 100644 python/ql/test/experimental/library-tests/CallGraph/CONSISTENCY/TypeTrackingConsistency.expected
diff --git a/python/ql/consistency-queries/TypeTrackingConsistency.ql b/python/ql/consistency-queries/TypeTrackingConsistency.ql
index 15083229002..551573a7aef 100644
--- a/python/ql/consistency-queries/TypeTrackingConsistency.ql
+++ b/python/ql/consistency-queries/TypeTrackingConsistency.ql
@@ -36,6 +36,13 @@ private module ConsistencyChecksInput implements ConsistencyChecksInputSig {
// which I couldn't just fix. We ignore the problems here, and instead rely on the
// test-case added in https://github.com/github/codeql/pull/15841
n.getLocation().getFile().getAbsolutePath().matches("%/socketserver.py")
+ or
+ // for iterable unpacking like `a,b = some_list`, we currently don't want to allow
+ // type-tracking... however, in the future when we allow tracking list indexes
+ // precisely (that is, move away from ListElementContent), we should ensure we have
+ // proper flow to the synthetic `IterableElementNode`.
+ exists(DataFlow::ListElementContent c) and
+ n instanceof DataFlow::IterableElementNode
}
}
diff --git a/python/ql/test/experimental/library-tests/CallGraph/CONSISTENCY/TypeTrackingConsistency.expected b/python/ql/test/experimental/library-tests/CallGraph/CONSISTENCY/TypeTrackingConsistency.expected
deleted file mode 100644
index 6aed7c83813..00000000000
--- a/python/ql/test/experimental/library-tests/CallGraph/CONSISTENCY/TypeTrackingConsistency.expected
+++ /dev/null
@@ -1,2 +0,0 @@
-| code/func_ref_in_content.py:19:1:19:5 | IterableElement | Unreachable node in step of kind store Tuple element at index 0. |
-| code/func_ref_in_content.py:19:1:19:5 | IterableElement | Unreachable node in step of kind store Tuple element at index 1. |
From fa0c4e18fcbe2638af0266bbd86d209e2feec054 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Mon, 4 Mar 2024 16:05:18 +0100
Subject: [PATCH 081/497] Python: Expand dict-content tt test even more
While it might be useful to track content to any lookup, it's not
something we do right now.
---
.../CallGraph/code/func_ref_in_content.py | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
index 24518ace088..eee8f29778b 100644
--- a/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
+++ b/python/ql/test/experimental/library-tests/CallGraph/code/func_ref_in_content.py
@@ -50,6 +50,17 @@ dct2['func2']() # $ tt=func2
dct2['contested']() # $ tt=func2 SPURIOUS: tt=func
+## non-precise access is not supported right now
+for k in dct2:
+ dct2[k]() # $ MISSING: tt=func tt=func2
+
+for v in dct2.values():
+ v() # $ MISSING: tt=func tt=func2
+
+for k, v in dct2.items():
+ v() # $ MISSING: tt=func tt=func2
+
+
def return_func_in_list():
return [func, 42]
From 7de304bf1680d61f7b6309cb840a941445f9caf9 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 12 Mar 2024 16:07:53 +0100
Subject: [PATCH 082/497] Python: Add proper type-tracking tests for content
Instead of just relying on the call-graph tests
---
.../dataflow/typetracking/content_test.py | 78 +++++++++++++++++++
.../dataflow/typetracking/tracked.ql | 8 ++
2 files changed, 86 insertions(+)
create mode 100644 python/ql/test/experimental/dataflow/typetracking/content_test.py
diff --git a/python/ql/test/experimental/dataflow/typetracking/content_test.py b/python/ql/test/experimental/dataflow/typetracking/content_test.py
new file mode 100644
index 00000000000..ac201f23301
--- /dev/null
+++ b/python/ql/test/experimental/dataflow/typetracking/content_test.py
@@ -0,0 +1,78 @@
+# test of other content types than attributes
+
+def test_tuple(index_arg):
+ tup = (tracked, other) # $tracked
+
+ tup[0] # $ tracked
+ tup[1]
+
+ a,b = tup # $tracked
+ a # $ tracked
+ b
+
+ # non-precise access is not supported right now (and it's not 100% clear if we want
+ # to support it, or if it will lead to bad results)
+ tup[index_arg]
+
+ for x in tup:
+ print(x)
+
+ for i in range(len(tup)):
+ print(tup[i])
+
+
+def test_dict(key_arg):
+ d1 = {"t": tracked, "o": other} # $tracked
+ d1["t"] # $ tracked
+ d1.get("t") # $ MISSING: tracked
+ d1.setdefault("t") # $ MISSING: tracked
+
+ d1["o"]
+ d1.get("o")
+ d1.setdefault("o")
+
+
+ # non-precise access is not supported right now (and it's not 100% clear if we want
+ # to support it, or if it will lead to bad results)
+ d1[key_arg]
+
+ for k in d1:
+ d1[k]
+
+ for v in d1.values():
+ v
+
+ for k, v in d1.items():
+ v
+
+
+ # construction with inline updates
+ d2 = dict()
+ d2["t"] = tracked # $ tracked
+ d2["o"] = other
+
+ d2["t"] # $ tracked
+ d2["o"]
+
+ # notice that time-travel is also possible (just as with attributes)
+ d3 = dict()
+ d3["t"] # $ SPURIOUS: tracked
+ d3["t"] = tracked # $ tracked
+ d3["t"] # $ tracked
+
+
+def test_list(index_arg):
+ l = [tracked, other] # $tracked
+
+ l[0] # $ MISSING: tracked
+ l[1]
+
+ # non-precise access is not supported right now (and it's not 100% clear if we want
+ # to support it, or if it will lead to bad results)
+ l[index_arg]
+
+ for x in l:
+ print(x)
+
+ for i in range(len(l)):
+ print(l[i])
diff --git a/python/ql/test/experimental/dataflow/typetracking/tracked.ql b/python/ql/test/experimental/dataflow/typetracking/tracked.ql
index ca893688256..8bad0e33ead 100644
--- a/python/ql/test/experimental/dataflow/typetracking/tracked.ql
+++ b/python/ql/test/experimental/dataflow/typetracking/tracked.ql
@@ -30,6 +30,14 @@ module TrackedTest implements TestSig {
not e instanceof DataFlow::ScopeEntryDefinitionNode and
// ...same for `SynthCaptureNode`s
not e instanceof DP::SynthCaptureNode and
+ // after starting to track all kinds of content, we generally just want to show
+ // annotations after reading the tracked data out again. (we keep the old
+ // attribute logic to not rewrite all our tests)
+ (
+ t.getContent().isNone()
+ or
+ t.getContent().asSome() instanceof DataFlow::AttributeContent
+ ) and
tag = "tracked" and
location = e.getLocation() and
value = t.getAttr() and
From 2b09b084e0393193e5daf97a1a512538c9aa4b57 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 12 Mar 2024 17:43:43 +0100
Subject: [PATCH 083/497] Python: Add change-note
---
python/ql/lib/change-notes/2024-03-12-typetracking-content.md | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 python/ql/lib/change-notes/2024-03-12-typetracking-content.md
diff --git a/python/ql/lib/change-notes/2024-03-12-typetracking-content.md b/python/ql/lib/change-notes/2024-03-12-typetracking-content.md
new file mode 100644
index 00000000000..5ad93a657ae
--- /dev/null
+++ b/python/ql/lib/change-notes/2024-03-12-typetracking-content.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Improved the type-tracking capabilities (and therefore also API graphs) to allow tracking items in tuples and dictionaries.
From af8cef5b535b068057a58654701cf27ca2641e81 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 12 Mar 2024 17:57:32 +0100
Subject: [PATCH 084/497] Python: Fixup deprecated type-tracker API
---
.../dataflow/new/internal/TypeTracker.qll | 46 +++++++++++++++----
.../new/internal/TypeTrackerSpecific.qll | 2 +-
2 files changed, 37 insertions(+), 11 deletions(-)
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll
index 0f6ff8bd3bd..01c881b2316 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll
@@ -1,6 +1,7 @@
/** Step Summaries and Type Tracking */
private import TypeTrackerSpecific
+private import semmle.python.dataflow.new.internal.DataFlowPublic as DataFlowPublic
cached
private module Cached {
@@ -12,10 +13,22 @@ private module Cached {
LevelStep() or
CallStep() or
ReturnStep() or
- deprecated StoreStep(TypeTrackerContent content) { basicStoreStep(_, _, content) } or
- deprecated LoadStep(TypeTrackerContent content) { basicLoadStep(_, _, content) } or
+ deprecated StoreStep(TypeTrackerContent content) {
+ exists(DataFlowPublic::AttributeContent dfc | dfc.getAttribute() = content |
+ basicStoreStep(_, _, dfc)
+ )
+ } or
+ deprecated LoadStep(TypeTrackerContent content) {
+ exists(DataFlowPublic::AttributeContent dfc | dfc.getAttribute() = content |
+ basicLoadStep(_, _, dfc)
+ )
+ } or
deprecated LoadStoreStep(TypeTrackerContent load, TypeTrackerContent store) {
- basicLoadStoreStep(_, _, load, store)
+ exists(DataFlowPublic::AttributeContent dfcLoad, DataFlowPublic::AttributeContent dfcStore |
+ dfcLoad.getAttribute() = load and dfcStore.getAttribute() = store
+ |
+ basicLoadStoreStep(_, _, dfcLoad, dfcStore)
+ )
} or
deprecated WithContent(ContentFilter filter) { basicWithContentStep(_, _, filter) } or
deprecated WithoutContent(ContentFilter filter) { basicWithoutContentStep(_, _, filter) } or
@@ -29,13 +42,13 @@ private module Cached {
// Restrict `content` to those that might eventually match a load.
// We can't rely on `basicStoreStep` since `startInContent` might be used with
// a content that has no corresponding store.
- exists(TypeTrackerContent loadContents |
+ exists(DataFlowPublic::AttributeContent loadContents |
(
basicLoadStep(_, _, loadContents)
or
basicLoadStoreStep(_, _, loadContents, _)
) and
- compatibleContents(content, loadContents)
+ compatibleContents(content, loadContents.getAttribute())
)
}
@@ -45,13 +58,13 @@ private module Cached {
content = noContent()
or
// As in MkTypeTracker, restrict `content` to those that might eventually match a store.
- exists(TypeTrackerContent storeContent |
+ exists(DataFlowPublic::AttributeContent storeContent |
(
basicStoreStep(_, _, storeContent)
or
basicLoadStoreStep(_, _, _, storeContent)
) and
- compatibleContents(storeContent, content)
+ compatibleContents(storeContent.getAttribute(), content)
)
}
@@ -198,7 +211,10 @@ private module Cached {
flowsToStoreStep(nodeFrom, nodeTo, content) and
summary = StoreStep(content)
or
- basicLoadStep(nodeFrom, nodeTo, content) and summary = LoadStep(content)
+ exists(DataFlowPublic::AttributeContent dfc | dfc.getAttribute() = content |
+ basicLoadStep(nodeFrom, nodeTo, dfc)
+ ) and
+ summary = LoadStep(content)
)
or
exists(TypeTrackerContent loadContent, TypeTrackerContent storeContent |
@@ -281,7 +297,12 @@ deprecated private predicate smallstepProj(Node nodeFrom, StepSummary summary) {
deprecated private predicate flowsToStoreStep(
Node nodeFrom, TypeTrackingNode nodeTo, TypeTrackerContent content
) {
- exists(Node obj | nodeTo.flowsTo(obj) and basicStoreStep(nodeFrom, obj, content))
+ exists(Node obj |
+ nodeTo.flowsTo(obj) and
+ exists(DataFlowPublic::AttributeContent dfc | dfc.getAttribute() = content |
+ basicStoreStep(nodeFrom, obj, dfc)
+ )
+ )
}
/**
@@ -292,7 +313,12 @@ deprecated private predicate flowsToLoadStoreStep(
TypeTrackerContent storeContent
) {
exists(Node obj |
- nodeTo.flowsTo(obj) and basicLoadStoreStep(nodeFrom, obj, loadContent, storeContent)
+ nodeTo.flowsTo(obj) and
+ exists(DataFlowPublic::AttributeContent loadDfc, DataFlowPublic::AttributeContent storeDfc |
+ loadDfc.getAttribute() = loadContent and storeDfc.getAttribute() = storeContent
+ |
+ basicLoadStoreStep(nodeFrom, obj, loadDfc, storeDfc)
+ )
)
}
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll
index c31cfeb5331..11cce1446f7 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll
@@ -15,7 +15,7 @@ deprecated class OptionalTypeTrackerContent extends string {
OptionalTypeTrackerContent() {
this = ""
or
- this instanceof TypeTrackingImpl::TypeTrackingInput::Content
+ this = any(DataFlowPublic::AttributeContent dfc).getAttribute()
}
}
From 6ffaad1bc8cfb0812549780d6547c8e37a2dcea9 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 12 Mar 2024 22:32:40 +0100
Subject: [PATCH 085/497] Python: Expand type-tracking tests with nested tuples
I was initially surprised to see that this didn't work, until I
remembered that type-tracking only works with content of depth 1.
---
.../TypeTrackingConsistency.expected | 13 +++++++++++
.../dataflow/typetracking/content_test.py | 22 +++++++++++++++++++
2 files changed, 35 insertions(+)
create mode 100644 python/ql/test/experimental/dataflow/typetracking/CONSISTENCY/TypeTrackingConsistency.expected
diff --git a/python/ql/test/experimental/dataflow/typetracking/CONSISTENCY/TypeTrackingConsistency.expected b/python/ql/test/experimental/dataflow/typetracking/CONSISTENCY/TypeTrackingConsistency.expected
new file mode 100644
index 00000000000..6fc4df91699
--- /dev/null
+++ b/python/ql/test/experimental/dataflow/typetracking/CONSISTENCY/TypeTrackingConsistency.expected
@@ -0,0 +1,13 @@
+unreachableNode
+| content_test.py:31:6:31:11 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 0. |
+| content_test.py:31:6:31:11 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 1. |
+| content_test.py:31:6:31:11 | ControlFlowNode for Tuple | Unreachable node in step of kind storeTarget. |
+| content_test.py:31:16:31:21 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 0. |
+| content_test.py:31:16:31:21 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 1. |
+| content_test.py:31:16:31:21 | ControlFlowNode for Tuple | Unreachable node in step of kind storeTarget. |
+| content_test.py:40:10:40:13 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 0. |
+| content_test.py:40:10:40:13 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 1. |
+| content_test.py:40:10:40:13 | ControlFlowNode for Tuple | Unreachable node in step of kind storeTarget. |
+| content_test.py:66:9:66:12 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 0. |
+| content_test.py:66:9:66:12 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 1. |
+| content_test.py:66:9:66:12 | ControlFlowNode for Tuple | Unreachable node in step of kind storeTarget. |
diff --git a/python/ql/test/experimental/dataflow/typetracking/content_test.py b/python/ql/test/experimental/dataflow/typetracking/content_test.py
index ac201f23301..1c52d659582 100644
--- a/python/ql/test/experimental/dataflow/typetracking/content_test.py
+++ b/python/ql/test/experimental/dataflow/typetracking/content_test.py
@@ -21,6 +21,28 @@ def test_tuple(index_arg):
print(tup[i])
+ # nested tuples
+ nested_tuples = ((tracked, other), (other, tracked)) # $tracked
+
+ nested_tuples[0][0] # $ MISSING: tracked
+ nested_tuples[0][1]
+ nested_tuples[1][0]
+ nested_tuples[1][1] # $ MISSING: tracked
+
+ (aa, ab), (ba, bb) = nested_tuples
+ aa # $ MISSING: tracked
+ ab
+ ba
+ bb # $ MISSING: tracked
+
+
+ # non-precise access is not supported right now (and it's not 100% clear if we want
+ # to support it, or if it will lead to bad results)
+ for (x, y) in nested_tuples:
+ x
+ y
+
+
def test_dict(key_arg):
d1 = {"t": tracked, "o": other} # $tracked
d1["t"] # $ tracked
From 7a3ee0f5f8145abe25b26a64415a43ed32b7016e Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Wed, 13 Mar 2024 16:41:42 +0100
Subject: [PATCH 086/497] Python: Make `IterableSequenceNode` LocalSourceNode
We do this to remove the inconsistencies, and to be ready for a future
where type-tracking support content tracker of depth > 1.
It works because targets of loadSteps needs to be LocalSourceNodes
predicate loadStep(Node nodeFrom, LocalSourceNode nodeTo, Content content) {
---
.../python/dataflow/new/internal/LocalSources.qll | 2 ++
.../CONSISTENCY/TypeTrackingConsistency.expected | 13 -------------
2 files changed, 2 insertions(+), 13 deletions(-)
delete mode 100644 python/ql/test/experimental/dataflow/typetracking/CONSISTENCY/TypeTrackingConsistency.expected
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll b/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll
index 34b137b3511..92d9e5887ad 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll
@@ -74,6 +74,8 @@ class LocalSourceNode extends Node {
this instanceof ScopeEntryDefinitionNode
or
this instanceof ParameterNode
+ or
+ this instanceof IterableSequenceNode
}
/** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */
diff --git a/python/ql/test/experimental/dataflow/typetracking/CONSISTENCY/TypeTrackingConsistency.expected b/python/ql/test/experimental/dataflow/typetracking/CONSISTENCY/TypeTrackingConsistency.expected
deleted file mode 100644
index 6fc4df91699..00000000000
--- a/python/ql/test/experimental/dataflow/typetracking/CONSISTENCY/TypeTrackingConsistency.expected
+++ /dev/null
@@ -1,13 +0,0 @@
-unreachableNode
-| content_test.py:31:6:31:11 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 0. |
-| content_test.py:31:6:31:11 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 1. |
-| content_test.py:31:6:31:11 | ControlFlowNode for Tuple | Unreachable node in step of kind storeTarget. |
-| content_test.py:31:16:31:21 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 0. |
-| content_test.py:31:16:31:21 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 1. |
-| content_test.py:31:16:31:21 | ControlFlowNode for Tuple | Unreachable node in step of kind storeTarget. |
-| content_test.py:40:10:40:13 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 0. |
-| content_test.py:40:10:40:13 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 1. |
-| content_test.py:40:10:40:13 | ControlFlowNode for Tuple | Unreachable node in step of kind storeTarget. |
-| content_test.py:66:9:66:12 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 0. |
-| content_test.py:66:9:66:12 | ControlFlowNode for Tuple | Unreachable node in step of kind load Tuple element at index 1. |
-| content_test.py:66:9:66:12 | ControlFlowNode for Tuple | Unreachable node in step of kind storeTarget. |
From 5b734c76b651241e0776faf1ffa46e8a01a125c1 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Tue, 5 Mar 2024 15:50:16 +0000
Subject: [PATCH 087/497] Add manual neutral models for java.util.Locale and
its subclasses
---
java/ql/lib/ext/java.util.model.yml | 55 +++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/java/ql/lib/ext/java.util.model.yml b/java/ql/lib/ext/java.util.model.yml
index 7ab6780b8f8..8f621df591e 100644
--- a/java/ql/lib/ext/java.util.model.yml
+++ b/java/ql/lib/ext/java.util.model.yml
@@ -451,7 +451,62 @@ extensions:
- ["java.util", "List", "of", "()", "summary", "manual"]
- ["java.util", "List", "sort", "(Comparator)", "summary", "manual"]
- ["java.util", "List", "size", "()", "summary", "manual"]
+ - ["java.util", "Locale$Builder", "addUnicodeLocaleAttribute", "(String)", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "build", "()", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "clear", "()", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "clearExtensions", "()", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "removeUnicodeLocaleAttribute", "(String)", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "setExtension", "(char,String)", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "setLanguage", "(String)", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "setLanguageTag", "(String)", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "setLocale", "(Locale)", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "setLocale", "(Locale)", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "setRegion", "(String)", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "setScript", "(String)", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "setUnicodeLocaleKeyword", "(String,String)", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "setVariant", "(String)", "summary", "df-manual"]
+ - ["java.util", "Locale$Builder", "setVariant", "(String)", "summary", "df-manual"]
+ - ["java.util", "Locale$LanguageRange", "LanguageRange", "(String)", "summary", "df-manual"]
+ - ["java.util", "Locale$LanguageRange", "LanguageRange", "(String,double)", "summary", "df-manual"]
+ - ["java.util", "Locale$LanguageRange", "getRange", "()", "summary", "df-manual"]
+ - ["java.util", "Locale$LanguageRange", "mapEquivalents", "(List,Map)", "summary", "df-manual"]
+ - ["java.util", "Locale$LanguageRange", "mapEquivalents", "(List,Map)", "summary", "df-manual"]
+ - ["java.util", "Locale$LanguageRange", "parse", "(String)", "summary", "df-manual"]
+ - ["java.util", "Locale$LanguageRange", "parse", "(String,Map)", "summary", "df-manual"]
+ - ["java.util", "Locale$LanguageRange", "parse", "(String,Map)", "summary", "df-manual"]
+ - ["java.util", "Locale", "Locale", "(String)", "summary", "df-manual"]
+ - ["java.util", "Locale", "Locale", "(String,String)", "summary", "df-manual"]
+ - ["java.util", "Locale", "Locale", "(String,String)", "summary", "df-manual"]
+ - ["java.util", "Locale", "Locale", "(String,String,String)", "summary", "df-manual"]
+ - ["java.util", "Locale", "Locale", "(String,String,String)", "summary", "df-manual"]
+ - ["java.util", "Locale", "Locale", "(String,String,String)", "summary", "df-manual"]
+ - ["java.util", "Locale", "filterTags", "(List,Collection)", "summary", "df-manual"]
+ - ["java.util", "Locale", "filterTags", "(List,Collection,Locale$FilteringMode)", "summary", "df-manual"]
- ["java.util", "Locale", "forLanguageTag", "(String)", "summary", "manual"]
+ - ["java.util", "Locale", "getCountry", "()", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayCountry", "()", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayCountry", "(Locale)", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayCountry", "(Locale)", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayLanguage", "()", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayLanguage", "(Locale)", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayLanguage", "(Locale)", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayName", "()", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayName", "(Locale)", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayName", "(Locale)", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayScript", "()", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayScript", "(Locale)", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayScript", "(Locale)", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayVariant", "()", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayVariant", "(Locale)", "summary", "df-manual"]
+ - ["java.util", "Locale", "getDisplayVariant", "(Locale)", "summary", "df-manual"]
+ - ["java.util", "Locale", "getExtensionKeys", "()", "summary", "df-manual"]
+ - ["java.util", "Locale", "getISO3Language", "()", "summary", "df-manual"]
+ - ["java.util", "Locale", "getLanguage", "()", "summary", "df-manual"]
+ - ["java.util", "Locale", "getScript", "()", "summary", "df-manual"]
+ - ["java.util", "Locale", "getVariant", "()", "summary", "df-manual"]
+ - ["java.util", "Locale", "lookupTag", "(List,Collection)", "summary", "df-manual"]
+ - ["java.util", "Locale", "stripExtensions", "()", "summary", "df-manual"]
+ - ["java.util", "Locale", "toLanguageTag", "()", "summary", "df-manual"]
- ["java.util", "Map", "containsKey", "(Object)", "summary", "manual"]
- ["java.util", "Map", "isEmpty", "()", "summary", "manual"]
- ["java.util", "Map", "size", "()", "summary", "manual"]
From 2bd08838d47309e6dbae9db9000cf39ec94587d2 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Wed, 6 Mar 2024 14:31:00 +0000
Subject: [PATCH 088/497] Add manual neutral models for java.lang.ClassLoader
---
java/ql/lib/ext/java.lang.model.yml | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/java/ql/lib/ext/java.lang.model.yml b/java/ql/lib/ext/java.lang.model.yml
index 0569b4c209c..fff3a90dcb3 100644
--- a/java/ql/lib/ext/java.lang.model.yml
+++ b/java/ql/lib/ext/java.lang.model.yml
@@ -185,8 +185,19 @@ extensions:
- ["java.lang", "Class", "isAssignableFrom", "(Class)", "summary", "manual"]
- ["java.lang", "Class", "isInstance", "(Object)", "summary", "manual"]
- ["java.lang", "Class", "toString", "()", "summary", "manual"]
+ - ["java.lang", "ClassLoader", "findResource", "(String)", "summary", "df-manual"]
+ - ["java.lang", "ClassLoader", "getDefinedPackage", "(String)", "summary", "df-manual"]
+ - ["java.lang", "ClassLoader", "getDefinedPackage", "(String)", "summary", "df-manual"]
+ - ["java.lang", "ClassLoader", "getName", "()", "summary", "df-manual"]
+ - ["java.lang", "ClassLoader", "getParent", "()", "summary", "df-manual"]
- ["java.lang", "ClassLoader", "getResource", "(String)", "summary", "manual"]
- ["java.lang", "ClassLoader", "getResourceAsStream", "(String)", "summary", "manual"]
+ - ["java.lang", "ClassLoader", "getSystemResource", "(String)", "summary", "df-manual"]
+ - ["java.lang", "ClassLoader", "getUnnamedModule", "()", "summary", "df-manual"]
+ - ["java.lang", "ClassLoader", "loadClass", "(String)", "summary", "df-manual"]
+ - ["java.lang", "ClassLoader", "loadClass", "(String,boolean)", "summary", "df-manual"]
+ - ["java.lang", "ClassLoader", "setClassAssertionStatus", "(String,boolean)", "summary", "df-manual"]
+ - ["java.lang", "ClassLoader", "setPackageAssertionStatus", "(String,boolean)", "summary", "df-manual"]
- ["java.lang", "Enum", "Enum", "(String,int)", "summary", "manual"]
- ["java.lang", "Enum", "equals", "(Object)", "summary", "manual"]
- ["java.lang", "Enum", "hashCode", "()", "summary", "manual"]
From 00f2a6a65e76336e0cd926a1630dd0001ed3bd14 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 15 Mar 2024 10:14:45 +0100
Subject: [PATCH 089/497] Python: Update ssa-compute test expectations
---
.../CONSISTENCY/TypeTrackingConsistency.expected | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/python/ql/test/library-tests/essa/ssa-compute/CONSISTENCY/TypeTrackingConsistency.expected b/python/ql/test/library-tests/essa/ssa-compute/CONSISTENCY/TypeTrackingConsistency.expected
index 81d19f3f20d..0e829fd207f 100644
--- a/python/ql/test/library-tests/essa/ssa-compute/CONSISTENCY/TypeTrackingConsistency.expected
+++ b/python/ql/test/library-tests/essa/ssa-compute/CONSISTENCY/TypeTrackingConsistency.expected
@@ -1,6 +1,6 @@
unreachableNode
-| test2.py:16:17:16:17 | ControlFlowNode for y | Unreachable node in step of kind load bar. |
-| test2.py:25:23:25:23 | ControlFlowNode for x | Unreachable node in step of kind load attribute. |
+| test2.py:16:17:16:17 | ControlFlowNode for y | Unreachable node in step of kind load Attribute bar. |
+| test2.py:25:23:25:23 | ControlFlowNode for x | Unreachable node in step of kind load Attribute attribute. |
| test2.py:25:23:25:23 | ControlFlowNode for x | Unreachable node in step of kind simpleLocalSmallStep. |
-| test2.py:26:17:26:17 | ControlFlowNode for y | Unreachable node in step of kind load bar. |
+| test2.py:26:17:26:17 | ControlFlowNode for y | Unreachable node in step of kind load Attribute bar. |
| test2.py:27:23:27:23 | ControlFlowNode for x | Unreachable node in step of kind simpleLocalSmallStep. |
From 6babb2ff909d750c908ed3f2faadc8a5285fe81e Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 15 Mar 2024 10:24:33 +0100
Subject: [PATCH 090/497] Python: Accept .expected for `typetracking-summaries`
---
.../experimental/dataflow/typetracking-summaries/summaries.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py
index e11f451b865..89b5e1756d5 100644
--- a/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py
+++ b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py
@@ -41,8 +41,8 @@ tms = tainted_mapped_summary[0]
tms # $ MISSING: tracked
another_tainted_list = TTS_append_to_list([], tracked) # $ tracked
-atl = another_tainted_list[0]
-atl # $ MISSING: tracked
+atl = another_tainted_list[0] # $ tracked
+atl # $ tracked
# This will not work, as the call is not found by `getACallSimple`.
from json import loads as json_loads
From 7eb4419342e08b9f537cd75e1db2e0f5693c55fe Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 15 Mar 2024 10:24:57 +0100
Subject: [PATCH 091/497] Python: Restrict type-tracking content to only be
precise
At least for now :)
---
.../dataflow/new/internal/TypeTrackingImpl.qll | 16 +++++++++++++++-
.../dataflow/typetracking-summaries/summaries.py | 4 ++--
2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
index 8b3e1a95ef1..ce95a6cca4e 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll
@@ -102,7 +102,21 @@ module TypeTrackingInput implements Shared::TypeTrackingInput {
class LocalSourceNode = DataFlowPublic::LocalSourceNode;
- class Content = DataFlowPublic::Content;
+ class Content extends DataFlowPublic::Content {
+ Content() {
+ // TODO: for now, it's not 100% clear if should support non-precise content in
+ // type-tracking, or if it will lead to bad results. We start with only allowing
+ // precise content, which should always be a good improvement! It also simplifies
+ // the process of examining new results from non-precise content steps in the
+ // future, since you will _only_ have to look over the results from the new
+ // non-precise steps.
+ this instanceof DataFlowPublic::AttributeContent
+ or
+ this instanceof DataFlowPublic::DictionaryElementContent
+ or
+ this instanceof DataFlowPublic::TupleElementContent
+ }
+ }
/**
* A label to use for `WithContent` and `WithoutContent` steps, restricting
diff --git a/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py
index 89b5e1756d5..e11f451b865 100644
--- a/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py
+++ b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py
@@ -41,8 +41,8 @@ tms = tainted_mapped_summary[0]
tms # $ MISSING: tracked
another_tainted_list = TTS_append_to_list([], tracked) # $ tracked
-atl = another_tainted_list[0] # $ tracked
-atl # $ tracked
+atl = another_tainted_list[0]
+atl # $ MISSING: tracked
# This will not work, as the call is not found by `getACallSimple`.
from json import loads as json_loads
From 8e52483bebdc1916ceda98d18ace0654346cdd35 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Thu, 14 Mar 2024 21:29:59 +0000
Subject: [PATCH 092/497] Add df-manual models in manually modeled classes
---
java/ql/lib/ext/java.io.model.yml | 2 ++
java/ql/lib/ext/java.lang.model.yml | 17 +++++++++--------
java/ql/lib/ext/java.util.model.yml | 12 ++++++++++++
3 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/java/ql/lib/ext/java.io.model.yml b/java/ql/lib/ext/java.io.model.yml
index 3824c588662..e8a14a13e51 100644
--- a/java/ql/lib/ext/java.io.model.yml
+++ b/java/ql/lib/ext/java.io.model.yml
@@ -78,11 +78,13 @@ extensions:
- ["java.io", "File", True, "getCanonicalFile", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.io", "File", True, "getCanonicalPath", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.io", "File", True, "getName", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]
+ - ["java.io", "File", True, "getParent", "()", "", "Argument[this]", "ReturnValue", "taint", "df-manual"]
- ["java.io", "File", True, "getParentFile", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.io", "File", True, "getPath", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.io", "File", True, "toPath", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.io", "File", True, "toString", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.io", "File", True, "toURI", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
+ - ["java.io", "File", True, "toURL", "()", "", "Argument[this]", "ReturnValue", "taint", "df-manual"]
- ["java.io", "FilterOutputStream", True, "FilterOutputStream", "(OutputStream)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["java.io", "InputStream", True, "read", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.io", "InputStream", True, "read", "(byte[])", "", "Argument[this]", "Argument[0]", "taint", "manual"]
diff --git a/java/ql/lib/ext/java.lang.model.yml b/java/ql/lib/ext/java.lang.model.yml
index fff3a90dcb3..92f0a7a0805 100644
--- a/java/ql/lib/ext/java.lang.model.yml
+++ b/java/ql/lib/ext/java.lang.model.yml
@@ -114,6 +114,7 @@ extensions:
- ["java.lang", "String", False, "indent", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.lang", "String", False, "intern", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.lang", "String", False, "join", "", "", "Argument[0..1]", "ReturnValue", "taint", "manual"]
+ - ["java.lang", "String", False, "lines", "()", "", "Argument[this]", "ReturnValue.Element", "taint", "df-generated"]
- ["java.lang", "String", False, "repeat", "(int)", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.lang", "String", False, "replace", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.lang", "String", False, "replace", "", "", "Argument[1]", "ReturnValue", "taint", "manual"]
@@ -239,14 +240,14 @@ extensions:
- ["java.lang", "Thread", "interrupt", "()", "summary", "manual"]
- ["java.lang", "Thread", "sleep", "(long)", "summary", "manual"]
- ["java.lang", "Thread", "start", "()", "summary", "manual"]
- - ["java.lang", "Throwable", "addSuppressed", "(Throwable)", "summary", "manual"]
- - ["java.lang", "Throwable", "fillInStackTrace", "()", "summary", "manual"]
- - ["java.lang", "Throwable", "getStackTrace", "()", "summary", "manual"]
- - ["java.lang", "Throwable", "getSuppressed", "()", "summary", "manual"]
- - ["java.lang", "Throwable", "printStackTrace", "()", "summary", "manual"]
- - ["java.lang", "Throwable", "printStackTrace", "(PrintStream)", "summary", "manual"]
- - ["java.lang", "Throwable", "printStackTrace", "(PrintWriter)", "summary", "manual"]
- - ["java.lang", "Throwable", "setStackTrace", "(StackTraceElement[])", "summary", "manual"]
+ - ["java.lang", "Throwable", "addSuppressed", "(Throwable)", "summary", "df-manual"]
+ - ["java.lang", "Throwable", "fillInStackTrace", "()", "summary", "df-manual"]
+ - ["java.lang", "Throwable", "getStackTrace", "()", "summary", "df-manual"]
+ - ["java.lang", "Throwable", "getSuppressed", "()", "summary", "df-manual"]
+ - ["java.lang", "Throwable", "printStackTrace", "()", "summary", "df-manual"]
+ - ["java.lang", "Throwable", "printStackTrace", "(PrintStream)", "summary", "df-manual"]
+ - ["java.lang", "Throwable", "printStackTrace", "(PrintWriter)", "summary", "df-manual"]
+ - ["java.lang", "Throwable", "setStackTrace", "(StackTraceElement[])", "summary", "df-manual"]
# The below APIs have numeric flow and are currently being stored as neutral models.
# These may be changed to summary models with kinds "value-numeric" and "taint-numeric" (or similar) in the future.
- ["java.lang", "Double", "doubleToLongBits", "(double)", "summary", "manual"] # taint-numeric
diff --git a/java/ql/lib/ext/java.util.model.yml b/java/ql/lib/ext/java.util.model.yml
index 8f621df591e..be4665d4cd7 100644
--- a/java/ql/lib/ext/java.util.model.yml
+++ b/java/ql/lib/ext/java.util.model.yml
@@ -58,6 +58,7 @@ extensions:
- ["java.util", "Collection", True, "toArray", "", "", "Argument[this].Element", "Argument[0].ArrayElement", "value", "manual"]
- ["java.util", "Collection", True, "toArray", "", "", "Argument[this].Element", "ReturnValue.ArrayElement", "value", "manual"]
- ["java.util", "Collections", False, "addAll", "(Collection,Object[])", "", "Argument[1].ArrayElement", "Argument[0].Element", "value", "manual"]
+ - ["java.util", "Collections", False, "asLifoQueue", "(Deque)", "", "Argument[0].Element", "ReturnValue.Element", "value", "df-manual"]
- ["java.util", "Collections", False, "checkedCollection", "(Collection,Class)", "", "Argument[0].Element", "ReturnValue.Element", "value", "manual"]
- ["java.util", "Collections", False, "checkedList", "(List,Class)", "", "Argument[0].Element", "ReturnValue.Element", "value", "manual"]
- ["java.util", "Collections", False, "checkedMap", "(Map,Class,Class)", "", "Argument[0].MapKey", "ReturnValue.MapKey", "value", "manual"]
@@ -65,6 +66,7 @@ extensions:
- ["java.util", "Collections", False, "checkedNavigableMap", "(NavigableMap,Class,Class)", "", "Argument[0].MapKey", "ReturnValue.MapKey", "value", "manual"]
- ["java.util", "Collections", False, "checkedNavigableMap", "(NavigableMap,Class,Class)", "", "Argument[0].MapValue", "ReturnValue.MapValue", "value", "manual"]
- ["java.util", "Collections", False, "checkedNavigableSet", "(NavigableSet,Class)", "", "Argument[0].Element", "ReturnValue.Element", "value", "manual"]
+ - ["java.util", "Collections", False, "checkedQueue", "(Queue,Class)", "", "Argument[0].Element", "ReturnValue.Element", "value", "df-manual"]
- ["java.util", "Collections", False, "checkedSet", "(Set,Class)", "", "Argument[0].Element", "ReturnValue.Element", "value", "manual"]
- ["java.util", "Collections", False, "checkedSortedMap", "(SortedMap,Class,Class)", "", "Argument[0].MapKey", "ReturnValue.MapKey", "value", "manual"]
- ["java.util", "Collections", False, "checkedSortedMap", "(SortedMap,Class,Class)", "", "Argument[0].MapValue", "ReturnValue.MapValue", "value", "manual"]
@@ -309,6 +311,9 @@ extensions:
- ["java.util", "Queue", True, "poll", "()", "", "Argument[this].Element", "ReturnValue", "value", "manual"]
- ["java.util", "Queue", True, "remove", "()", "", "Argument[this].Element", "ReturnValue", "value", "manual"]
- ["java.util", "ResourceBundle", True, "getString", "(String)", "", "Argument[this].MapValue", "ReturnValue", "value", "manual"]
+ - ["java.util", "Scanner", True, "findAll", "(Pattern)", "", "Argument[this]", "ReturnValue.Element", "taint", "df-manual"]
+ - ["java.util", "Scanner", True, "findAll", "(String)", "", "Argument[this]", "ReturnValue", "taint", "df-manual"]
+ - ["java.util", "Scanner", True, "match", "()", "", "Argument[this]", "ReturnValue", "taint", "df-manual"]
- ["java.util", "Scanner", True, "Scanner", "", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["java.util", "Scanner", True, "findInLine", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["java.util", "Scanner", True, "findWithinHorizon", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
@@ -428,6 +433,8 @@ extensions:
- ["java.util", "Collections", "emptyList", "()", "summary", "manual"]
- ["java.util", "Collections", "emptyMap", "()", "summary", "manual"]
- ["java.util", "Collections", "emptySet", "()", "summary", "manual"]
+ - ["java.util", "Collections", "newSetFromMap", "", "summary", "df-manual"]
+ - ["java.util", "Collections", "reverseOrder", "", "summary", "df-manual"]
- ["java.util", "Collections", "sort", "", "summary", "manual"]
- ["java.util", "Enumeration", "hasMoreElements", "()", "summary", "manual"]
- ["java.util", "EnumSet", "allOf", "(Class)", "summary", "df-manual"]
@@ -520,6 +527,11 @@ extensions:
- ["java.util", "Optional", "isPresent", "()", "summary", "manual"]
- ["java.util", "Random", "nextInt", "(int)", "summary", "manual"]
- ["java.util", "ResourceBundle", "getBundle", "", "summary", "df-manual"]
+ - ["java.util", "Scanner", "delimiter", "()", "summary", "df-generated"]
+ - ["java.util", "Scanner", "hasNext", "(Pattern)", "summary", "df-generated"]
+ - ["java.util", "Scanner", "hasNext", "(String)", "summary", "df-generated"]
+ - ["java.util", "Scanner", "ioException", "()", "summary", "df-generated"]
+ - ["java.util", "Scanner", "locale", "()", "summary", "df-generated"]
- ["java.util", "Set", "contains", "(Object)", "summary", "manual"]
- ["java.util", "Set", "isEmpty", "()", "summary", "manual"]
- ["java.util", "Set", "size", "()", "summary", "manual"]
From cfbc3f73ec47a7d8e69311f280019b926f5ffaab Mon Sep 17 00:00:00 2001
From: Rasmus Lerchedahl Petersen
Date: Fri, 15 Mar 2024 15:13:39 +0100
Subject: [PATCH 093/497] Pyhton: add test for conflicting summaries We noticed
that when - a function has more than one summary (with different charpred) -
one summary is subsumed by a subpath (or something happens around the
function being extracted) - the function is called multiple times(we needed
at least three) one of the summaries would no longer lead to flow.
---
.../summaries/InlineTaintTest.expected | 4 +
.../dataflow/summaries/InlineTaintTest.ql | 4 +
.../dataflow/summaries/TestSummaries.qll | 105 ++++++++++++++++++
.../summaries/conflicting_summaries.py | 18 +++
.../summaries/extracted_package/functions.py | 5 +
5 files changed, 136 insertions(+)
create mode 100644 python/ql/test/experimental/dataflow/summaries/InlineTaintTest.expected
create mode 100644 python/ql/test/experimental/dataflow/summaries/InlineTaintTest.ql
create mode 100644 python/ql/test/experimental/dataflow/summaries/conflicting_summaries.py
create mode 100644 python/ql/test/experimental/dataflow/summaries/extracted_package/functions.py
diff --git a/python/ql/test/experimental/dataflow/summaries/InlineTaintTest.expected b/python/ql/test/experimental/dataflow/summaries/InlineTaintTest.expected
new file mode 100644
index 00000000000..366de37b867
--- /dev/null
+++ b/python/ql/test/experimental/dataflow/summaries/InlineTaintTest.expected
@@ -0,0 +1,4 @@
+argumentToEnsureNotTaintedNotMarkedAsSpurious
+untaintedArgumentToEnsureTaintedNotMarkedAsMissing
+testFailures
+failures
diff --git a/python/ql/test/experimental/dataflow/summaries/InlineTaintTest.ql b/python/ql/test/experimental/dataflow/summaries/InlineTaintTest.ql
new file mode 100644
index 00000000000..96cc5c3e31f
--- /dev/null
+++ b/python/ql/test/experimental/dataflow/summaries/InlineTaintTest.ql
@@ -0,0 +1,4 @@
+import python
+import experimental.meta.InlineTaintTest
+import MakeInlineTaintTest
+import TestSummaries
diff --git a/python/ql/test/experimental/dataflow/summaries/TestSummaries.qll b/python/ql/test/experimental/dataflow/summaries/TestSummaries.qll
index b2e29e9999e..534fac62491 100644
--- a/python/ql/test/experimental/dataflow/summaries/TestSummaries.qll
+++ b/python/ql/test/experimental/dataflow/summaries/TestSummaries.qll
@@ -136,3 +136,108 @@ private class SummarizedCallableJsonLoads extends SummarizedCallable {
preservesValue = true
}
}
+
+// Repeated summaries
+private class SummarizedCallableWithSubpath extends SummarizedCallable {
+ SummarizedCallableWithSubpath() { this = "extracted_package.functions.with_subpath" }
+
+ override DataFlow::CallCfgNode getACall() {
+ result =
+ API::moduleImport("extracted_package")
+ .getMember("functions")
+ .getMember("with_subpath")
+ .getACall()
+ }
+
+ override DataFlow::ArgumentNode getACallback() {
+ result =
+ API::moduleImport("extracted_package")
+ .getMember("functions")
+ .getMember("with_subpath")
+ .getAValueReachableFromSource()
+ }
+
+ override predicate propagatesFlow(string input, string output, boolean preservesValue) {
+ input = "Argument[0]" and
+ output = "ReturnValue" and
+ preservesValue = false
+ }
+}
+
+private class SummarizedCallableWithSubpathAgain extends SummarizedCallable {
+ SummarizedCallableWithSubpathAgain() { this = "extracted_package.functions.with_subpathII" }
+
+ override DataFlow::CallCfgNode getACall() {
+ result =
+ API::moduleImport("extracted_package")
+ .getMember("functions")
+ .getMember("with_subpath")
+ .getACall()
+ }
+
+ override DataFlow::ArgumentNode getACallback() {
+ result =
+ API::moduleImport("extracted_package")
+ .getMember("functions")
+ .getMember("with_subpath")
+ .getAValueReachableFromSource()
+ }
+
+ override predicate propagatesFlow(string input, string output, boolean preservesValue) {
+ input = "Argument[0]" and
+ output = "ReturnValue.Attribute[pattern]" and
+ preservesValue = true
+ }
+}
+
+private class SummarizedCallableWithoutSubpath extends SummarizedCallable {
+ SummarizedCallableWithoutSubpath() { this = "extracted_package.functions.without_subpath" }
+
+ override DataFlow::CallCfgNode getACall() {
+ result =
+ API::moduleImport("extracted_package")
+ .getMember("functions")
+ .getMember("without_subpath")
+ .getACall()
+ }
+
+ override DataFlow::ArgumentNode getACallback() {
+ result =
+ API::moduleImport("extracted_package")
+ .getMember("functions")
+ .getMember("without_subpath")
+ .getAValueReachableFromSource()
+ }
+
+ override predicate propagatesFlow(string input, string output, boolean preservesValue) {
+ input = "Argument[0]" and
+ output = "ReturnValue" and
+ preservesValue = false
+ }
+}
+
+private class SummarizedCallableWithoutSubpathAgain extends SummarizedCallable {
+ SummarizedCallableWithoutSubpathAgain() { this = "extracted_package.functions.without_subpathII" }
+
+ override DataFlow::CallCfgNode getACall() {
+ result =
+ API::moduleImport("extracted_package")
+ .getMember("functions")
+ .getMember("without_subpath")
+ .getACall()
+ }
+
+ override DataFlow::ArgumentNode getACallback() {
+ result =
+ API::moduleImport("extracted_package")
+ .getMember("functions")
+ .getMember("without_subpath")
+ .getAValueReachableFromSource()
+ }
+
+ override predicate propagatesFlow(string input, string output, boolean preservesValue) {
+ input = "Argument[0]" and
+ output = "ReturnValue.Attribute[pattern]" and
+ preservesValue = true
+ }
+}
diff --git a/python/ql/test/experimental/dataflow/summaries/conflicting_summaries.py b/python/ql/test/experimental/dataflow/summaries/conflicting_summaries.py
new file mode 100644
index 00000000000..9528e9cdafc
--- /dev/null
+++ b/python/ql/test/experimental/dataflow/summaries/conflicting_summaries.py
@@ -0,0 +1,18 @@
+# Bad interaction of two summaries for the same function
+ts = TAINTED_STRING
+
+from extracted_package.functions import with_subpath, without_subpath
+
+# For the function `with_subpath`, flow from the first argument to the return value
+# can be concluded from its definition. This seems to discard all summaries, including
+# the one with flow to `ReturnValue.Attribute[pattern]`.
+ensure_tainted(
+ with_subpath(ts).pattern, # $ MISSING: tainted
+ with_subpath(ts), # $ tainted
+ with_subpath(ts), # $ tainted
+)
+ensure_tainted(
+ without_subpath(ts).pattern, # $ tainted
+ without_subpath(ts), # $ tainted
+ without_subpath(ts), # $ tainted
+)
\ No newline at end of file
diff --git a/python/ql/test/experimental/dataflow/summaries/extracted_package/functions.py b/python/ql/test/experimental/dataflow/summaries/extracted_package/functions.py
new file mode 100644
index 00000000000..f4780be20a3
--- /dev/null
+++ b/python/ql/test/experimental/dataflow/summaries/extracted_package/functions.py
@@ -0,0 +1,5 @@
+def with_subpath(x):
+ return x
+
+def without_subpath(x):
+ pass
\ No newline at end of file
From 55f7369df0d44893dd4cd4d843b7e740cc764854 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Fri, 15 Mar 2024 14:06:36 -0400
Subject: [PATCH 094/497] Java: performance fix
---
java/ql/lib/semmle/code/java/security/UrlForward.qll | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/java/ql/lib/semmle/code/java/security/UrlForward.qll b/java/ql/lib/semmle/code/java/security/UrlForward.qll
index b8cc6821abf..464a125ef75 100644
--- a/java/ql/lib/semmle/code/java/security/UrlForward.qll
+++ b/java/ql/lib/semmle/code/java/security/UrlForward.qll
@@ -26,10 +26,15 @@ private class DefaultUrlForwardSink extends UrlForwardSink {
private class SpringUrlForwardPrefixSink extends UrlForwardSink {
SpringUrlForwardPrefixSink() {
any(SpringRequestMappingMethod srmm).polyCalls*(this.getEnclosingCallable()) and
- this.asExpr() = any(ForwardPrefix fp).getAnAppendedExpression()
+ appendedToForwardPrefix(this)
}
}
+pragma[nomagic]
+private predicate appendedToForwardPrefix(DataFlow::ExprNode exprNode) {
+ exists(ForwardPrefix fp | exprNode.asExpr() = fp.getAnAppendedExpression())
+}
+
private class ForwardPrefix extends InterestingPrefix {
ForwardPrefix() { this.getStringValue() = "forward:" }
From fc367042efdba093a21e8d37ac3df1062c93c83f Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Fri, 15 Mar 2024 23:19:25 +0000
Subject: [PATCH 095/497] Fix df-manual model with wrong parameter type
---
java/ql/lib/ext/java.nio.file.model.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/ql/lib/ext/java.nio.file.model.yml b/java/ql/lib/ext/java.nio.file.model.yml
index fc0648c85aa..8f8db20a0c0 100644
--- a/java/ql/lib/ext/java.nio.file.model.yml
+++ b/java/ql/lib/ext/java.nio.file.model.yml
@@ -91,7 +91,7 @@ extensions:
data:
# summary neutrals
- ["java.nio.file", "Files", "exists", "(Path,LinkOption[])", "summary", "manual"]
- - ["java.nio.file", "Files", "newInputStream", "(Path,LinkOption[])", "summary", "df-manual"]
+ - ["java.nio.file", "Files", "newInputStream", "(Path,OpenOption[])", "summary", "df-manual"]
# sink neutrals
- ["java.nio.file", "Files", "getLastModifiedTime", "", "sink", "hq-manual"]
- ["java.nio.file", "Files", "getOwner", "", "sink", "hq-manual"]
From 23a58a0835f096e8abba75247203235190ff2963 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Fri, 15 Mar 2024 23:21:29 +0000
Subject: [PATCH 096/497] Add df-manual models related to existing df-manual
models
---
java/ql/lib/ext/java.io.model.yml | 1 +
java/ql/lib/ext/java.net.model.yml | 1 +
java/ql/lib/ext/javax.crypto.spec.model.yml | 1 +
3 files changed, 3 insertions(+)
diff --git a/java/ql/lib/ext/java.io.model.yml b/java/ql/lib/ext/java.io.model.yml
index e8a14a13e51..1cbbf456779 100644
--- a/java/ql/lib/ext/java.io.model.yml
+++ b/java/ql/lib/ext/java.io.model.yml
@@ -120,6 +120,7 @@ extensions:
- ["java.io", "File", "listFiles", "", "summary", "df-manual"]
- ["java.io", "File", "mkdirs", "()", "summary", "manual"]
- ["java.io", "FileInputStream", "FileInputStream", "(File)", "summary", "manual"]
+ - ["java.io", "FileInputStream", "FileInputStream", "(FileDescriptor)", "summary", "df-manual"]
- ["java.io", "FileInputStream", "FileInputStream", "(String)", "summary", "df-manual"]
- ["java.io", "InputStream", "close", "()", "summary", "manual"]
- ["java.io", "ObjectInput", "readObject", "()", "summary", "df-manual"] # this is a deserialization sink modeled in regular CodeQL
diff --git a/java/ql/lib/ext/java.net.model.yml b/java/ql/lib/ext/java.net.model.yml
index 19044ec7a40..5884c60e4e7 100644
--- a/java/ql/lib/ext/java.net.model.yml
+++ b/java/ql/lib/ext/java.net.model.yml
@@ -67,4 +67,5 @@ extensions:
data:
# summary neutrals
- ["java.net", "Socket", "getOutputStream", "()", "summary", "df-manual"]
+ - ["java.net", "Socket", "connect", "(SocketAddress)", "summary", "df-manual"]
- ["java.net", "Socket", "connect", "(SocketAddress,int)", "summary", "df-manual"]
diff --git a/java/ql/lib/ext/javax.crypto.spec.model.yml b/java/ql/lib/ext/javax.crypto.spec.model.yml
index 2a88b6275fd..d2b7dbc99b8 100644
--- a/java/ql/lib/ext/javax.crypto.spec.model.yml
+++ b/java/ql/lib/ext/javax.crypto.spec.model.yml
@@ -31,3 +31,4 @@ extensions:
extensible: neutralModel
data:
- ["javax.crypto.spec", "SecretKeySpec", "SecretKeySpec", "(byte[],String)", "summary", "df-manual"]
+ - ["javax.crypto.spec", "SecretKeySpec", "SecretKeySpec", "(byte[],int,int,String)", "summary", "df-manual"]
From 658fffeac1acaf6e3b823635efd27df7f611584f Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Sun, 17 Mar 2024 22:03:59 -0400
Subject: [PATCH 097/497] Java: remove experimental files
---
...ndertow.server.handlers.resource.model.yml | 8 -
.../jakarta.servlet.http.model.yml | 6 -
.../ext/experimental/java.nio.file.model.yml | 10 --
.../java.util.concurrent.model.yml | 1 -
.../experimental/javax.servlet.http.model.yml | 6 -
.../org.springframework.core.io.model.yml | 16 --
.../CWE/CWE-552/UnsafeLoadSpringResource.java | 21 ---
.../CWE/CWE-552/UnsafeResourceGet.java | 18 --
.../CWE-552/UnsafeServletRequestDispatch.java | 11 --
.../CWE/CWE-552/UnsafeUrlForward.java | 38 ----
.../CWE/CWE-552/UnsafeUrlForward.qhelp | 70 --------
.../Security/CWE/CWE-552/UnsafeUrlForward.ql | 64 -------
.../Security/CWE/CWE-552/UnsafeUrlForward.qll | 163 ------------------
13 files changed, 432 deletions(-)
delete mode 100644 java/ql/lib/ext/experimental/io.undertow.server.handlers.resource.model.yml
delete mode 100644 java/ql/lib/ext/experimental/jakarta.servlet.http.model.yml
delete mode 100644 java/ql/lib/ext/experimental/java.nio.file.model.yml
delete mode 100644 java/ql/lib/ext/experimental/org.springframework.core.io.model.yml
delete mode 100644 java/ql/src/experimental/Security/CWE/CWE-552/UnsafeLoadSpringResource.java
delete mode 100644 java/ql/src/experimental/Security/CWE/CWE-552/UnsafeResourceGet.java
delete mode 100644 java/ql/src/experimental/Security/CWE/CWE-552/UnsafeServletRequestDispatch.java
delete mode 100644 java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.java
delete mode 100644 java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qhelp
delete mode 100644 java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.ql
delete mode 100644 java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qll
diff --git a/java/ql/lib/ext/experimental/io.undertow.server.handlers.resource.model.yml b/java/ql/lib/ext/experimental/io.undertow.server.handlers.resource.model.yml
deleted file mode 100644
index 5c86c75522c..00000000000
--- a/java/ql/lib/ext/experimental/io.undertow.server.handlers.resource.model.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-extensions:
- - addsTo:
- pack: codeql/java-all
- extensible: experimentalSummaryModel
- data:
- - ["io.undertow.server.handlers.resource", "Resource", True, "getFile", "", "", "Argument[this]", "ReturnValue", "taint", "manual", "unsafe-url-forward"]
- - ["io.undertow.server.handlers.resource", "Resource", True, "getFilePath", "", "", "Argument[this]", "ReturnValue", "taint", "manual", "unsafe-url-forward"]
- - ["io.undertow.server.handlers.resource", "Resource", True, "getPath", "", "", "Argument[this]", "ReturnValue", "taint", "manual", "unsafe-url-forward"]
diff --git a/java/ql/lib/ext/experimental/jakarta.servlet.http.model.yml b/java/ql/lib/ext/experimental/jakarta.servlet.http.model.yml
deleted file mode 100644
index 9500beba15b..00000000000
--- a/java/ql/lib/ext/experimental/jakarta.servlet.http.model.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-extensions:
- - addsTo:
- pack: codeql/java-all
- extensible: experimentalSourceModel
- data:
- - ["jakarta.servlet.http", "HttpServletRequest", True, "getServletPath", "", "", "ReturnValue", "remote", "manual", "unsafe-url-forward"]
diff --git a/java/ql/lib/ext/experimental/java.nio.file.model.yml b/java/ql/lib/ext/experimental/java.nio.file.model.yml
deleted file mode 100644
index 647d72329d0..00000000000
--- a/java/ql/lib/ext/experimental/java.nio.file.model.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-extensions:
- - addsTo:
- pack: codeql/java-all
- extensible: experimentalSummaryModel
- data:
- - ["java.nio.file", "Path", True, "normalize", "", "", "Argument[this]", "ReturnValue", "taint", "manual", "unsafe-url-forward"]
- - ["java.nio.file", "Path", True, "resolve", "", "", "Argument[this]", "ReturnValue", "taint", "manual", "unsafe-url-forward"]
- - ["java.nio.file", "Path", True, "resolve", "", "", "Argument[0]", "ReturnValue", "taint", "manual", "unsafe-url-forward"]
- - ["java.nio.file", "Path", True, "toString", "", "", "Argument[this]", "ReturnValue", "taint", "manual", "unsafe-url-forward"]
- - ["java.nio.file", "Paths", True, "get", "", "", "Argument[0..1]", "ReturnValue", "taint", "manual", "unsafe-url-forward"]
diff --git a/java/ql/lib/ext/experimental/java.util.concurrent.model.yml b/java/ql/lib/ext/experimental/java.util.concurrent.model.yml
index 82ff0a00570..9484a5f5eb9 100644
--- a/java/ql/lib/ext/experimental/java.util.concurrent.model.yml
+++ b/java/ql/lib/ext/experimental/java.util.concurrent.model.yml
@@ -4,4 +4,3 @@ extensions:
extensible: experimentalSinkModel
data:
- ["java.util.concurrent", "TimeUnit", True, "sleep", "", "", "Argument[0]", "thread-pause", "manual", "thread-resource-abuse"]
- - ["java.util.concurrent", "TimeUnit", True, "sleep", "", "", "Argument[0]", "thread-pause", "manual", "unsafe-url-forward"]
diff --git a/java/ql/lib/ext/experimental/javax.servlet.http.model.yml b/java/ql/lib/ext/experimental/javax.servlet.http.model.yml
index db140149a99..04681b300ca 100644
--- a/java/ql/lib/ext/experimental/javax.servlet.http.model.yml
+++ b/java/ql/lib/ext/experimental/javax.servlet.http.model.yml
@@ -1,9 +1,4 @@
extensions:
- - addsTo:
- pack: codeql/java-all
- extensible: experimentalSourceModel
- data:
- - ["javax.servlet.http", "HttpServletRequest", True, "getServletPath", "", "", "ReturnValue", "remote", "manual", "unsafe-url-forward"]
- addsTo:
pack: codeql/java-all
extensible: experimentalSourceModel
@@ -13,4 +8,3 @@ extensions:
- ["javax.servlet.http", "HttpServletRequest", False, "getRequestURI", "()", "", "ReturnValue", "uri-path", "manual", "permissive-dot-regex-query"]
- ["javax.servlet.http", "HttpServletRequest", False, "getRequestURL", "()", "", "ReturnValue", "uri-path", "manual", "permissive-dot-regex-query"]
- ["javax.servlet.http", "HttpServletRequest", False, "getServletPath", "()", "", "ReturnValue", "uri-path", "manual", "permissive-dot-regex-query"]
-
diff --git a/java/ql/lib/ext/experimental/org.springframework.core.io.model.yml b/java/ql/lib/ext/experimental/org.springframework.core.io.model.yml
deleted file mode 100644
index e929260f21b..00000000000
--- a/java/ql/lib/ext/experimental/org.springframework.core.io.model.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-extensions:
- - addsTo:
- pack: codeql/java-all
- extensible: experimentalSinkModel
- data:
- - ["org.springframework.core.io", "ClassPathResource", True, "getFilename", "", "", "Argument[this]", "get-resource", "manual", "unsafe-url-forward"]
- - ["org.springframework.core.io", "ClassPathResource", True, "getPath", "", "", "Argument[this]", "get-resource", "manual", "unsafe-url-forward"]
- - ["org.springframework.core.io", "ClassPathResource", True, "getURL", "", "", "Argument[this]", "get-resource", "manual", "unsafe-url-forward"]
- - ["org.springframework.core.io", "ClassPathResource", True, "resolveURL", "", "", "Argument[this]", "get-resource", "manual", "unsafe-url-forward"]
- - addsTo:
- pack: codeql/java-all
- extensible: experimentalSummaryModel
- data:
- - ["org.springframework.core.io", "ClassPathResource", False, "ClassPathResource", "", "", "Argument[0]", "Argument[this]", "taint", "manual", "unsafe-url-forward"]
- - ["org.springframework.core.io", "Resource", True, "createRelative", "", "", "Argument[0]", "ReturnValue", "taint", "manual", "unsafe-url-forward"]
- - ["org.springframework.core.io", "ResourceLoader", True, "getResource", "", "", "Argument[0]", "ReturnValue", "taint", "manual", "unsafe-url-forward"]
diff --git a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeLoadSpringResource.java b/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeLoadSpringResource.java
deleted file mode 100644
index ce462fe490e..00000000000
--- a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeLoadSpringResource.java
+++ /dev/null
@@ -1,21 +0,0 @@
-//BAD: no path validation in Spring resource loading
-@GetMapping("/file")
-public String getFileContent(@RequestParam(name="fileName") String fileName) {
- ClassPathResource clr = new ClassPathResource(fileName);
-
- File file = ResourceUtils.getFile(fileName);
-
- Resource resource = resourceLoader.getResource(fileName);
-}
-
-//GOOD: check for a trusted prefix, ensuring path traversal is not used to erase that prefix in Spring resource loading:
-@GetMapping("/file")
-public String getFileContent(@RequestParam(name="fileName") String fileName) {
- if (!fileName.contains("..") && fileName.hasPrefix("/public-content")) {
- ClassPathResource clr = new ClassPathResource(fileName);
-
- File file = ResourceUtils.getFile(fileName);
-
- Resource resource = resourceLoader.getResource(fileName);
- }
-}
diff --git a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeResourceGet.java b/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeResourceGet.java
deleted file mode 100644
index 8b3583bf59e..00000000000
--- a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeResourceGet.java
+++ /dev/null
@@ -1,18 +0,0 @@
-// BAD: no URI validation
-URL url = request.getServletContext().getResource(requestUrl);
-url = getClass().getResource(requestUrl);
-InputStream in = url.openStream();
-
-InputStream in = request.getServletContext().getResourceAsStream(requestPath);
-in = getClass().getClassLoader().getResourceAsStream(requestPath);
-
-// GOOD: check for a trusted prefix, ensuring path traversal is not used to erase that prefix:
-// (alternatively use `Path.normalize` instead of checking for `..`)
-if (!requestPath.contains("..") && requestPath.startsWith("/trusted")) {
- InputStream in = request.getServletContext().getResourceAsStream(requestPath);
-}
-
-Path path = Paths.get(requestUrl).normalize().toRealPath();
-if (path.startsWith("/trusted")) {
- URL url = request.getServletContext().getResource(path.toString());
-}
diff --git a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeServletRequestDispatch.java b/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeServletRequestDispatch.java
deleted file mode 100644
index 88a794ab9c6..00000000000
--- a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeServletRequestDispatch.java
+++ /dev/null
@@ -1,11 +0,0 @@
-// BAD: no URI validation
-String returnURL = request.getParameter("returnURL");
-RequestDispatcher rd = sc.getRequestDispatcher(returnURL);
-rd.forward(request, response);
-
-// GOOD: check for a trusted prefix, ensuring path traversal is not used to erase that prefix:
-// (alternatively use `Path.normalize` instead of checking for `..`)
-if (!returnURL.contains("..") && returnURL.hasPrefix("/pages")) { ... }
-// Also GOOD: check for a forbidden prefix, ensuring URL-encoding is not used to evade the check:
-// (alternatively use `URLDecoder.decode` before `hasPrefix`)
-if (returnURL.hasPrefix("/internal") && !returnURL.contains("%")) { ... }
\ No newline at end of file
diff --git a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.java b/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.java
deleted file mode 100644
index d159c405736..00000000000
--- a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.java
+++ /dev/null
@@ -1,38 +0,0 @@
-import java.io.IOException;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.servlet.ModelAndView;
-
-@Controller
-public class UnsafeUrlForward {
-
- @GetMapping("/bad1")
- public ModelAndView bad1(String url) {
- return new ModelAndView(url);
- }
-
- @GetMapping("/bad2")
- public void bad2(String url, HttpServletRequest request, HttpServletResponse response) {
- try {
- request.getRequestDispatcher("/WEB-INF/jsp/" + url + ".jsp").include(request, response);
- } catch (ServletException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- @GetMapping("/good1")
- public void good1(String url, HttpServletRequest request, HttpServletResponse response) {
- try {
- request.getRequestDispatcher("/index.jsp?token=" + url).forward(request, response);
- } catch (ServletException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-}
diff --git a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qhelp b/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qhelp
deleted file mode 100644
index 2e425952edc..00000000000
--- a/java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qhelp
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
-
-
-
Constructing a server-side redirect path with user input could allow an attacker to download application binaries
-(including application classes or jar files) or view arbitrary files within protected directories.
-
-
-
-
-
Unsanitized user provided data must not be used to construct the path for URL forwarding. In order to prevent
-untrusted URL forwarding, it is recommended to avoid concatenating user input directly into the forwarding URL.
-Instead, user input should be checked against allowed (e.g., must come within user_content/) or disallowed
-(e.g. must not come within /internal) paths, ensuring that neither path traversal using ../
-or URL encoding are used to evade these checks.
-
-
-
-
-
-
The following examples show the bad case and the good case respectively.
-The bad methods show an HTTP request parameter being used directly in a URL forward
-without validating the input, which may cause file leakage. In the good1 method,
-ordinary forwarding requests are shown, which will not cause file leakage.
-
-
-
-
-
The following examples show an HTTP request parameter or request path being used directly in a
-request dispatcher of Java EE without validating the input, which allows sensitive file exposure
-attacks. It also shows how to remedy the problem by validating the user input.
-
-
-
-
-
The following examples show an HTTP request parameter or request path being used directly to
-retrieve a resource of a Java EE application without validating the input, which allows sensitive
-file exposure attacks. It also shows how to remedy the problem by validating the user input.
-
-
-
-
-
The following examples show an HTTP request parameter being used directly to retrieve a resource
- of a Java Spring application without validating the input, which allows sensitive file exposure
- attacks. It also shows how to remedy the problem by validating the user input.
-