Compare commits

..

12 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
2e6bc6612c Update inline expectations and relearn affected tests 2026-06-26 08:07:15 +00:00
copilot-swe-agent[bot]
5c2614283d Initial plan 2026-06-26 07:28:39 +00:00
Owen Mansel-Chan
7b800b1dd6 Merge pull request #22065 from github/dependabot/go_modules/go/extractor/extractor-dependencies-9f88df4328
Bump golang.org/x/tools from 0.46.0 to 0.47.0 in /go/extractor in the extractor-dependencies group
2026-06-26 06:59:52 +01:00
dependabot[bot]
3d1b6b64ed Bump golang.org/x/tools
Bumps the extractor-dependencies group in /go/extractor with 1 update: [golang.org/x/tools](https://github.com/golang/tools).


Updates `golang.org/x/tools` from 0.46.0 to 0.47.0
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](https://github.com/golang/tools/compare/v0.46.0...v0.47.0)

---
updated-dependencies:
- dependency-name: golang.org/x/tools
  dependency-version: 0.47.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: extractor-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-26 03:03:16 +00:00
yoff
5fcaac7cb2 Merge pull request #21869 from yoff/python/support-flask-subclasses
Python: Support Flask subclasses
2026-06-25 23:42:21 +02:00
Mario Campos
336df3ccf4 Merge pull request #22060 from github/post-release-prep/codeql-cli-2.26.0
Post-release preparation for codeql-cli-2.26.0
2026-06-25 12:43:54 -05:00
github-actions[bot]
456e33773b Post-release preparation for codeql-cli-2.26.0 2026-06-25 16:24:06 +00:00
yoff
f7c4e61956 Apply suggestions from code review
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-02 15:12:41 +02:00
yoff
575ece6ae2 Python: Add change note 2026-06-02 13:50:31 +02:00
yoff
f6ed5c19be Python: fix sub class test 2026-06-02 13:50:31 +02:00
yoff
4298b70f1c Python: add test for sub class 2026-06-02 13:49:25 +02:00
yoff
e88b8c53f3 Python: Add test for instances 2026-06-02 13:49:24 +02:00
92 changed files with 222 additions and 175 deletions

View File

@@ -1,5 +1,5 @@
name: codeql/actions-all name: codeql/actions-all
version: 0.4.38 version: 0.4.39-dev
library: true library: true
warnOnImplicitThis: true warnOnImplicitThis: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/actions-queries name: codeql/actions-queries
version: 0.6.30 version: 0.6.31-dev
library: false library: false
warnOnImplicitThis: true warnOnImplicitThis: true
groups: [actions, queries] groups: [actions, queries]

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all name: codeql/cpp-all
version: 11.0.0 version: 11.0.1-dev
groups: cpp groups: cpp
dbscheme: semmlecode.cpp.dbscheme dbscheme: semmlecode.cpp.dbscheme
extractor: cpp extractor: cpp

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries name: codeql/cpp-queries
version: 1.6.5 version: 1.6.6-dev
groups: groups:
- cpp - cpp
- queries - queries

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all name: codeql/csharp-solorigate-all
version: 1.7.69 version: 1.7.70-dev
groups: groups:
- csharp - csharp
- solorigate - solorigate

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries name: codeql/csharp-solorigate-queries
version: 1.7.69 version: 1.7.70-dev
groups: groups:
- csharp - csharp
- solorigate - solorigate

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-all name: codeql/csharp-all
version: 7.0.0 version: 7.0.1-dev
groups: csharp groups: csharp
dbscheme: semmlecode.csharp.dbscheme dbscheme: semmlecode.csharp.dbscheme
extractor: csharp extractor: csharp

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-queries name: codeql/csharp-queries
version: 1.7.5 version: 1.7.6-dev
groups: groups:
- csharp - csharp
- queries - queries

View File

@@ -3,13 +3,13 @@ class C
void Problems() void Problems()
{ {
// correct expectation comment, but only for `problem-query` // correct expectation comment, but only for `problem-query`
var x = "Alert"; // $ Alert var x = "Alert"; // $ Alert[problem-query]
// irrelevant expectation comment, will be ignored // irrelevant expectation comment, will be ignored
x = "Not an alert"; // $ IrrelevantTag x = "Not an alert"; // $ IrrelevantTag
// incorrect expectation comment // incorrect expectation comment
x = "Also not an alert"; // $ Alert x = "Also not an alert"; // $ MISSING: Alert[problem-query]
// missing expectation comment, but only for `problem-query` // missing expectation comment, but only for `problem-query`
x = "Alert"; x = "Alert";

View File

@@ -13,8 +13,6 @@
| InlineTests.cs:88:13:88:23 | "Alert:0:1" | InlineTests.cs:88:13:88:23 | "Alert:0:1" | InlineTests.cs:87:16:87:21 | "Sink" | This is a problem | | InlineTests.cs:88:13:88:23 | "Alert:0:1" | InlineTests.cs:88:13:88:23 | "Alert:0:1" | InlineTests.cs:87:16:87:21 | "Sink" | This is a problem |
edges edges
testFailures testFailures
| InlineTests.cs:6:26:6:35 | // ... | Missing result: Alert |
| InlineTests.cs:12:34:12:43 | // ... | Missing result: Alert |
| InlineTests.cs:37:28:37:38 | // ... | Missing result: Source | | InlineTests.cs:37:28:37:38 | // ... | Missing result: Source |
| InlineTests.cs:38:24:38:32 | // ... | Missing result: Sink | | InlineTests.cs:38:24:38:32 | // ... | Missing result: Sink |
| InlineTests.cs:39:33:39:42 | // ... | Missing result: Alert | | InlineTests.cs:39:33:39:42 | // ... | Missing result: Alert |

View File

@@ -3,8 +3,6 @@
| InlineTests.cs:100:13:100:25 | "Alert:3:2:1" | InlineTests.cs:97:18:97:25 | "Source" | InlineTests.cs:98:16:98:21 | "Sink" | This is a problem with $@ | InlineTests.cs:99:19:99:27 | "Related" | a related location | | InlineTests.cs:100:13:100:25 | "Alert:3:2:1" | InlineTests.cs:97:18:97:25 | "Source" | InlineTests.cs:98:16:98:21 | "Sink" | This is a problem with $@ | InlineTests.cs:99:19:99:27 | "Related" | a related location |
edges edges
testFailures testFailures
| InlineTests.cs:6:26:6:35 | // ... | Missing result: Alert |
| InlineTests.cs:12:34:12:43 | // ... | Missing result: Alert |
| InlineTests.cs:32:32:32:42 | // ... | Missing result: Source | | InlineTests.cs:32:32:32:42 | // ... | Missing result: Source |
| InlineTests.cs:33:28:33:36 | // ... | Missing result: Sink | | InlineTests.cs:33:28:33:36 | // ... | Missing result: Sink |
| InlineTests.cs:34:30:34:39 | // ... | Missing result: Alert | | InlineTests.cs:34:30:34:39 | // ... | Missing result: Alert |

View File

@@ -3,7 +3,6 @@
| InlineTests.cs:15:13:15:19 | "Alert" | This is a problem | | InlineTests.cs:15:13:15:19 | "Alert" | This is a problem |
| InlineTests.cs:18:13:18:19 | "Alert" | This is a problem | | InlineTests.cs:18:13:18:19 | "Alert" | This is a problem |
testFailures testFailures
| InlineTests.cs:12:34:12:43 | // ... | Missing result: Alert |
| InlineTests.cs:15:13:15:19 | This is a problem | Unexpected result: Alert | | InlineTests.cs:15:13:15:19 | This is a problem | Unexpected result: Alert |
| InlineTests.cs:34:30:34:39 | // ... | Missing result: Alert | | InlineTests.cs:34:30:34:39 | // ... | Missing result: Alert |
| InlineTests.cs:39:33:39:42 | // ... | Missing result: Alert | | InlineTests.cs:39:33:39:42 | // ... | Missing result: Alert |

View File

@@ -2,8 +2,6 @@
| InlineTests.cs:22:13:22:21 | "Alert:1" | This is a problem with $@ | InlineTests.cs:21:23:21:31 | "Related" | a related location | | InlineTests.cs:22:13:22:21 | "Alert:1" | This is a problem with $@ | InlineTests.cs:21:23:21:31 | "Related" | a related location |
| InlineTests.cs:26:13:26:21 | "Alert:1" | This is a problem with $@ | InlineTests.cs:25:19:25:27 | "Related" | a related location | | InlineTests.cs:26:13:26:21 | "Alert:1" | This is a problem with $@ | InlineTests.cs:25:19:25:27 | "Related" | a related location |
testFailures testFailures
| InlineTests.cs:6:26:6:35 | // ... | Missing result: Alert |
| InlineTests.cs:12:34:12:43 | // ... | Missing result: Alert |
| InlineTests.cs:25:19:25:27 | "Related" | Unexpected result: RelatedLocation | | InlineTests.cs:25:19:25:27 | "Related" | Unexpected result: RelatedLocation |
| InlineTests.cs:34:30:34:39 | // ... | Missing result: Alert | | InlineTests.cs:34:30:34:39 | // ... | Missing result: Alert |
| InlineTests.cs:39:33:39:42 | // ... | Missing result: Alert | | InlineTests.cs:39:33:39:42 | // ... | Missing result: Alert |

View File

@@ -10,7 +10,7 @@ toolchain go1.26.4
// bazel mod tidy // bazel mod tidy
require ( require (
golang.org/x/mod v0.37.0 golang.org/x/mod v0.37.0
golang.org/x/tools v0.46.0 golang.org/x/tools v0.47.0
) )
require github.com/stretchr/testify v1.11.1 require github.com/stretchr/testify v1.11.1

View File

@@ -10,8 +10,8 @@ golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk= golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
golang.org/x/tools v0.46.0/go.mod h1:FrD85F8l+NWL+9XWBSyVSHO6Ne4jutsfIFba7AWQ5Ys= golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -1,5 +1,5 @@
name: codeql-go-consistency-queries name: codeql-go-consistency-queries
version: 1.0.52 version: 1.0.53-dev
groups: groups:
- go - go
- queries - queries

View File

@@ -1,5 +1,5 @@
name: codeql/go-all name: codeql/go-all
version: 7.2.0 version: 7.2.1-dev
groups: go groups: go
dbscheme: go.dbscheme dbscheme: go.dbscheme
extractor: go extractor: go

View File

@@ -1,5 +1,5 @@
name: codeql/go-queries name: codeql/go-queries
version: 1.6.5 version: 1.6.6-dev
groups: groups:
- go - go
- queries - queries

View File

@@ -1,5 +1,5 @@
name: codeql/java-all name: codeql/java-all
version: 9.2.0 version: 9.2.1-dev
groups: java groups: java
dbscheme: config/semmlecode.dbscheme dbscheme: config/semmlecode.dbscheme
extractor: java extractor: java

View File

@@ -1,5 +1,5 @@
name: codeql/java-queries name: codeql/java-queries
version: 1.11.5 version: 1.11.6-dev
groups: groups:
- java - java
- queries - queries

View File

@@ -30,7 +30,5 @@ nodes
| BadMacUse.java:152:42:152:51 | ciphertext | semmle.label | ciphertext | | BadMacUse.java:152:42:152:51 | ciphertext | semmle.label | ciphertext |
subpaths subpaths
testFailures testFailures
| BadMacUse.java:50:56:50:66 | // $ Source | Missing result: Source |
| BadMacUse.java:63:118:63:128 | // $ Source | Missing result: Source |
| BadMacUse.java:92:31:92:35 | bytes : byte[] | Unexpected result: Source | | BadMacUse.java:92:31:92:35 | bytes : byte[] | Unexpected result: Source |
| BadMacUse.java:146:95:146:105 | // $ Source | Missing result: Source | | BadMacUse.java:146:95:146:105 | // $ Source | Missing result: Source |

View File

@@ -31,7 +31,7 @@ nodes
| BadMacUse.java:124:42:124:51 | ciphertext | semmle.label | ciphertext | | BadMacUse.java:124:42:124:51 | ciphertext | semmle.label | ciphertext |
subpaths subpaths
testFailures testFailures
| BadMacUse.java:63:118:63:128 | // $ Source | Missing result: Source | | BadMacUse.java:50:28:50:53 | doFinal(...) : byte[] | Fixed missing result: Source |
| BadMacUse.java:92:16:92:36 | doFinal(...) : byte[] | Unexpected result: Source | | BadMacUse.java:92:16:92:36 | doFinal(...) : byte[] | Unexpected result: Source |
| BadMacUse.java:124:42:124:51 | ciphertext | Unexpected result: Alert | | BadMacUse.java:124:42:124:51 | ciphertext | Unexpected result: Alert |
| BadMacUse.java:146:95:146:105 | // $ Source | Missing result: Source | | BadMacUse.java:146:95:146:105 | // $ Source | Missing result: Source |

View File

@@ -45,7 +45,7 @@ nodes
| BadMacUse.java:152:42:152:51 | ciphertext | semmle.label | ciphertext | | BadMacUse.java:152:42:152:51 | ciphertext | semmle.label | ciphertext |
subpaths subpaths
testFailures testFailures
| BadMacUse.java:50:56:50:66 | // $ Source | Missing result: Source | | BadMacUse.java:63:82:63:97 | plaintext : byte[] | Fixed missing result: Source |
| BadMacUse.java:139:79:139:90 | input : byte[] | Unexpected result: Source | | BadMacUse.java:139:79:139:90 | input : byte[] | Unexpected result: Source |
| BadMacUse.java:146:95:146:105 | // $ Source | Missing result: Source | | BadMacUse.java:146:95:146:105 | // $ Source | Missing result: Source |
| BadMacUse.java:152:42:152:51 | ciphertext | Unexpected result: Alert | | BadMacUse.java:152:42:152:51 | ciphertext | Unexpected result: Alert |

View File

@@ -47,7 +47,7 @@ class BadMacUse {
SecretKey encryptionKey = new SecretKeySpec(encryptionKeyBytes, "AES"); SecretKey encryptionKey = new SecretKeySpec(encryptionKeyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, encryptionKey, new SecureRandom()); cipher.init(Cipher.DECRYPT_MODE, encryptionKey, new SecureRandom());
byte[] plaintext = cipher.doFinal(ciphertext); // $ Source byte[] plaintext = cipher.doFinal(ciphertext); // $ MISSING: Source
// Now verify MAC (too late) // Now verify MAC (too late)
SecretKey macKey = new SecretKeySpec(macKeyBytes, "HmacSHA256"); SecretKey macKey = new SecretKeySpec(macKeyBytes, "HmacSHA256");
@@ -60,7 +60,7 @@ class BadMacUse {
} }
} }
public void BadMacOnPlaintext(byte[] encryptionKeyBytes, byte[] macKeyBytes, byte[] plaintext) throws Exception {// $ Source public void BadMacOnPlaintext(byte[] encryptionKeyBytes, byte[] macKeyBytes, byte[] plaintext) throws Exception {// $ MISSING: Source
// Create keys directly from provided byte arrays // Create keys directly from provided byte arrays
SecretKey encryptionKey = new SecretKeySpec(encryptionKeyBytes, "AES"); SecretKey encryptionKey = new SecretKeySpec(encryptionKeyBytes, "AES");
SecretKey macKey = new SecretKeySpec(macKeyBytes, "HmacSHA256"); SecretKey macKey = new SecretKeySpec(macKeyBytes, "HmacSHA256");

View File

@@ -126,5 +126,3 @@ nodes
| InsecureIVorNonceSource.java:202:54:202:55 | iv : byte[] | semmle.label | iv : byte[] | | InsecureIVorNonceSource.java:202:54:202:55 | iv : byte[] | semmle.label | iv : byte[] |
| InsecureIVorNonceSource.java:206:51:206:56 | ivSpec | semmle.label | ivSpec | | InsecureIVorNonceSource.java:206:51:206:56 | ivSpec | semmle.label | ivSpec |
subpaths subpaths
testFailures
| InsecureIVorNonceSource.java:42:21:42:21 | 1 : Number | Unexpected result: Source |

View File

@@ -39,7 +39,7 @@ public class InsecureIVorNonceSource {
public byte[] encryptWithStaticIvByteArray(byte[] key, byte[] plaintext) throws Exception { public byte[] encryptWithStaticIvByteArray(byte[] key, byte[] plaintext) throws Exception {
byte[] iv = new byte[16]; byte[] iv = new byte[16];
for (byte i = 0; i < iv.length; i++) { for (byte i = 0; i < iv.length; i++) {
iv[i] = 1; iv[i] = 1; // $ Source
} }
IvParameterSpec ivSpec = new IvParameterSpec(iv); IvParameterSpec ivSpec = new IvParameterSpec(iv);

View File

@@ -40,11 +40,11 @@ public class Test {
* SAST/CBOM: - Parent: PBKDF2. - Iteration count is only 10, which is far * SAST/CBOM: - Parent: PBKDF2. - Iteration count is only 10, which is far
* below acceptable security standards. - Flagged as insecure. * below acceptable security standards. - Flagged as insecure.
*/ */
public void pbkdf2LowIteration(String password, int iterationCount) throws Exception { // $ Source public void pbkdf2LowIteration(String password, int iterationCount) throws Exception { // $ MISSING: Source
byte[] salt = generateSalt(16); byte[] salt = generateSalt(16);
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterationCount, 256); // $ Alert[java/quantum/examples/unknown-kdf-iteration-count] PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterationCount, 256);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] key = factory.generateSecret(spec).getEncoded(); byte[] key = factory.generateSecret(spec).getEncoded(); // $ Alert[java/quantum/examples/unknown-kdf-iteration-count]
} }
/** /**

View File

@@ -1,5 +1 @@
#select
| Test.java:47:22:47:49 | KeyDerivation | Key derivation operation with unknown iteration: $@ | Test.java:43:53:43:70 | iterationCount | iterationCount | | Test.java:47:22:47:49 | KeyDerivation | Key derivation operation with unknown iteration: $@ | Test.java:43:53:43:70 | iterationCount | iterationCount |
testFailures
| Test.java:45:94:45:154 | // $ Alert[java/quantum/examples/unknown-kdf-iteration-count] | Missing result: Alert[java/quantum/examples/unknown-kdf-iteration-count] |
| Test.java:47:22:47:49 | Key derivation operation with unknown iteration: $@ | Unexpected result: Alert |

View File

@@ -12,5 +12,3 @@ nodes
| Test.java:58:30:58:38 | 1_000_000 : Number | semmle.label | 1_000_000 : Number | | Test.java:58:30:58:38 | 1_000_000 : Number | semmle.label | 1_000_000 : Number |
| Test.java:59:72:59:85 | iterationCount | semmle.label | iterationCount | | Test.java:59:72:59:85 | iterationCount | semmle.label | iterationCount |
subpaths subpaths
testFailures
| Test.java:43:92:43:102 | // $ Source | Missing result: Source |

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-all name: codeql/javascript-all
version: 2.8.0 version: 2.8.1-dev
groups: javascript groups: javascript
dbscheme: semmlecode.javascript.dbscheme dbscheme: semmlecode.javascript.dbscheme
extractor: javascript extractor: javascript

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-queries name: codeql/javascript-queries
version: 2.4.0 version: 2.4.1-dev
groups: groups:
- javascript - javascript
- queries - queries

View File

@@ -1,4 +1,4 @@
name: codeql/suite-helpers name: codeql/suite-helpers
version: 1.0.52 version: 1.0.53-dev
groups: shared groups: shared
warnOnImplicitThis: true warnOnImplicitThis: true

View File

@@ -70,7 +70,7 @@ No user-facing changes.
### Minor Analysis Improvements ### Minor Analysis Improvements
* Added new full SSRF sanitization barrier from the new AntiSSRF library. * Added new full SSRF sanitization barrier from the new AntiSSRF library.
* When a guard such as `isSafe(x)` is defined, we now also automatically handle `isSafe(x) == true` and `isSafe(x) != false`. * When a guard such as `isSafe(x)` is defined, we now also automatically handle `isSafe(x) == true` and `isSafe(x) != false`.
## 6.1.1 ## 6.1.1
@@ -169,7 +169,7 @@ No user-facing changes.
### Minor Analysis Improvements ### Minor Analysis Improvements
- The modelling of Psycopg2 now supports the use of `psycopg2.pool` connection pools for handling database connections. - The modelling of Psycopg2 now supports the use of `psycopg2.pool` connection pools for handling database connections.
* Removed `lxml` as an XML bomb sink. The underlying libxml2 library now includes [entity reference loop detection](https://github.com/lxml/lxml/blob/f33ac2c2f5f9c4c4c1fc47f363be96db308f2fa6/doc/FAQ.txt#L1077) that prevents XML bomb attacks. * Removed `lxml` as an XML bomb sink. The underlying libxml2 library now includes [entity reference loop detection](https://github.com/lxml/lxml/blob/f33ac2c2f5f9c4c4c1fc47f363be96db308f2fa6/doc/FAQ.txt#L1077) that prevents XML bomb attacks.
## 4.0.13 ## 4.0.13
@@ -262,7 +262,7 @@ No user-facing changes.
### Minor Analysis Improvements ### Minor Analysis Improvements
* The sensitive data library has been improved so that `snake_case` style variable names are recognized more reliably. This may result in more sensitive data being identified, and more results from queries that use the sensitive data library. * The sensitive data library has been improved so that `snake_case` style variable names are recognized more reliably. This may result in more sensitive data being identified, and more results from queries that use the sensitive data library.
- Additional taint steps through methods of `lxml.etree.Element` and `lxml.etree.ElementTree` objects from the `lxml` PyPI package have been modeled. - Additional taint steps through methods of `lxml.etree.Element` and `lxml.etree.ElementTree` objects from the `lxml` PyPI package have been modeled.
## 3.1.0 ## 3.1.0
@@ -316,7 +316,7 @@ No user-facing changes.
### Minor Analysis Improvements ### Minor Analysis Improvements
* The common sanitizer guard `StringConstCompareBarrier` has been renamed to `ConstCompareBarrier` and expanded to cover comparisons with other constant values such as `None`. This may result in fewer false positive results for several queries. * The common sanitizer guard `StringConstCompareBarrier` has been renamed to `ConstCompareBarrier` and expanded to cover comparisons with other constant values such as `None`. This may result in fewer false positive results for several queries.
## 2.0.0 ## 2.0.0
@@ -545,7 +545,7 @@ No user-facing changes.
### New Features ### New Features
* The `DataFlow::StateConfigSig` signature module has gained default implementations for `isBarrier/2` and `isAdditionalFlowStep/4`. * The `DataFlow::StateConfigSig` signature module has gained default implementations for `isBarrier/2` and `isAdditionalFlowStep/4`.
Hence it is no longer needed to provide `none()` implementations of these predicates if they are not needed. Hence it is no longer needed to provide `none()` implementations of these predicates if they are not needed.
### Minor Analysis Improvements ### Minor Analysis Improvements
@@ -572,7 +572,7 @@ No user-facing changes.
* Deleted many deprecated predicates and classes with uppercase `API`, `HTTP`, `XSS`, `SQL`, etc. in their names. Use the PascalCased versions instead. * Deleted many deprecated predicates and classes with uppercase `API`, `HTTP`, `XSS`, `SQL`, etc. in their names. Use the PascalCased versions instead.
* Deleted the deprecated `getName()` predicate from the `Container` class, use `getAbsolutePath()` instead. * Deleted the deprecated `getName()` predicate from the `Container` class, use `getAbsolutePath()` instead.
* Deleted many deprecated module names that started with a lowercase letter, use the versions that start with an uppercase letter instead. * Deleted many deprecated module names that started with a lowercase letter, use the versions that start with an uppercase letter instead.
* Deleted many deprecated predicates in `PointsTo.qll`. * Deleted many deprecated predicates in `PointsTo.qll`.
* Deleted many deprecated files from the `semmle.python.security` package. * Deleted many deprecated files from the `semmle.python.security` package.
* Deleted the deprecated `BottleRoutePointToExtension` class from `Extensions.qll`. * Deleted the deprecated `BottleRoutePointToExtension` class from `Extensions.qll`.
* Type tracking is now aware of flow summaries. This leads to a richer API graph, and may lead to more results in some queries. * Type tracking is now aware of flow summaries. This leads to a richer API graph, and may lead to more results in some queries.
@@ -729,7 +729,7 @@ No user-facing changes.
### Deprecated APIs ### Deprecated APIs
* Some unused predicates in `SsaDefinitions.qll`, `TObject.qll`, `protocols.qll`, and the `pointsto/` folder have been deprecated. * Some unused predicates in `SsaDefinitions.qll`, `TObject.qll`, `protocols.qll`, and the `pointsto/` folder have been deprecated.
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide. * Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias. The old name still exists as a deprecated alias.
### Minor Analysis Improvements ### Minor Analysis Improvements
@@ -748,9 +748,9 @@ No user-facing changes.
### Deprecated APIs ### Deprecated APIs
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide. * Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias. The old name still exists as a deprecated alias.
* The utility files previously in the `semmle.python.security.performance` package have been moved to the `semmle.python.security.regexp` package. * The utility files previously in the `semmle.python.security.performance` package have been moved to the `semmle.python.security.regexp` package.
The previous files still exist as deprecated aliases. The previous files still exist as deprecated aliases.
### Minor Analysis Improvements ### Minor Analysis Improvements
@@ -843,9 +843,9 @@ No user-facing changes.
### Deprecated APIs ### Deprecated APIs
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide. * Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
The old name still exists as a deprecated alias. The old name still exists as a deprecated alias.
* Some modules that started with a lowercase letter have been renamed to follow our style-guide. * Some modules that started with a lowercase letter have been renamed to follow our style-guide.
The old name still exists as a deprecated alias. The old name still exists as a deprecated alias.
### New Features ### New Features

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* `Flask::FlaskApp::instance()` will now also return instances of subclasses defined in the source tree. Previously, these were filtered out. `Flask::FlaskApp::classRef()` has been deprecated in favor of `Flask::FlaskApp::subclassRef()` since it already returned some subclasses.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Type tracking of values stored in instance attributes and read from outside the class (for example `instance.attr` where the value was assigned to `self.attr` in a method) no longer relies on a dedicated instance type-tracker. This avoids a structural mutual recursion that could cause catastrophic query slowdowns on some OOP-heavy code bases. Such reads are now resolved using local flow from the constructor call, which is slightly less precise for instances that flow across a call or return before being read.

View File

@@ -1,5 +1,5 @@
name: codeql/python-all name: codeql/python-all
version: 7.2.0 version: 7.2.1-dev
groups: python groups: python
dbscheme: semmlecode.python.dbscheme dbscheme: semmlecode.python.dbscheme
extractor: python extractor: python

View File

@@ -1138,9 +1138,7 @@ predicate clearsContent(Node n, ContentSet cs) {
* Holds if the value that is being tracked is expected to be stored inside content `c` * Holds if the value that is being tracked is expected to be stored inside content `c`
* at node `n`. * at node `n`.
*/ */
predicate expectsContent(Node n, ContentSet c) { predicate expectsContent(Node n, ContentSet c) { none() }
FlowSummaryImpl::Private::Steps::summaryExpectsContent(n.(FlowSummaryNode).getSummaryNode(), c)
}
/** /**
* Holds if values stored inside attribute `c` are cleared at node `n`. * Holds if values stored inside attribute `c` are cleared at node `n`.

View File

@@ -91,8 +91,6 @@ module Input implements InputSig<Location, DataFlowImplSpecific::PythonDataFlow>
cs.isAnyTupleOrDictionaryElement() and result = "AnyTupleOrDictionaryElement" and arg = "" cs.isAnyTupleOrDictionaryElement() and result = "AnyTupleOrDictionaryElement" and arg = ""
} }
string encodeWithContent(ContentSet c, string arg) { result = "With" + encodeContent(c, arg) }
bindingset[token] bindingset[token]
ParameterPosition decodeUnknownParameterPosition(AccessPath::AccessPathTokenBase token) { ParameterPosition decodeUnknownParameterPosition(AccessPath::AccessPathTokenBase token) {
// needed to support `Argument[x..y]` ranges // needed to support `Argument[x..y]` ranges

View File

@@ -349,23 +349,11 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
* `instance.attr`, where `instance` is a reference to an instance of `cls`). * `instance.attr`, where `instance` is a reference to an instance of `cls`).
* *
* This complements `selfAttrRef`, which only handles `self.attr` accesses inside the * This complements `selfAttrRef`, which only handles `self.attr` accesses inside the
* methods of `cls`. The instance is identified using *local* flow from a constructor * methods of `cls`. Unlike `selfAttrRef`, this depends on the call graph (via
* call `cls(...)` (resolved via the call graph by `resolveClassCall`), rather than a * `classInstanceTracker`), so steps using it must be reported as `levelStepCall`.
* dedicated instance type-tracker (`classInstanceTracker`).
*
* Using `classInstanceTracker` here would make `levelStepCall` mutually recursive with
* `classInstanceTracker` -- itself a full type-tracker run -- which caused catastrophic
* query slowdowns on some OOP-heavy Python code bases (e.g. `mypy` and `dask`). Relying
* on local flow from a resolved constructor call instead depends only on `classTracker`
* (the same call-graph machinery already used by `inheritedFieldStep`), avoiding that
* blow-up. The trade-off is reduced precision: instances that flow across a call or
* return before being read are no longer covered by this step.
*/ */
private predicate instanceAttrRead(Class cls, string attr, DataFlowPublic::AttrRead read) { private predicate instanceAttrRead(Class cls, string attr, DataFlowPublic::AttrRead read) {
exists(DataFlowPublic::CallCfgNode construction | read.getObject() = DataFlowDispatch::classInstanceTracker(cls) and
DataFlowDispatch::resolveClassCall(construction.asCfgNode(), cls) and
read.getObject().getALocalSource() = construction
) and
read.mayHaveAttributeName(attr) read.mayHaveAttributeName(attr)
} }
@@ -444,9 +432,9 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
* This is the cross-instance counterpart of `localFieldStep`: it relates a write of * This is the cross-instance counterpart of `localFieldStep`: it relates a write of
* `self.attr` inside a class to a read of `attr` on a reference to an instance of that * `self.attr` inside a class to a read of `attr` on a reference to an instance of that
* class or one of its subclasses. Identifying instances relies on the call graph (via * class or one of its subclasses. Identifying instances relies on the call graph (via
* `resolveClassCall`, see `instanceAttrRead`), so this step is reported as * `classInstanceTracker`), so this step is reported as `levelStepCall` rather than
* `levelStepCall` rather than `levelStepNoCall`. The write may occur in the instance's * `levelStepNoCall`. The write may occur in the instance's own class or in any of its
* own class or in any of its superclasses, since those methods are inherited. * superclasses, since those methods are inherited.
* *
* Like `localFieldStep`, this is an over-approximation: it is both instance-insensitive * Like `localFieldStep`, this is an over-approximation: it is both instance-insensitive
* and order-insensitive. * and order-insensitive.

View File

@@ -71,14 +71,21 @@ module Flask {
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask. * See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.
*/ */
module FlaskApp { module FlaskApp {
/** Gets a reference to the `flask.Flask` class. */ /**
API::Node classRef() { * Gets a reference to the `flask.Flask` class or any subclass.
result = API::moduleImport("flask").getMember("Flask") or *
* Deprecated: Use `subclassRef()` instead, this predicate always returned some subclasses.
*/
deprecated API::Node classRef() { result = subclassRef() }
/** Gets a reference to the `flask.Flask` class or any subclass. */
API::Node subclassRef() {
result = API::moduleImport("flask").getMember("Flask").getASubclass*() or
result = ModelOutput::getATypeNode("flask.Flask~Subclass").getASubclass*() result = ModelOutput::getATypeNode("flask.Flask~Subclass").getASubclass*()
} }
/** Gets a reference to an instance of `flask.Flask` (a flask application). */ /** Gets a reference to an instance of `flask.Flask` (a flask application). */
API::Node instance() { result = classRef().getReturn() } API::Node instance() { result = subclassRef().getReturn() }
} }
/** /**
@@ -132,7 +139,7 @@ module Flask {
API::Node classRef() { API::Node classRef() {
result = API::moduleImport("flask").getMember("Response") result = API::moduleImport("flask").getMember("Response")
or or
result = [FlaskApp::classRef(), FlaskApp::instance()].getMember("response_class") result = [FlaskApp::subclassRef(), FlaskApp::instance()].getMember("response_class")
or or
result = ModelOutput::getATypeNode("flask.Response~Subclass").getASubclass*() result = ModelOutput::getATypeNode("flask.Response~Subclass").getASubclass*()
} }

View File

@@ -4199,9 +4199,11 @@ module StdlibPrivate {
// The positional argument contains a mapping. // The positional argument contains a mapping.
// TODO: these values can be overwritten by keyword arguments // TODO: these values can be overwritten by keyword arguments
// - dict mapping // - dict mapping
input = "Argument[0].WithAnyDictionaryElement" and exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
output = "ReturnValue" and input = "Argument[0].DictionaryElement[" + key + "]" and
preservesValue = true output = "ReturnValue.DictionaryElement[" + key + "]" and
preservesValue = true
)
or or
// - list-of-pairs mapping // - list-of-pairs mapping
input = "Argument[0].ListElement.TupleElement[1]" and input = "Argument[0].ListElement.TupleElement[1]" and
@@ -4238,7 +4240,9 @@ module StdlibPrivate {
or or
input = "Argument[0].SetElement" input = "Argument[0].SetElement"
or or
input = "Argument[0].AnyTupleElement" exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and ) and
// Element content is mutated into list element content // Element content is mutated into list element content
@@ -4262,9 +4266,11 @@ module StdlibPrivate {
} }
override predicate propagatesFlow(string input, string output, boolean preservesValue) { override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0].WithAnyTupleElement" and exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
output = "ReturnValue" and input = "Argument[0].TupleElement[" + i.toString() + "]" and
preservesValue = true output = "ReturnValue.TupleElement[" + i.toString() + "]" and
preservesValue = true
)
or or
input = "Argument[0].ListElement" and input = "Argument[0].ListElement" and
output = "ReturnValue" and output = "ReturnValue" and
@@ -4288,7 +4294,9 @@ module StdlibPrivate {
or or
input = "Argument[0].SetElement" input = "Argument[0].SetElement"
or or
input = "Argument[0].AnyTupleElement" exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and ) and
output = "ReturnValue.SetElement" and output = "ReturnValue.SetElement" and
@@ -4334,7 +4342,9 @@ module StdlibPrivate {
or or
input = "Argument[0].SetElement" input = "Argument[0].SetElement"
or or
input = "Argument[0].AnyTupleElement" exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and ) and
output = "ReturnValue.ListElement" and output = "ReturnValue.ListElement" and
@@ -4362,7 +4372,9 @@ module StdlibPrivate {
or or
content = "SetElement" content = "SetElement"
or or
content = "AnyTupleElement" exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
content = "TupleElement[" + i.toString() + "]"
)
| |
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
input = "Argument[0]." + content and input = "Argument[0]." + content and
@@ -4392,7 +4404,9 @@ module StdlibPrivate {
or or
input = "Argument[0].SetElement" input = "Argument[0].SetElement"
or or
input = "Argument[0].AnyTupleElement" exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and ) and
output = "ReturnValue.ListElement" and output = "ReturnValue.ListElement" and
@@ -4420,7 +4434,9 @@ module StdlibPrivate {
or or
input = "Argument[0].SetElement" input = "Argument[0].SetElement"
or or
input = "Argument[0].AnyTupleElement" exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and ) and
output = "ReturnValue" and output = "ReturnValue" and
@@ -4452,7 +4468,9 @@ module StdlibPrivate {
// We reduce generality slightly by not tracking tuple contents on list arguments beyond the first, for performance. // We reduce generality slightly by not tracking tuple contents on list arguments beyond the first, for performance.
// TODO: Once we have TupleElementAny, this generality can be increased. // TODO: Once we have TupleElementAny, this generality can be increased.
i = 0 and i = 0 and
input = "Argument[1].AnyTupleElement" exists(DataFlow::TupleElementContent tc, int j | j = tc.getIndex() |
input = "Argument[1].TupleElement[" + j.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and ) and
output = "Argument[0].Parameter[" + i.toString() + "]" and output = "Argument[0].Parameter[" + i.toString() + "]" and
@@ -4481,7 +4499,9 @@ module StdlibPrivate {
or or
input = "Argument[1].SetElement" input = "Argument[1].SetElement"
or or
input = "Argument[1].AnyTupleElement" exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[1].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and ) and
(output = "Argument[0].Parameter[0]" or output = "ReturnValue.ListElement") and (output = "Argument[0].Parameter[0]" or output = "ReturnValue.ListElement") and
@@ -4505,7 +4525,9 @@ module StdlibPrivate {
or or
input = "Argument[0].SetElement" input = "Argument[0].SetElement"
or or
input = "Argument[0].AnyTupleElement" exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and ) and
output = "ReturnValue.ListElement.TupleElement[1]" and output = "ReturnValue.ListElement.TupleElement[1]" and
@@ -4530,7 +4552,12 @@ module StdlibPrivate {
or or
input = "Argument[" + i.toString() + "].SetElement" input = "Argument[" + i.toString() + "].SetElement"
or or
input = "Argument[" + i.toString() + "].AnyTupleElement" // We reduce generality slightly by not tracking tuple contents on arguments beyond the first two, for performance.
// TODO: Once we have TupleElementAny, this generality can be increased.
i in [0 .. 1] and
exists(DataFlow::TupleElementContent tc, int j | j = tc.getIndex() |
input = "Argument[" + i.toString() + "].TupleElement[" + j.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and ) and
output = "ReturnValue.ListElement.TupleElement[" + i.toString() + "]" and output = "ReturnValue.ListElement.TupleElement[" + i.toString() + "]" and
@@ -4553,6 +4580,12 @@ module StdlibPrivate {
override DataFlow::ArgumentNode getACallback() { none() } override DataFlow::ArgumentNode getACallback() { none() }
override predicate propagatesFlow(string input, string output, boolean preservesValue) { override predicate propagatesFlow(string input, string output, boolean preservesValue) {
exists(DataFlow::Content c |
input = "Argument[self]." + c.getMaDRepresentation() and
output = "ReturnValue." + c.getMaDRepresentation() and
preservesValue = true
)
or
input = "Argument[self]" and input = "Argument[self]" and
output = "ReturnValue" and output = "ReturnValue" and
preservesValue = true preservesValue = true
@@ -4708,10 +4741,12 @@ module StdlibPrivate {
override DataFlow::ArgumentNode getACallback() { none() } override DataFlow::ArgumentNode getACallback() { none() }
override predicate propagatesFlow(string input, string output, boolean preservesValue) { override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].AnyDictionaryElement" and exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
output = "ReturnValue.TupleElement[1]" and input = "Argument[self].DictionaryElement[" + key + "]" and
preservesValue = true output = "ReturnValue.TupleElement[1]" and
// TODO: put `key` into "ReturnValue.TupleElement[0]" preservesValue = true
// TODO: put `key` into "ReturnValue.TupleElement[0]"
)
} }
} }
@@ -4790,9 +4825,11 @@ module StdlibPrivate {
} }
override predicate propagatesFlow(string input, string output, boolean preservesValue) { override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].AnyDictionaryElement" and exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
output = "ReturnValue.ListElement" and input = "Argument[self].DictionaryElement[" + key + "]" and
preservesValue = true output = "ReturnValue.ListElement" and
preservesValue = true
)
or or
input = "Argument[self]" and input = "Argument[self]" and
output = "ReturnValue" and output = "ReturnValue" and
@@ -4839,9 +4876,11 @@ module StdlibPrivate {
} }
override predicate propagatesFlow(string input, string output, boolean preservesValue) { override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].AnyDictionaryElement" and exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
output = "ReturnValue.ListElement.TupleElement[1]" and input = "Argument[self].DictionaryElement[" + key + "]" and
preservesValue = true output = "ReturnValue.ListElement.TupleElement[1]" and
preservesValue = true
)
or or
// TODO: Add the keys to output list // TODO: Add the keys to output list
input = "Argument[self]" and input = "Argument[self]" and

View File

@@ -351,7 +351,7 @@ class DjangoHttpRequest extends FindSubclassesSpec {
class FlaskClass extends FindSubclassesSpec { class FlaskClass extends FindSubclassesSpec {
FlaskClass() { this = "flask.Flask~Subclass" } FlaskClass() { this = "flask.Flask~Subclass" }
override API::Node getAlreadyModeledClass() { result = Flask::FlaskApp::classRef() } override API::Node getAlreadyModeledClass() { result = Flask::FlaskApp::subclassRef() }
} }
class FlaskBlueprint extends FindSubclassesSpec { class FlaskBlueprint extends FindSubclassesSpec {

View File

@@ -1,5 +1,5 @@
name: codeql/python-queries name: codeql/python-queries
version: 1.8.5 version: 1.8.6-dev
groups: groups:
- python - python
- queries - queries

View File

@@ -0,0 +1,29 @@
/**
* Defines an InlineExpectationsTest for class instances, that is,
* for any API::Node that is an instance of a class (e.g. `Flask`).
*/
import python
import semmle.python.ApiGraphs
import utils.test.InlineExpectationsTest
private import semmle.python.dataflow.new.internal.PrintNode
signature API::Node getInstanceSig();
module MakeInlineInstanceTest<getInstanceSig/0 getInstance> {
private module InlineInstanceTest implements TestSig {
string getARelevantTag() { result = "instance" }
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(location.getFile().getRelativePath()) and
exists(API::Node instance | instance = getInstance() |
location = instance.getLocation() and
element = prettyNode(instance.asSource()) and
value = "" and
tag = "instance"
)
}
}
import MakeTest<InlineInstanceTest>
}

View File

@@ -3,5 +3,5 @@ argumentToEnsureNotTaintedNotMarkedAsSpurious
untaintedArgumentToEnsureTaintedNotMarkedAsMissing untaintedArgumentToEnsureTaintedNotMarkedAsMissing
| taint_test.py:32:9:32:25 | taint_test.py:32 | ERROR, you should add `# $ MISSING: tainted` annotation | should_be_tainted | | taint_test.py:32:9:32:25 | taint_test.py:32 | ERROR, you should add `# $ MISSING: tainted` annotation | should_be_tainted |
| taint_test.py:37:24:37:40 | taint_test.py:37 | ERROR, you should add `# $ MISSING: tainted` annotation | should_be_tainted | | taint_test.py:37:24:37:40 | taint_test.py:37 | ERROR, you should add `# $ MISSING: tainted` annotation | should_be_tainted |
| taint_test.py:41:24:41:40 | taint_test.py:41 | ERROR, you should add `# $ MISSING: tainted` annotation | should_be_tainted |
testFailures testFailures
| taint_test.py:41:20:41:21 | ts | Fixed missing result: tainted |

View File

@@ -38,7 +38,7 @@ def bad_usage():
# if you try to get around it by adding BOTH annotations, that results in a problem # if you try to get around it by adding BOTH annotations, that results in a problem
# from the default set of inline-test-expectation rules # from the default set of inline-test-expectation rules
ensure_tainted(ts, should_be_tainted) # $ tainted MISSING: tainted ensure_tainted(ts, should_be_tainted) # $ tainted
# simulating handling something we _want_ to treat at untainted, but we currently treat as tainted # simulating handling something we _want_ to treat at untainted, but we currently treat as tainted
should_not_be_tainted = "pretend this is now safe" + ts should_not_be_tainted = "pretend this is now safe" + ts

View File

@@ -589,11 +589,11 @@ def test_zip_tuple():
SINK(z[0][0]) # $ flow="SOURCE, l:-7 -> z[0][0]" SINK(z[0][0]) # $ flow="SOURCE, l:-7 -> z[0][0]"
SINK(z[0][1]) # $ flow="SOURCE, l:-7 -> z[0][1]" SINK(z[0][1]) # $ flow="SOURCE, l:-7 -> z[0][1]"
SINK_F(z[0][2]) # $ SPURIOUS: flow="SOURCE, l:-7 -> z[0][2]" SINK_F(z[0][2])
SINK_F(z[0][3]) SINK_F(z[0][3])
SINK(z[1][0]) # $ flow="SOURCE, l:-11 -> z[1][0]" SINK(z[1][0]) # $ flow="SOURCE, l:-11 -> z[1][0]"
SINK_F(z[1][1]) # $ SPURIOUS: flow="SOURCE, l:-11 -> z[1][1]" SINK_F(z[1][1]) # $ SPURIOUS: flow="SOURCE, l:-11 -> z[1][1]"
SINK(z[1][2]) # $ flow="SOURCE, l:-11 -> z[1][2]" SINK(z[1][2]) # $ MISSING: flow="SOURCE, l:-11 -> z[1][2]" # Tuple contents are not tracked beyond the first two arguments for performance.
SINK_F(z[1][3]) SINK_F(z[1][3])
@expects(4) @expects(4)

View File

@@ -161,18 +161,6 @@ print(instance.foo) # $ tracked MISSING: tracked=foo
instance.print_foo() # $ MISSING: tracked=foo instance.print_foo() # $ MISSING: tracked=foo
# attribute set in method, but the instance flows across a call/return before the read.
# `instanceFieldStep` identifies the instance using only local flow from the constructor
# call, so a value stored on `self.foo` is not seen once the instance has crossed a
# function boundary.
def make_my_class2():
return MyClass2()
returned_instance = make_my_class2()
print(returned_instance.foo) # $ MISSING: tracked
# attribute set from outside of class # attribute set from outside of class
class MyClass3(object): class MyClass3(object):

View File

@@ -362,7 +362,7 @@ def test_load_in_bulk():
# see https://docs.djangoproject.com/en/4.0/ref/models/querysets/#in-bulk # see https://docs.djangoproject.com/en/4.0/ref/models/querysets/#in-bulk
d = TestLoad.objects.in_bulk([1]) d = TestLoad.objects.in_bulk([1])
for val in d.values(): for val in d.values():
SINK(val.text) # $ flow="SOURCE, l:-65 -> val.text" SINK(val.text) # $ MISSING: flow
SINK(d[1].text) # $ flow="SOURCE, l:-66 -> d[1].text" SINK(d[1].text) # $ flow="SOURCE, l:-66 -> d[1].text"

View File

@@ -0,0 +1,8 @@
import python
import semmle.python.frameworks.Flask
import semmle.python.ApiGraphs
import experimental.meta.InlineInstanceTest
API::Node getInstance() { result = Flask::FlaskApp::instance() }
import MakeInlineInstanceTest<getInstance/0>

View File

@@ -0,0 +1,14 @@
from flask import Flask
class Sub(Flask):
def __init__(self, *args, **kwargs):
Flask.__init__(self, *args, **kwargs)
app = Sub(__name__) # $ instance
@app.route("/") # $ routeSetup="/"
def hello(): # $ requestHandler
return "world" # $ HttpResponse

View File

@@ -1,7 +1,7 @@
import flask import flask
from flask import Flask, request, make_response from flask import Flask, request, make_response
app = Flask(__name__) app = Flask(__name__) # $ instance
@app.route("/") # $ routeSetup="/" @app.route("/") # $ routeSetup="/"
def hello_world(): # $ requestHandler def hello_world(): # $ requestHandler

View File

@@ -3,7 +3,7 @@ import json
from flask import Flask, make_response, jsonify, Response, request, redirect from flask import Flask, make_response, jsonify, Response, request, redirect
from werkzeug.datastructures import Headers from werkzeug.datastructures import Headers
app = Flask(__name__) app = Flask(__name__) # $ instance
@app.route("/html1") # $ routeSetup="/html1" @app.route("/html1") # $ routeSetup="/html1"

View File

@@ -1,7 +1,7 @@
import flask import flask
from flask import Flask, make_response from flask import Flask, make_response
app = Flask(__name__) app = Flask(__name__) # $ instance
SOME_ROUTE = "/some/route" SOME_ROUTE = "/some/route"

View File

@@ -1,5 +1,5 @@
from flask import Flask, request from flask import Flask, request
app = Flask(__name__) app = Flask(__name__) # $ instance
@app.route("/save-uploaded-file") # $ routeSetup="/save-uploaded-file" @app.route("/save-uploaded-file") # $ routeSetup="/save-uploaded-file"
def test_taint(): # $ requestHandler def test_taint(): # $ requestHandler

View File

@@ -1,5 +1,5 @@
from flask import Flask, request, render_template_string, stream_template_string from flask import Flask, request, render_template_string, stream_template_string
app = Flask(__name__) app = Flask(__name__) # $ instance
@app.route("/test_taint/<name>/<int:number>") # $ routeSetup="/test_taint/<name>/<int:number>" @app.route("/test_taint/<name>/<int:number>") # $ routeSetup="/test_taint/<name>/<int:number>"
def test_taint(name = "World!", number="0", foo="foo"): # $ requestHandler routedParameter=name routedParameter=number def test_taint(name = "World!", number="0", foo="foo"): # $ requestHandler routedParameter=name routedParameter=number

View File

@@ -1,5 +1,5 @@
from flask import Flask, Response, stream_with_context, render_template_string, stream_template_string from flask import Flask, Response, stream_with_context, render_template_string, stream_template_string
app = Flask(__name__) app = Flask(__name__) # $ instance
@app.route("/a") # $ routeSetup="/a" @app.route("/a") # $ routeSetup="/a"
def a(): # $ requestHandler def a(): # $ requestHandler

View File

@@ -1,5 +1,5 @@
name: codeql/ruby-all name: codeql/ruby-all
version: 6.0.0 version: 6.0.1-dev
groups: ruby groups: ruby
extractor: ruby extractor: ruby
dbscheme: ruby.dbscheme dbscheme: ruby.dbscheme

View File

@@ -1,5 +1,5 @@
name: codeql/ruby-queries name: codeql/ruby-queries
version: 1.6.5 version: 1.6.6-dev
groups: groups:
- ruby - ruby
- queries - queries

View File

@@ -28,7 +28,6 @@ nodes
| string_flow.rb:227:10:227:10 | a | semmle.label | a | | string_flow.rb:227:10:227:10 | a | semmle.label | a |
subpaths subpaths
testFailures testFailures
| string_flow.rb:85:10:85:10 | a | Unexpected result: hasValueFlow=a |
| string_flow.rb:227:10:227:10 | a | Unexpected result: hasValueFlow=a | | string_flow.rb:227:10:227:10 | a | Unexpected result: hasValueFlow=a |
#select #select
| string_flow.rb:3:10:3:22 | call to new | string_flow.rb:2:9:2:18 | call to source | string_flow.rb:3:10:3:22 | call to new | $@ | string_flow.rb:2:9:2:18 | call to source | call to source | | string_flow.rb:3:10:3:22 | call to new | string_flow.rb:2:9:2:18 | call to source | string_flow.rb:3:10:3:22 | call to new | $@ | string_flow.rb:2:9:2:18 | call to source | call to source |

View File

@@ -82,7 +82,7 @@ end
def m_clear def m_clear
a = source "a" a = source "a"
a.clear a.clear
sink a sink a # $ hasValueFlow=a
end end
# concat and prepend omitted because they clash with the summaries for # concat and prepend omitted because they clash with the summaries for

View File

@@ -18,7 +18,7 @@ class OneController < ActionController::Base
end end
def c def c
sink @foo sink @foo # $ hasTaintFlow
end end
end end

View File

@@ -270,7 +270,6 @@ nodes
| params_flow.rb:205:10:205:10 | a | semmle.label | a | | params_flow.rb:205:10:205:10 | a | semmle.label | a |
subpaths subpaths
testFailures testFailures
| filter_flow.rb:21:10:21:13 | @foo | Unexpected result: hasTaintFlow |
| filter_flow.rb:38:10:38:13 | @foo | Unexpected result: hasTaintFlow | | filter_flow.rb:38:10:38:13 | @foo | Unexpected result: hasTaintFlow |
| filter_flow.rb:55:10:55:13 | @foo | Unexpected result: hasTaintFlow | | filter_flow.rb:55:10:55:13 | @foo | Unexpected result: hasTaintFlow |
| filter_flow.rb:71:10:71:17 | call to bar | Unexpected result: hasTaintFlow | | filter_flow.rb:71:10:71:17 | call to bar | Unexpected result: hasTaintFlow |

View File

@@ -497,7 +497,6 @@ nodes
| hash_extensions.rb:126:10:126:19 | call to sole | semmle.label | call to sole | | hash_extensions.rb:126:10:126:19 | call to sole | semmle.label | call to sole |
subpaths subpaths
testFailures testFailures
| hash_extensions.rb:126:10:126:19 | call to sole | Unexpected result: hasValueFlow=b |
#select #select
| active_support.rb:182:10:182:13 | ...[...] | active_support.rb:180:10:180:17 | call to source | active_support.rb:182:10:182:13 | ...[...] | $@ | active_support.rb:180:10:180:17 | call to source | call to source | | active_support.rb:182:10:182:13 | ...[...] | active_support.rb:180:10:180:17 | call to source | active_support.rb:182:10:182:13 | ...[...] | $@ | active_support.rb:180:10:180:17 | call to source | call to source |
| active_support.rb:188:10:188:13 | ...[...] | active_support.rb:186:10:186:18 | call to source | active_support.rb:188:10:188:13 | ...[...] | $@ | active_support.rb:186:10:186:18 | call to source | call to source | | active_support.rb:188:10:188:13 | ...[...] | active_support.rb:186:10:186:18 | call to source | active_support.rb:188:10:188:13 | ...[...] | $@ | active_support.rb:186:10:186:18 | call to source | call to source |

View File

@@ -123,7 +123,7 @@ def m_sole
multi = [source("b"), source("c")] multi = [source("b"), source("c")]
sink(empty.sole) sink(empty.sole)
sink(single.sole) # $ hasValueFlow=a sink(single.sole) # $ hasValueFlow=a
sink(multi.sole) # TODO: model that 'sole' does not return if the receiver has multiple elements sink(multi.sole) # $ hasValueFlow=b # TODO: model that 'sole' does not return if the receiver has multiple elements
end end
m_sole() m_sole()

View File

@@ -23,7 +23,6 @@ nodes
| views/index.erb:2:10:2:12 | call to foo | semmle.label | call to foo | | views/index.erb:2:10:2:12 | call to foo | semmle.label | call to foo |
subpaths subpaths
testFailures testFailures
| views/index.erb:2:10:2:12 | call to foo | Unexpected result: hasTaintFlow |
#select #select
| app.rb:95:10:95:14 | @user | app.rb:103:13:103:22 | call to source | app.rb:95:10:95:14 | @user | $@ | app.rb:103:13:103:22 | call to source | call to source | | app.rb:95:10:95:14 | @user | app.rb:103:13:103:22 | call to source | app.rb:95:10:95:14 | @user | $@ | app.rb:103:13:103:22 | call to source | call to source |
| views/index.erb:2:10:2:12 | call to foo | app.rb:75:12:75:17 | call to params | views/index.erb:2:10:2:12 | call to foo | $@ | app.rb:75:12:75:17 | call to params | call to params | | views/index.erb:2:10:2:12 | call to foo | app.rb:75:12:75:17 | call to params | views/index.erb:2:10:2:12 | call to foo | $@ | app.rb:75:12:75:17 | call to params | call to params |

View File

@@ -1,2 +1,2 @@
<%= @foo %> <%= @foo %>
<%= sink foo %> <%= sink foo # $ hasTaintFlow %>

View File

@@ -1,5 +1,4 @@
testFailures testFailures
| improper_memoization.rb:100:1:104:3 | m14 | Unexpected result: result=BAD |
#select #select
| improper_memoization.rb:50:1:55:3 | m7 | improper_memoization.rb:50:8:50:10 | arg | improper_memoization.rb:51:3:53:5 | ... \|\|= ... | | improper_memoization.rb:50:1:55:3 | m7 | improper_memoization.rb:50:8:50:10 | arg | improper_memoization.rb:51:3:53:5 | ... \|\|= ... |
| improper_memoization.rb:58:1:63:3 | m8 | improper_memoization.rb:58:8:58:10 | arg | improper_memoization.rb:59:3:61:5 | ... \|\|= ... | | improper_memoization.rb:58:1:63:3 | m8 | improper_memoization.rb:58:8:58:10 | arg | improper_memoization.rb:59:3:61:5 | ... \|\|= ... |

View File

@@ -101,4 +101,4 @@ def m14(arg)
@m14 ||= {} @m14 ||= {}
key = "foo/#{arg}" key = "foo/#{arg}"
@m14[key] ||= long_running_method(arg) @m14[key] ||= long_running_method(arg)
end end # $ SPURIOUS: result=BAD

View File

@@ -1,5 +1,5 @@
name: codeql/rust-all name: codeql/rust-all
version: 0.2.16 version: 0.2.17-dev
groups: rust groups: rust
extractor: rust extractor: rust
dbscheme: rust.dbscheme dbscheme: rust.dbscheme

View File

@@ -1,5 +1,5 @@
name: codeql/rust-queries name: codeql/rust-queries
version: 0.1.37 version: 0.1.38-dev
groups: groups:
- rust - rust
- queries - queries

View File

@@ -1,5 +1,5 @@
name: codeql/concepts name: codeql/concepts
version: 0.0.26 version: 0.0.27-dev
groups: shared groups: shared
library: true library: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/controlflow name: codeql/controlflow
version: 2.0.36 version: 2.0.37-dev
groups: shared groups: shared
library: true library: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/dataflow name: codeql/dataflow
version: 2.1.8 version: 2.1.9-dev
groups: shared groups: shared
library: true library: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/mad name: codeql/mad
version: 1.0.52 version: 1.0.53-dev
groups: shared groups: shared
library: true library: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/namebinding name: codeql/namebinding
version: 0.0.1 version: 0.0.2-dev
groups: shared groups: shared
library: true library: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/quantum name: codeql/quantum
version: 0.0.30 version: 0.0.31-dev
groups: shared groups: shared
library: true library: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/rangeanalysis name: codeql/rangeanalysis
version: 1.0.52 version: 1.0.53-dev
groups: shared groups: shared
library: true library: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/regex name: codeql/regex
version: 1.0.52 version: 1.0.53-dev
groups: shared groups: shared
library: true library: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/ssa name: codeql/ssa
version: 2.0.28 version: 2.0.29-dev
groups: shared groups: shared
library: true library: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/threat-models name: codeql/threat-models
version: 1.0.52 version: 1.0.53-dev
library: true library: true
groups: shared groups: shared
dataExtensions: dataExtensions:

View File

@@ -1,7 +1,7 @@
name: codeql/tutorial name: codeql/tutorial
description: Library for the CodeQL detective tutorials, helping new users learn to description: Library for the CodeQL detective tutorials, helping new users learn to
write CodeQL queries. write CodeQL queries.
version: 1.0.52 version: 1.0.53-dev
groups: shared groups: shared
library: true library: true
warnOnImplicitThis: true warnOnImplicitThis: true

View File

@@ -1,5 +1,5 @@
name: codeql/typeflow name: codeql/typeflow
version: 1.0.52 version: 1.0.53-dev
groups: shared groups: shared
library: true library: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/typeinference name: codeql/typeinference
version: 0.0.33 version: 0.0.34-dev
groups: shared groups: shared
library: true library: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/typetracking name: codeql/typetracking
version: 2.0.36 version: 2.0.37-dev
groups: shared groups: shared
library: true library: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/typos name: codeql/typos
version: 1.0.52 version: 1.0.53-dev
groups: shared groups: shared
library: true library: true
warnOnImplicitThis: true warnOnImplicitThis: true

View File

@@ -1,5 +1,5 @@
name: codeql/util name: codeql/util
version: 2.0.39 version: 2.0.40-dev
groups: shared groups: shared
library: true library: true
dependencies: null dependencies: null

View File

@@ -1,5 +1,5 @@
name: codeql/xml name: codeql/xml
version: 1.0.52 version: 1.0.53-dev
groups: shared groups: shared
library: true library: true
dependencies: dependencies:

View File

@@ -1,5 +1,5 @@
name: codeql/yaml name: codeql/yaml
version: 1.0.52 version: 1.0.53-dev
groups: shared groups: shared
library: true library: true
warnOnImplicitThis: true warnOnImplicitThis: true

View File

@@ -1,5 +1,5 @@
name: codeql/swift-all name: codeql/swift-all
version: 6.7.1 version: 6.7.2-dev
groups: swift groups: swift
extractor: swift extractor: swift
dbscheme: swift.dbscheme dbscheme: swift.dbscheme

View File

@@ -1,5 +1,5 @@
name: codeql/swift-queries name: codeql/swift-queries
version: 1.3.5 version: 1.3.6-dev
groups: groups:
- swift - swift
- queries - queries