diff --git a/javascript/ql/lib/change-notes/2025-07-28-dynamodb.md b/javascript/ql/lib/change-notes/2025-07-28-dynamodb.md new file mode 100644 index 000000000000..bbf5d57163ae --- /dev/null +++ b/javascript/ql/lib/change-notes/2025-07-28-dynamodb.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added support for the `aws-sdk` and `@aws-sdk/client-dynamodb`, `@aws-sdk/client-athena`, `@aws-sdk/client-s3`, and `@aws-sdk/client-rds-data` packages. diff --git a/javascript/ql/lib/ext/aws-sdk.model.yml b/javascript/ql/lib/ext/aws-sdk.model.yml index eefa87fbe613..d850fec7371c 100644 --- a/javascript/ql/lib/ext/aws-sdk.model.yml +++ b/javascript/ql/lib/ext/aws-sdk.model.yml @@ -3,6 +3,49 @@ extensions: pack: codeql/javascript-all extensible: sinkModel data: - - ["aws-sdk", "AnyMember.Argument[0].Member[secretAccessKey,accessKeyId]", "credentials-key"] - - ["aws-sdk", "AnyMember.Member[secretAccessKey,accessKeyId]", "credentials-key"] - - ["aws-sdk", "Member[Credentials].Argument[0,1]", "credentials-key"] + - ["aws-sdk", "AnyMember.Argument[0].Member[secretAccessKey,accessKeyId]", "credentials-key"] + - ["aws-sdk", "AnyMember.Member[secretAccessKey,accessKeyId]", "credentials-key"] + - ["aws-sdk", "Member[Credentials].Argument[0,1]", "credentials-key"] + - ["AWS-V3-Common", "ReturnValue.Member[send].Argument[0]", "sql-injection"] + - ["AthenaClientV2", "ReturnValue.Member[startQueryExecution,createNamedQuery,updateNamedQuery].Argument[0].Member[QueryString]", "sql-injection"] + - ["S3ClientV2", "ReturnValue.Member[selectObjectContent].Argument[0].Member[Expression]", "sql-injection"] + - ["RDSDataClientV2", "ReturnValue.Member[executeStatement,batchExecuteStatement].Argument[0].Member[sql]", "sql-injection"] + - ["RDSDataClientV2", "ReturnValue.Member[batchExecuteStatement].Argument[0].Member[parameterSets].ArrayElement.Member[sql]", "sql-injection"] + - ["DynamoDBClientV2", "ReturnValue.Member[executeStatement].Argument[0].Member[Statement]", "sql-injection"] + - ["DynamoDBClientV2", "ReturnValue.Member[batchExecuteStatement].Argument[0].Member[Statements].ArrayElement.Member[Statement]", "sql-injection"] + - addsTo: + pack: codeql/javascript-all + extensible: summaryModel + data: + - ["@aws-sdk/client-athena", "Member[StartQueryExecutionCommand,CreateNamedQueryCommand,UpdateNamedQueryCommand]", "Argument[0].Member[QueryString]", "ReturnValue", "taint"] + - ["@aws-sdk/client-s3", "Member[SelectObjectContentCommand]", "Argument[0].Member[Expression]", "ReturnValue", "taint"] + - ["@aws-sdk/client-rds-data", "Member[ExecuteStatementCommand,BatchExecuteStatementCommand]", "Argument[0].Member[sql]", "ReturnValue", "taint"] + - ["@aws-sdk/client-rds-data", "Member[BatchExecuteStatementCommand]", "Argument[0].Member[parameterSets].ArrayElement.Member[sql]", "ReturnValue", "taint"] + - ["@aws-sdk/client-rds-data", "Member[ExecuteSqlCommand]", "Argument[0].Member[sqlStatements]", "ReturnValue", "taint"] + - ["@aws-sdk/client-dynamodb", "Member[ExecuteStatementCommand]", "Argument[0].Member[Statement]", "ReturnValue", "taint"] + - ["@aws-sdk/client-dynamodb", "Member[BatchExecuteStatementCommand]", "Argument[0].Member[Statements].ArrayElement.Member[Statement]", "ReturnValue", "taint"] + - addsTo: + pack: codeql/javascript-all + extensible: typeModel + data: + - ["AthenaClientV2", "aws-sdk", "Member[Athena]"] + - ["S3ClientV2", "aws-sdk", "Member[S3]"] + - ["RDSDataClientV2", "aws-sdk", "Member[RDSDataService]"] + - ["DynamoDBClientV2", "aws-sdk", "Member[DynamoDB]"] + - ["AWS-V3-Common", "@aws-sdk/client-athena", "Member[AthenaClient]"] + - ["AWS-V3-Common", "@aws-sdk/client-s3", "Member[S3Client]"] + - ["AWS-V3-Common", "@aws-sdk/client-dynamodb", "Member[DynamoDBClient,DynamoDB]"] + - ["AWS-V3-Common", "@aws-sdk/client-rds-data", "Member[RDSDataClient]"] + - addsTo: + pack: codeql/javascript-all + extensible: sourceModel + data: + - ["AWS-V3-Common", "ReturnValue.Member[send].ReturnValue.Awaited", "database-access-result"] + - ["AthenaClientV2", "ReturnValue.Member[getQueryResults].ReturnValue.Member[promise].ReturnValue.Awaited", "database-access-result"] + - ["AthenaClientV2", "ReturnValue.Member[getQueryResults].Argument[1].Parameter[1]", "database-access-result"] + - ["S3ClientV2", "ReturnValue.Member[getObject].ReturnValue.Member[promise].ReturnValue.Awaited", "database-access-result"] + - ["S3ClientV2", "ReturnValue.Member[getObject].Argument[1].Parameter[1]", "database-access-result"] + - ["RDSDataClientV2", "ReturnValue.Member[executeStatement,batchExecuteStatement].ReturnValue.Member[promise].ReturnValue.Awaited", "database-access-result"] + - ["RDSDataClientV2", "ReturnValue.Member[executeStatement,batchExecuteStatement].Argument[1].Parameter[1]", "database-access-result"] + - ["DynamoDBClientV2", "ReturnValue.Member[executeStatement,batchExecuteStatement,query,scan,getItem,batchGetItem].ReturnValue.Member[promise].ReturnValue.Awaited", "database-access-result"] + - ["DynamoDBClientV2", "ReturnValue.Member[executeStatement,batchExecuteStatement,query,scan,getItem,batchGetItem].Argument[1].Parameter[1]", "database-access-result"] diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected index c031b7c1810c..295a830754ce 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected @@ -32,6 +32,34 @@ nodes | angular-tempate-url.js:13:30:13:31 | ev | semmle.label | ev | | angular-tempate-url.js:14:26:14:27 | ev | semmle.label | ev | | angular-tempate-url.js:14:26:14:32 | ev.data | semmle.label | ev.data | +| aws-db.js:15:31:15:37 | results | semmle.label | results | +| aws-db.js:15:31:15:76 | results ... arValue | semmle.label | results ... arValue | +| aws-db.js:20:31:20:38 | response | semmle.label | response | +| aws-db.js:20:31:20:54 | respons ... tring() | semmle.label | respons ... tring() | +| aws-db.js:24:31:24:39 | response2 | semmle.label | response2 | +| aws-db.js:24:31:24:47 | response2.records | semmle.label | response2.records | +| aws-db.js:28:31:28:39 | response3 | semmle.label | response3 | +| aws-db.js:28:31:28:44 | response3.Item | semmle.label | response3.Item | +| aws-db.js:43:31:43:37 | results | semmle.label | results | +| aws-db.js:43:31:43:76 | results ... arValue | semmle.label | results ... arValue | +| aws-db.js:46:35:46:38 | data | semmle.label | data | +| aws-db.js:46:35:46:77 | data.Re ... arValue | semmle.label | data.Re ... arValue | +| aws-db.js:51:31:51:38 | response | semmle.label | response | +| aws-db.js:51:31:51:54 | respons ... tring() | semmle.label | respons ... tring() | +| aws-db.js:54:35:54:38 | data | semmle.label | data | +| aws-db.js:54:35:54:54 | data.Body.toString() | semmle.label | data.Body.toString() | +| aws-db.js:59:31:59:39 | response1 | semmle.label | response1 | +| aws-db.js:59:31:59:47 | response1.records | semmle.label | response1.records | +| aws-db.js:62:35:62:38 | data | semmle.label | data | +| aws-db.js:62:35:62:46 | data.records | semmle.label | data.records | +| aws-db.js:66:31:66:39 | response2 | semmle.label | response2 | +| aws-db.js:66:31:66:53 | respons ... Results | semmle.label | respons ... Results | +| aws-db.js:69:35:69:38 | data | semmle.label | data | +| aws-db.js:69:35:69:52 | data.updateResults | semmle.label | data.updateResults | +| aws-db.js:74:35:74:38 | data | semmle.label | data | +| aws-db.js:74:35:74:43 | data.Item | semmle.label | data.Item | +| aws-db.js:77:35:77:38 | data | semmle.label | data | +| aws-db.js:77:35:77:43 | data.Item | semmle.label | data.Item | | classnames.js:7:31:7:84 | `` | semmle.label | `` | | classnames.js:7:47:7:69 | classNa ... w.name) | semmle.label | classNa ... w.name) | | classnames.js:7:58:7:68 | window.name | semmle.label | window.name | @@ -724,6 +752,20 @@ edges | angular-tempate-url.js:13:30:13:31 | ev | angular-tempate-url.js:14:26:14:27 | ev | provenance | | | angular-tempate-url.js:14:26:14:27 | ev | angular-tempate-url.js:14:26:14:32 | ev.data | provenance | | | angular-tempate-url.js:14:26:14:32 | ev.data | angular-tempate-url.js:9:26:9:45 | Cookie.get("unsafe") | provenance | | +| aws-db.js:15:31:15:37 | results | aws-db.js:15:31:15:76 | results ... arValue | provenance | | +| aws-db.js:20:31:20:38 | response | aws-db.js:20:31:20:54 | respons ... tring() | provenance | | +| aws-db.js:24:31:24:39 | response2 | aws-db.js:24:31:24:47 | response2.records | provenance | | +| aws-db.js:28:31:28:39 | response3 | aws-db.js:28:31:28:44 | response3.Item | provenance | | +| aws-db.js:43:31:43:37 | results | aws-db.js:43:31:43:76 | results ... arValue | provenance | | +| aws-db.js:46:35:46:38 | data | aws-db.js:46:35:46:77 | data.Re ... arValue | provenance | | +| aws-db.js:51:31:51:38 | response | aws-db.js:51:31:51:54 | respons ... tring() | provenance | | +| aws-db.js:54:35:54:38 | data | aws-db.js:54:35:54:54 | data.Body.toString() | provenance | | +| aws-db.js:59:31:59:39 | response1 | aws-db.js:59:31:59:47 | response1.records | provenance | | +| aws-db.js:62:35:62:38 | data | aws-db.js:62:35:62:46 | data.records | provenance | | +| aws-db.js:66:31:66:39 | response2 | aws-db.js:66:31:66:53 | respons ... Results | provenance | | +| aws-db.js:69:35:69:38 | data | aws-db.js:69:35:69:52 | data.updateResults | provenance | | +| aws-db.js:74:35:74:38 | data | aws-db.js:74:35:74:43 | data.Item | provenance | | +| aws-db.js:77:35:77:38 | data | aws-db.js:77:35:77:43 | data.Item | provenance | | | classnames.js:7:47:7:69 | classNa ... w.name) | classnames.js:7:31:7:84 | `` | provenance | | | classnames.js:7:58:7:68 | window.name | classnames.js:7:47:7:69 | classNa ... w.name) | provenance | | | classnames.js:8:47:8:70 | classNa ... w.name) | classnames.js:8:31:8:85 | `` | provenance | | @@ -1319,6 +1361,20 @@ subpaths | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:17:24:17:28 | attrs | various-concat-obfuscations.js:18:10:18:105 | '
') | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) | | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:17:24:17:28 | attrs | various-concat-obfuscations.js:18:10:18:105 | '
') [ArrayElement] | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) | #select +| aws-db.js:15:31:15:76 | results ... arValue | aws-db.js:15:31:15:37 | results | aws-db.js:15:31:15:76 | results ... arValue | Cross-site scripting vulnerability due to $@. | aws-db.js:15:31:15:37 | results | user-provided value | +| aws-db.js:20:31:20:54 | respons ... tring() | aws-db.js:20:31:20:38 | response | aws-db.js:20:31:20:54 | respons ... tring() | Cross-site scripting vulnerability due to $@. | aws-db.js:20:31:20:38 | response | user-provided value | +| aws-db.js:24:31:24:47 | response2.records | aws-db.js:24:31:24:39 | response2 | aws-db.js:24:31:24:47 | response2.records | Cross-site scripting vulnerability due to $@. | aws-db.js:24:31:24:39 | response2 | user-provided value | +| aws-db.js:28:31:28:44 | response3.Item | aws-db.js:28:31:28:39 | response3 | aws-db.js:28:31:28:44 | response3.Item | Cross-site scripting vulnerability due to $@. | aws-db.js:28:31:28:39 | response3 | user-provided value | +| aws-db.js:43:31:43:76 | results ... arValue | aws-db.js:43:31:43:37 | results | aws-db.js:43:31:43:76 | results ... arValue | Cross-site scripting vulnerability due to $@. | aws-db.js:43:31:43:37 | results | user-provided value | +| aws-db.js:46:35:46:77 | data.Re ... arValue | aws-db.js:46:35:46:38 | data | aws-db.js:46:35:46:77 | data.Re ... arValue | Cross-site scripting vulnerability due to $@. | aws-db.js:46:35:46:38 | data | user-provided value | +| aws-db.js:51:31:51:54 | respons ... tring() | aws-db.js:51:31:51:38 | response | aws-db.js:51:31:51:54 | respons ... tring() | Cross-site scripting vulnerability due to $@. | aws-db.js:51:31:51:38 | response | user-provided value | +| aws-db.js:54:35:54:54 | data.Body.toString() | aws-db.js:54:35:54:38 | data | aws-db.js:54:35:54:54 | data.Body.toString() | Cross-site scripting vulnerability due to $@. | aws-db.js:54:35:54:38 | data | user-provided value | +| aws-db.js:59:31:59:47 | response1.records | aws-db.js:59:31:59:39 | response1 | aws-db.js:59:31:59:47 | response1.records | Cross-site scripting vulnerability due to $@. | aws-db.js:59:31:59:39 | response1 | user-provided value | +| aws-db.js:62:35:62:46 | data.records | aws-db.js:62:35:62:38 | data | aws-db.js:62:35:62:46 | data.records | Cross-site scripting vulnerability due to $@. | aws-db.js:62:35:62:38 | data | user-provided value | +| aws-db.js:66:31:66:53 | respons ... Results | aws-db.js:66:31:66:39 | response2 | aws-db.js:66:31:66:53 | respons ... Results | Cross-site scripting vulnerability due to $@. | aws-db.js:66:31:66:39 | response2 | user-provided value | +| aws-db.js:69:35:69:52 | data.updateResults | aws-db.js:69:35:69:38 | data | aws-db.js:69:35:69:52 | data.updateResults | Cross-site scripting vulnerability due to $@. | aws-db.js:69:35:69:38 | data | user-provided value | +| aws-db.js:74:35:74:43 | data.Item | aws-db.js:74:35:74:38 | data | aws-db.js:74:35:74:43 | data.Item | Cross-site scripting vulnerability due to $@. | aws-db.js:74:35:74:38 | data | user-provided value | +| aws-db.js:77:35:77:43 | data.Item | aws-db.js:77:35:77:38 | data | aws-db.js:77:35:77:43 | data.Item | Cross-site scripting vulnerability due to $@. | aws-db.js:77:35:77:38 | data | user-provided value | | hana.js:11:37:11:51 | rows[0].comment | hana.js:11:37:11:40 | rows | hana.js:11:37:11:51 | rows[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:11:37:11:40 | rows | user-provided value | | hana.js:16:37:16:51 | rows[0].comment | hana.js:16:37:16:40 | rows | hana.js:16:37:16:51 | rows[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:16:37:16:40 | rows | user-provided value | | hana.js:19:37:19:51 | rows[0].comment | hana.js:19:37:19:40 | rows | hana.js:19:37:19:51 | rows[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:19:37:19:40 | rows | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/aws-db.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/aws-db.js new file mode 100644 index 000000000000..0f345f7172e0 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/aws-db.js @@ -0,0 +1,79 @@ +const { AthenaClient, GetQueryResultsCommand } = require('@aws-sdk/client-athena'); +const { S3Client, GetObjectCommand } = require("@aws-sdk/client-s3"); +const { RDSDataClient, ExecuteStatementCommand } = require("@aws-sdk/client-rds-data"); +const { DynamoDBClient, GetItemCommand } = require("@aws-sdk/client-dynamodb"); + + +const express = require('express'); +const bodyParser = require('body-parser'); +const app = express(); +app.use(bodyParser.json()); + +app.post('/v3/all', async (req, res) => { + const client = new AthenaClient({ region: "us-east-1" }); + const results = await client.send(new GetQueryResultsCommand({ QueryExecutionId })); + document.body.innerHTML = results.ResultSet.Rows[0].Data[0].VarCharValue; // $ Alert[js/xss-additional-sources-dom-test] + + const s3 = new S3Client({ region: "us-east-1" }); + const command = new GetObjectCommand({ Bucket: bucket, Key: key }); + const response = await s3.send(command); + document.body.innerHTML = response.Body.toString(); // $ Alert[js/xss-additional-sources-dom-test] + + const clientRDS = new RDSDataClient({ region: "us-east-1" }); + const response2 = await clientRDS.send(new ExecuteStatementCommand(command)); + document.body.innerHTML = response2.records; // $ Alert[js/xss-additional-sources-dom-test] + + const clientDyamo = new DynamoDBClient({ region: "us-east-1" }); + const response3 = await clientDyamo.send(new GetItemCommand(command)); + document.body.innerHTML = response3.Item; // $ Alert[js/xss-additional-sources-dom-test] + +}); + + +app.post('/v2/all', async (req, res) => { + const AWS = require('aws-sdk'); + const athena = new AWS.Athena(); + const params = { + QueryString: 'SELECT * FROM my_table', + ResultConfiguration: { OutputLocation: 's3://bucket/prefix/' } + }; + const { QueryExecutionId } = await athena.startQueryExecution(params).promise(); + + const results = await athena.getQueryResults({ QueryExecutionId }).promise(); + document.body.innerHTML = results.ResultSet.Rows[0].Data[0].VarCharValue; // $ Alert[js/xss-additional-sources-dom-test] + + athena.getQueryResults({ QueryExecutionId }, (err, data) => { + document.body.innerHTML = data.ResultSet.Rows[0].Data[0].VarCharValue; // $ Alert[js/xss-additional-sources-dom-test] + }); + + const s3 = new AWS.S3({ region: "us-east-1" }); + const response = await s3.getObject({ Bucket: "bucket", Key: "key" }).promise(); + document.body.innerHTML = response.Body.toString(); // $ Alert[js/xss-additional-sources-dom-test] + + s3.getObject({ Bucket: "bucket", Key: "key" }, (err, data) => { + document.body.innerHTML = data.Body.toString(); // $ Alert[js/xss-additional-sources-dom-test] + }); + + const rdsData = new AWS.RDSDataService({ region: "us-east-1" }); + const response1 = await rdsData.executeStatement(params).promise(); + document.body.innerHTML = response1.records; // $ Alert[js/xss-additional-sources-dom-test] + + rdsData.executeStatement(params, function(err, data) { + document.body.innerHTML = data.records; // $ Alert[js/xss-additional-sources-dom-test] + }); + + const response2 = await rdsData.batchExecuteStatement(params).promise(); + document.body.innerHTML = response2.updateResults; // $ Alert[js/xss-additional-sources-dom-test] + + rdsData.batchExecuteStatement(params, function(err, data) { + document.body.innerHTML = data.updateResults; // $ Alert[js/xss-additional-sources-dom-test] + }); + + const dynamodb = new AWS.DynamoDB({ region: "us-east-1" }); + dynamodb.executeStatement(params, (err, data) => { + document.body.innerHTML = data.Item; // $ Alert[js/xss-additional-sources-dom-test] + }); + dynamodb.executeStatement(params).promise().then(data => { + document.body.innerHTML = data.Item; // $ Alert[js/xss-additional-sources-dom-test] + }); +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected index 843d41eb9229..888cbee4641e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected @@ -1,4 +1,19 @@ #select +| athena.js:19:23:19:23 | p | athena.js:9:23:9:30 | req.body | athena.js:19:23:19:23 | p | This query string depends on a $@. | athena.js:9:23:9:30 | req.body | user-provided value | +| athena.js:27:23:27:58 | new Cre ... arams2) | athena.js:9:23:9:30 | req.body | athena.js:27:23:27:58 | new Cre ... arams2) | This query string depends on a $@. | athena.js:9:23:9:30 | req.body | user-provided value | +| athena.js:36:23:36:58 | new Upd ... arams3) | athena.js:9:23:9:30 | req.body | athena.js:36:23:36:58 | new Upd ... arams3) | This query string depends on a $@. | athena.js:9:23:9:30 | req.body | user-provided value | +| athena.js:48:22:48:30 | userQuery | athena.js:43:23:43:30 | req.body | athena.js:48:22:48:30 | userQuery | This query string depends on a $@. | athena.js:43:23:43:30 | req.body | user-provided value | +| athena.js:57:22:57:30 | userQuery | athena.js:43:23:43:30 | req.body | athena.js:57:22:57:30 | userQuery | This query string depends on a $@. | athena.js:43:23:43:30 | req.body | user-provided value | +| athena.js:66:22:66:30 | userQuery | athena.js:43:23:43:30 | req.body | athena.js:66:22:66:30 | userQuery | This query string depends on a $@. | athena.js:43:23:43:30 | req.body | user-provided value | +| clients3.js:18:23:18:60 | new Sel ... params) | clients3.js:10:26:10:33 | req.body | clients3.js:18:23:18:60 | new Sel ... params) | This query string depends on a $@. | clients3.js:10:26:10:33 | req.body | user-provided value | +| clients3.js:29:21:29:68 | "SELECT ... usInput | clients3.js:23:26:23:33 | req.body | clients3.js:29:21:29:68 | "SELECT ... usInput | This query string depends on a $@. | clients3.js:23:26:23:33 | req.body | user-provided value | +| clients3.js:38:21:38:68 | "SELECT ... usInput | clients3.js:23:26:23:33 | req.body | clients3.js:38:21:38:68 | "SELECT ... usInput | This query string depends on a $@. | clients3.js:23:26:23:33 | req.body | user-provided value | +| dynamodb.js:15:23:15:29 | command | dynamodb.js:9:26:9:33 | req.body | dynamodb.js:15:23:15:29 | command | This query string depends on a $@. | dynamodb.js:9:26:9:33 | req.body | user-provided value | +| dynamodb.js:21:23:21:35 | updateCommand | dynamodb.js:9:26:9:33 | req.body | dynamodb.js:21:23:21:35 | updateCommand | This query string depends on a $@. | dynamodb.js:9:26:9:33 | req.body | user-provided value | +| dynamodb.js:47:24:47:30 | command | dynamodb.js:9:26:9:33 | req.body | dynamodb.js:47:24:47:30 | command | This query string depends on a $@. | dynamodb.js:9:26:9:33 | req.body | user-provided value | +| dynamodb.js:58:20:58:77 | `SELECT ... nput}'` | dynamodb.js:56:26:56:33 | req.body | dynamodb.js:58:20:58:77 | `SELECT ... nput}'` | This query string depends on a $@. | dynamodb.js:56:26:56:33 | req.body | user-provided value | +| dynamodb.js:64:28:64:85 | `SELECT ... nput}'` | dynamodb.js:56:26:56:33 | req.body | dynamodb.js:64:28:64:85 | `SELECT ... nput}'` | This query string depends on a $@. | dynamodb.js:56:26:56:33 | req.body | user-provided value | +| dynamodb.js:67:28:67:85 | `SELECT ... nput}'` | dynamodb.js:56:26:56:33 | req.body | dynamodb.js:67:28:67:85 | `SELECT ... nput}'` | This query string depends on a $@. | dynamodb.js:56:26:56:33 | req.body | user-provided value | | graphql.js:9:34:19:5 | `\\n ... }\\n ` | graphql.js:8:16:8:28 | req.params.id | graphql.js:9:34:19:5 | `\\n ... }\\n ` | This query string depends on a $@. | graphql.js:8:16:8:28 | req.params.id | user-provided value | | graphql.js:26:30:26:40 | `foo ${id}` | graphql.js:25:16:25:28 | req.params.id | graphql.js:26:30:26:40 | `foo ${id}` | This query string depends on a $@. | graphql.js:25:16:25:28 | req.params.id | user-provided value | | graphql.js:29:32:29:42 | `foo ${id}` | graphql.js:25:16:25:28 | req.params.id | graphql.js:29:32:29:42 | `foo ${id}` | This query string depends on a $@. | graphql.js:25:16:25:28 | req.params.id | user-provided value | @@ -122,6 +137,10 @@ | pg-promise.js:60:20:60:24 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:60:20:60:24 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | | pg-promise.js:63:23:63:27 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:63:23:63:27 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | | pg-promise.js:64:16:64:20 | query | pg-promise.js:7:16:7:34 | req.params.category | pg-promise.js:64:16:64:20 | query | This query string depends on a $@. | pg-promise.js:7:16:7:34 | req.params.category | user-provided value | +| rds-client.js:19:23:19:58 | new Exe ... arams1) | rds-client.js:8:23:8:30 | req.body | rds-client.js:19:23:19:58 | new Exe ... arams1) | This query string depends on a $@. | rds-client.js:8:23:8:30 | req.body | user-provided value | +| rds-client.js:36:23:36:51 | new Exe ... params) | rds-client.js:8:23:8:30 | req.body | rds-client.js:36:23:36:51 | new Exe ... params) | This query string depends on a $@. | rds-client.js:8:23:8:30 | req.body | user-provided value | +| rds-client.js:53:14:53:22 | userQuery | rds-client.js:44:23:44:30 | req.body | rds-client.js:53:14:53:22 | userQuery | This query string depends on a $@. | rds-client.js:44:23:44:30 | req.body | user-provided value | +| rds-client.js:61:50:61:52 | sql | rds-client.js:45:25:45:32 | req.body | rds-client.js:61:50:61:52 | sql | This query string depends on a $@. | rds-client.js:45:25:45:32 | req.body | user-provided value | | redis.js:10:16:10:27 | req.body.key | redis.js:10:16:10:23 | req.body | redis.js:10:16:10:27 | req.body.key | This query object depends on a $@. | redis.js:10:16:10:23 | req.body | user-provided value | | redis.js:18:16:18:18 | key | redis.js:12:15:12:22 | req.body | redis.js:18:16:18:18 | key | This query object depends on a $@. | redis.js:12:15:12:22 | req.body | user-provided value | | redis.js:19:43:19:45 | key | redis.js:12:15:12:22 | req.body | redis.js:19:43:19:45 | key | This query object depends on a $@. | redis.js:12:15:12:22 | req.body | user-provided value | @@ -137,6 +156,64 @@ | tst4.js:8:10:8:66 | 'SELECT ... d + '"' | tst4.js:8:46:8:60 | $routeParams.id | tst4.js:8:10:8:66 | 'SELECT ... d + '"' | This query string depends on a $@. | tst4.js:8:46:8:60 | $routeParams.id | user-provided value | | tst.js:10:10:10:64 | 'SELECT ... d + '"' | tst.js:10:46:10:58 | req.params.id | tst.js:10:10:10:64 | 'SELECT ... d + '"' | This query string depends on a $@. | tst.js:10:46:10:58 | req.params.id | user-provided value | edges +| athena.js:9:11:9:36 | userQuery | athena.js:14:30:14:38 | userQuery | provenance | | +| athena.js:9:11:9:36 | userQuery | athena.js:24:22:24:30 | userQuery | provenance | | +| athena.js:9:11:9:36 | userQuery | athena.js:33:22:33:30 | userQuery | provenance | | +| athena.js:9:23:9:30 | req.body | athena.js:9:11:9:36 | userQuery | provenance | | +| athena.js:13:11:17:5 | params1 [QueryString] | athena.js:18:46:18:52 | params1 [QueryString] | provenance | | +| athena.js:13:21:17:5 | {\\n ... }\\n } [QueryString] | athena.js:13:11:17:5 | params1 [QueryString] | provenance | | +| athena.js:14:22:14:38 | "SQL" + userQuery | athena.js:13:21:17:5 | {\\n ... }\\n } [QueryString] | provenance | | +| athena.js:14:30:14:38 | userQuery | athena.js:14:22:14:38 | "SQL" + userQuery | provenance | | +| athena.js:18:11:18:53 | p | athena.js:19:23:19:23 | p | provenance | | +| athena.js:18:15:18:53 | new Sta ... arams1) | athena.js:18:11:18:53 | p | provenance | | +| athena.js:18:46:18:52 | params1 [QueryString] | athena.js:18:15:18:53 | new Sta ... arams1) | provenance | | +| athena.js:21:11:26:5 | params2 [QueryString] | athena.js:27:51:27:57 | params2 [QueryString] | provenance | | +| athena.js:21:21:26:5 | {\\n ... "\\n } [QueryString] | athena.js:21:11:26:5 | params2 [QueryString] | provenance | | +| athena.js:24:22:24:30 | userQuery | athena.js:21:21:26:5 | {\\n ... "\\n } [QueryString] | provenance | | +| athena.js:27:51:27:57 | params2 [QueryString] | athena.js:27:23:27:58 | new Cre ... arams2) | provenance | | +| athena.js:29:11:35:5 | params3 [QueryString] | athena.js:36:51:36:57 | params3 [QueryString] | provenance | | +| athena.js:29:21:35:5 | {\\n ... "\\n } [QueryString] | athena.js:29:11:35:5 | params3 [QueryString] | provenance | | +| athena.js:33:22:33:30 | userQuery | athena.js:29:21:35:5 | {\\n ... "\\n } [QueryString] | provenance | | +| athena.js:36:51:36:57 | params3 [QueryString] | athena.js:36:23:36:58 | new Upd ... arams3) | provenance | | +| athena.js:43:11:43:36 | userQuery | athena.js:48:22:48:30 | userQuery | provenance | | +| athena.js:43:11:43:36 | userQuery | athena.js:57:22:57:30 | userQuery | provenance | | +| athena.js:43:11:43:36 | userQuery | athena.js:66:22:66:30 | userQuery | provenance | | +| athena.js:43:23:43:30 | req.body | athena.js:43:11:43:36 | userQuery | provenance | | +| clients3.js:10:9:10:40 | maliciousInput | clients3.js:16:55:16:68 | maliciousInput | provenance | | +| clients3.js:10:26:10:33 | req.body | clients3.js:10:9:10:40 | maliciousInput | provenance | | +| clients3.js:12:11:17:5 | params [Expression] | clients3.js:18:54:18:59 | params [Expression] | provenance | | +| clients3.js:12:20:17:5 | {\\n ... ,\\n } [Expression] | clients3.js:12:11:17:5 | params [Expression] | provenance | | +| clients3.js:16:21:16:68 | "SELECT ... usInput | clients3.js:12:20:17:5 | {\\n ... ,\\n } [Expression] | provenance | | +| clients3.js:16:55:16:68 | maliciousInput | clients3.js:16:21:16:68 | "SELECT ... usInput | provenance | | +| clients3.js:18:54:18:59 | params [Expression] | clients3.js:18:23:18:60 | new Sel ... params) | provenance | | +| clients3.js:23:9:23:40 | maliciousInput | clients3.js:29:55:29:68 | maliciousInput | provenance | | +| clients3.js:23:9:23:40 | maliciousInput | clients3.js:38:55:38:68 | maliciousInput | provenance | | +| clients3.js:23:26:23:33 | req.body | clients3.js:23:9:23:40 | maliciousInput | provenance | | +| clients3.js:29:55:29:68 | maliciousInput | clients3.js:29:21:29:68 | "SELECT ... usInput | provenance | | +| clients3.js:38:55:38:68 | maliciousInput | clients3.js:38:21:38:68 | "SELECT ... usInput | provenance | | +| dynamodb.js:9:9:9:38 | maliciousInput | dynamodb.js:11:64:11:77 | maliciousInput | provenance | | +| dynamodb.js:9:9:9:38 | maliciousInput | dynamodb.js:17:80:17:93 | maliciousInput | provenance | | +| dynamodb.js:9:26:9:33 | req.body | dynamodb.js:9:9:9:38 | maliciousInput | provenance | | +| dynamodb.js:11:11:11:80 | statement | dynamodb.js:13:20:13:28 | statement | provenance | | +| dynamodb.js:11:64:11:77 | maliciousInput | dynamodb.js:11:11:11:80 | statement | provenance | | +| dynamodb.js:12:11:14:6 | command | dynamodb.js:15:23:15:29 | command | provenance | | +| dynamodb.js:12:11:14:6 | command | dynamodb.js:47:24:47:30 | command | provenance | | +| dynamodb.js:12:21:14:6 | new Exe ... \\n }) | dynamodb.js:12:11:14:6 | command | provenance | | +| dynamodb.js:12:49:14:5 | {\\n ... t\\n } [Statement] | dynamodb.js:12:21:14:6 | new Exe ... \\n }) | provenance | | +| dynamodb.js:13:20:13:28 | statement | dynamodb.js:12:49:14:5 | {\\n ... t\\n } [Statement] | provenance | | +| dynamodb.js:17:11:17:93 | updateStatement | dynamodb.js:19:20:19:34 | updateStatement | provenance | | +| dynamodb.js:17:80:17:93 | maliciousInput | dynamodb.js:17:11:17:93 | updateStatement | provenance | | +| dynamodb.js:18:11:20:6 | updateCommand | dynamodb.js:21:23:21:35 | updateCommand | provenance | | +| dynamodb.js:18:27:20:6 | new Exe ... \\n }) | dynamodb.js:18:11:20:6 | updateCommand | provenance | | +| dynamodb.js:18:55:20:5 | {\\n ... t\\n } [Statement] | dynamodb.js:18:27:20:6 | new Exe ... \\n }) | provenance | | +| dynamodb.js:19:20:19:34 | updateStatement | dynamodb.js:18:55:20:5 | {\\n ... t\\n } [Statement] | provenance | | +| dynamodb.js:56:9:56:38 | maliciousInput | dynamodb.js:58:61:58:74 | maliciousInput | provenance | | +| dynamodb.js:56:9:56:38 | maliciousInput | dynamodb.js:64:69:64:82 | maliciousInput | provenance | | +| dynamodb.js:56:9:56:38 | maliciousInput | dynamodb.js:67:69:67:82 | maliciousInput | provenance | | +| dynamodb.js:56:26:56:33 | req.body | dynamodb.js:56:9:56:38 | maliciousInput | provenance | | +| dynamodb.js:58:61:58:74 | maliciousInput | dynamodb.js:58:20:58:77 | `SELECT ... nput}'` | provenance | | +| dynamodb.js:64:69:64:82 | maliciousInput | dynamodb.js:64:28:64:85 | `SELECT ... nput}'` | provenance | | +| dynamodb.js:67:69:67:82 | maliciousInput | dynamodb.js:67:28:67:85 | `SELECT ... nput}'` | provenance | | | graphql.js:8:11:8:28 | id | graphql.js:11:46:11:47 | id | provenance | | | graphql.js:8:16:8:28 | req.params.id | graphql.js:8:11:8:28 | id | provenance | | | graphql.js:11:46:11:47 | id | graphql.js:9:34:19:5 | `\\n ... }\\n ` | provenance | | @@ -490,6 +567,23 @@ edges | pg-promise.js:22:11:22:15 | query | pg-promise.js:60:20:60:24 | query | provenance | | | pg-promise.js:22:11:22:15 | query | pg-promise.js:63:23:63:27 | query | provenance | | | pg-promise.js:22:11:22:15 | query | pg-promise.js:64:16:64:20 | query | provenance | | +| rds-client.js:8:11:8:36 | userQuery | rds-client.js:17:14:17:22 | userQuery | provenance | | +| rds-client.js:8:11:8:36 | userQuery | rds-client.js:33:24:33:32 | userQuery | provenance | | +| rds-client.js:8:23:8:30 | req.body | rds-client.js:8:11:8:36 | userQuery | provenance | | +| rds-client.js:13:11:18:5 | params1 [sql] | rds-client.js:19:51:19:57 | params1 [sql] | provenance | | +| rds-client.js:13:21:18:5 | {\\n ... y\\n } [sql] | rds-client.js:13:11:18:5 | params1 [sql] | provenance | | +| rds-client.js:17:14:17:22 | userQuery | rds-client.js:13:21:18:5 | {\\n ... y\\n } [sql] | provenance | | +| rds-client.js:19:51:19:57 | params1 [sql] | rds-client.js:19:23:19:58 | new Exe ... arams1) | provenance | | +| rds-client.js:29:11:34:5 | params [sqlStatements] | rds-client.js:36:45:36:50 | params [sqlStatements] | provenance | | +| rds-client.js:29:20:34:5 | {\\n ... y\\n } [sqlStatements] | rds-client.js:29:11:34:5 | params [sqlStatements] | provenance | | +| rds-client.js:33:24:33:32 | userQuery | rds-client.js:29:20:34:5 | {\\n ... y\\n } [sqlStatements] | provenance | | +| rds-client.js:36:45:36:50 | params [sqlStatements] | rds-client.js:36:23:36:51 | new Exe ... params) | provenance | | +| rds-client.js:44:11:44:36 | userQuery | rds-client.js:53:14:53:22 | userQuery | provenance | | +| rds-client.js:44:23:44:30 | req.body | rds-client.js:44:11:44:36 | userQuery | provenance | | +| rds-client.js:45:11:45:40 | userQueries | rds-client.js:61:24:61:34 | userQueries | provenance | | +| rds-client.js:45:25:45:32 | req.body | rds-client.js:45:11:45:40 | userQueries | provenance | | +| rds-client.js:61:24:61:34 | userQueries | rds-client.js:61:40:61:42 | sql | provenance | | +| rds-client.js:61:40:61:42 | sql | rds-client.js:61:50:61:52 | sql | provenance | | | redis.js:10:16:10:23 | req.body | redis.js:10:16:10:27 | req.body.key | provenance | Config | | redis.js:12:9:12:26 | key | redis.js:13:16:13:18 | key | provenance | | | redis.js:12:9:12:26 | key | redis.js:18:16:18:18 | key | provenance | | @@ -518,6 +612,70 @@ edges | tst4.js:8:46:8:60 | $routeParams.id | tst4.js:8:10:8:66 | 'SELECT ... d + '"' | provenance | | | tst.js:10:46:10:58 | req.params.id | tst.js:10:10:10:64 | 'SELECT ... d + '"' | provenance | | nodes +| athena.js:9:11:9:36 | userQuery | semmle.label | userQuery | +| athena.js:9:23:9:30 | req.body | semmle.label | req.body | +| athena.js:13:11:17:5 | params1 [QueryString] | semmle.label | params1 [QueryString] | +| athena.js:13:21:17:5 | {\\n ... }\\n } [QueryString] | semmle.label | {\\n ... }\\n } [QueryString] | +| athena.js:14:22:14:38 | "SQL" + userQuery | semmle.label | "SQL" + userQuery | +| athena.js:14:30:14:38 | userQuery | semmle.label | userQuery | +| athena.js:18:11:18:53 | p | semmle.label | p | +| athena.js:18:15:18:53 | new Sta ... arams1) | semmle.label | new Sta ... arams1) | +| athena.js:18:46:18:52 | params1 [QueryString] | semmle.label | params1 [QueryString] | +| athena.js:19:23:19:23 | p | semmle.label | p | +| athena.js:21:11:26:5 | params2 [QueryString] | semmle.label | params2 [QueryString] | +| athena.js:21:21:26:5 | {\\n ... "\\n } [QueryString] | semmle.label | {\\n ... "\\n } [QueryString] | +| athena.js:24:22:24:30 | userQuery | semmle.label | userQuery | +| athena.js:27:23:27:58 | new Cre ... arams2) | semmle.label | new Cre ... arams2) | +| athena.js:27:51:27:57 | params2 [QueryString] | semmle.label | params2 [QueryString] | +| athena.js:29:11:35:5 | params3 [QueryString] | semmle.label | params3 [QueryString] | +| athena.js:29:21:35:5 | {\\n ... "\\n } [QueryString] | semmle.label | {\\n ... "\\n } [QueryString] | +| athena.js:33:22:33:30 | userQuery | semmle.label | userQuery | +| athena.js:36:23:36:58 | new Upd ... arams3) | semmle.label | new Upd ... arams3) | +| athena.js:36:51:36:57 | params3 [QueryString] | semmle.label | params3 [QueryString] | +| athena.js:43:11:43:36 | userQuery | semmle.label | userQuery | +| athena.js:43:23:43:30 | req.body | semmle.label | req.body | +| athena.js:48:22:48:30 | userQuery | semmle.label | userQuery | +| athena.js:57:22:57:30 | userQuery | semmle.label | userQuery | +| athena.js:66:22:66:30 | userQuery | semmle.label | userQuery | +| clients3.js:10:9:10:40 | maliciousInput | semmle.label | maliciousInput | +| clients3.js:10:26:10:33 | req.body | semmle.label | req.body | +| clients3.js:12:11:17:5 | params [Expression] | semmle.label | params [Expression] | +| clients3.js:12:20:17:5 | {\\n ... ,\\n } [Expression] | semmle.label | {\\n ... ,\\n } [Expression] | +| clients3.js:16:21:16:68 | "SELECT ... usInput | semmle.label | "SELECT ... usInput | +| clients3.js:16:55:16:68 | maliciousInput | semmle.label | maliciousInput | +| clients3.js:18:23:18:60 | new Sel ... params) | semmle.label | new Sel ... params) | +| clients3.js:18:54:18:59 | params [Expression] | semmle.label | params [Expression] | +| clients3.js:23:9:23:40 | maliciousInput | semmle.label | maliciousInput | +| clients3.js:23:26:23:33 | req.body | semmle.label | req.body | +| clients3.js:29:21:29:68 | "SELECT ... usInput | semmle.label | "SELECT ... usInput | +| clients3.js:29:55:29:68 | maliciousInput | semmle.label | maliciousInput | +| clients3.js:38:21:38:68 | "SELECT ... usInput | semmle.label | "SELECT ... usInput | +| clients3.js:38:55:38:68 | maliciousInput | semmle.label | maliciousInput | +| dynamodb.js:9:9:9:38 | maliciousInput | semmle.label | maliciousInput | +| dynamodb.js:9:26:9:33 | req.body | semmle.label | req.body | +| dynamodb.js:11:11:11:80 | statement | semmle.label | statement | +| dynamodb.js:11:64:11:77 | maliciousInput | semmle.label | maliciousInput | +| dynamodb.js:12:11:14:6 | command | semmle.label | command | +| dynamodb.js:12:21:14:6 | new Exe ... \\n }) | semmle.label | new Exe ... \\n }) | +| dynamodb.js:12:49:14:5 | {\\n ... t\\n } [Statement] | semmle.label | {\\n ... t\\n } [Statement] | +| dynamodb.js:13:20:13:28 | statement | semmle.label | statement | +| dynamodb.js:15:23:15:29 | command | semmle.label | command | +| dynamodb.js:17:11:17:93 | updateStatement | semmle.label | updateStatement | +| dynamodb.js:17:80:17:93 | maliciousInput | semmle.label | maliciousInput | +| dynamodb.js:18:11:20:6 | updateCommand | semmle.label | updateCommand | +| dynamodb.js:18:27:20:6 | new Exe ... \\n }) | semmle.label | new Exe ... \\n }) | +| dynamodb.js:18:55:20:5 | {\\n ... t\\n } [Statement] | semmle.label | {\\n ... t\\n } [Statement] | +| dynamodb.js:19:20:19:34 | updateStatement | semmle.label | updateStatement | +| dynamodb.js:21:23:21:35 | updateCommand | semmle.label | updateCommand | +| dynamodb.js:47:24:47:30 | command | semmle.label | command | +| dynamodb.js:56:9:56:38 | maliciousInput | semmle.label | maliciousInput | +| dynamodb.js:56:26:56:33 | req.body | semmle.label | req.body | +| dynamodb.js:58:20:58:77 | `SELECT ... nput}'` | semmle.label | `SELECT ... nput}'` | +| dynamodb.js:58:61:58:74 | maliciousInput | semmle.label | maliciousInput | +| dynamodb.js:64:28:64:85 | `SELECT ... nput}'` | semmle.label | `SELECT ... nput}'` | +| dynamodb.js:64:69:64:82 | maliciousInput | semmle.label | maliciousInput | +| dynamodb.js:67:28:67:85 | `SELECT ... nput}'` | semmle.label | `SELECT ... nput}'` | +| dynamodb.js:67:69:67:82 | maliciousInput | semmle.label | maliciousInput | | graphql.js:8:11:8:28 | id | semmle.label | id | | graphql.js:8:16:8:28 | req.params.id | semmle.label | req.params.id | | graphql.js:9:34:19:5 | `\\n ... }\\n ` | semmle.label | `\\n ... }\\n ` | @@ -803,6 +961,26 @@ nodes | pg-promise.js:60:20:60:24 | query | semmle.label | query | | pg-promise.js:63:23:63:27 | query | semmle.label | query | | pg-promise.js:64:16:64:20 | query | semmle.label | query | +| rds-client.js:8:11:8:36 | userQuery | semmle.label | userQuery | +| rds-client.js:8:23:8:30 | req.body | semmle.label | req.body | +| rds-client.js:13:11:18:5 | params1 [sql] | semmle.label | params1 [sql] | +| rds-client.js:13:21:18:5 | {\\n ... y\\n } [sql] | semmle.label | {\\n ... y\\n } [sql] | +| rds-client.js:17:14:17:22 | userQuery | semmle.label | userQuery | +| rds-client.js:19:23:19:58 | new Exe ... arams1) | semmle.label | new Exe ... arams1) | +| rds-client.js:19:51:19:57 | params1 [sql] | semmle.label | params1 [sql] | +| rds-client.js:29:11:34:5 | params [sqlStatements] | semmle.label | params [sqlStatements] | +| rds-client.js:29:20:34:5 | {\\n ... y\\n } [sqlStatements] | semmle.label | {\\n ... y\\n } [sqlStatements] | +| rds-client.js:33:24:33:32 | userQuery | semmle.label | userQuery | +| rds-client.js:36:23:36:51 | new Exe ... params) | semmle.label | new Exe ... params) | +| rds-client.js:36:45:36:50 | params [sqlStatements] | semmle.label | params [sqlStatements] | +| rds-client.js:44:11:44:36 | userQuery | semmle.label | userQuery | +| rds-client.js:44:23:44:30 | req.body | semmle.label | req.body | +| rds-client.js:45:11:45:40 | userQueries | semmle.label | userQueries | +| rds-client.js:45:25:45:32 | req.body | semmle.label | req.body | +| rds-client.js:53:14:53:22 | userQuery | semmle.label | userQuery | +| rds-client.js:61:24:61:34 | userQueries | semmle.label | userQueries | +| rds-client.js:61:40:61:42 | sql | semmle.label | sql | +| rds-client.js:61:50:61:52 | sql | semmle.label | sql | | redis.js:10:16:10:23 | req.body | semmle.label | req.body | | redis.js:10:16:10:27 | req.body.key | semmle.label | req.body.key | | redis.js:12:9:12:26 | key | semmle.label | key | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/athena.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/athena.js new file mode 100644 index 000000000000..2b661d5d4aea --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/athena.js @@ -0,0 +1,72 @@ +const { AthenaClient, StartQueryExecutionCommand, CreateNamedQueryCommand, UpdateNamedQueryCommand } = require("@aws-sdk/client-athena"); +const AWS = require('aws-sdk'); +const express = require('express'); +const bodyParser = require('body-parser'); +const app = express(); +app.use(bodyParser.json()); + +app.post('/v3/athena/all', async (req, res) => { + const userQuery = req.body.query; // $ Source + + const client = new AthenaClient({ region: "us-east-1" }); + + const params1 = { + QueryString: "SQL" + userQuery, + QueryExecutionContext: { Database: "default" }, + ResultConfiguration: { OutputLocation: "s3://my-results/" } + }; + const p = new StartQueryExecutionCommand(params1); + await client.send(p); // $ Alert + + const params2 = { + Name: "user_query", + Database: "default", + QueryString: userQuery, + Description: "User-provided query" + }; + await client.send(new CreateNamedQueryCommand(params2)); // $ Alert -- This only stores query to database, not executed + + const params3 = { + NamedQueryId: "namedQueryId", + Name: "user_query_updated", + Database: "default", + QueryString: userQuery, + Description: "Updated user-provided query" + }; + await client.send(new UpdateNamedQueryCommand(params3)); // $ Alert -- This only stores query to database, not executed + + res.end(); +}); + + +app.post('/v2/athena/all', async (req, res) => { + const userQuery = req.body.query; // $ Source + + const athena = new AWS.Athena({ region: "us-east-1" }); + + const params1 = { + QueryString: userQuery, // $ Alert + QueryExecutionContext: { Database: "default" }, + ResultConfiguration: { OutputLocation: "s3://my-results/" } + }; + await athena.startQueryExecution(params1).promise(); + + const params2 = { + Name: "user_query", + Database: "default", + QueryString: userQuery, // $ Alert -- This only stores query to database, not executed + Description: "User-provided query" + }; + await athena.createNamedQuery(params2).promise(); + + const params3 = { + NamedQueryId: "namedQueryId", + Name: "user_query_updated", + Database: "default", + QueryString: userQuery, // $ Alert -- This only stores query to database, not executed + Description: "Updated user-provided query" + }; + await athena.updateNamedQuery(params3).promise(); + + res.end(); +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/clients3.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/clients3.js new file mode 100644 index 000000000000..9c6bce426575 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/clients3.js @@ -0,0 +1,44 @@ +const { S3Client, SelectObjectContentCommand } = require("@aws-sdk/client-s3"); +const AWS = require('aws-sdk'); +const express = require('express'); +const bodyParser = require('body-parser'); + +const app = express(); +app.use(bodyParser.json()); + +app.post('/client/v3/execute', async (req, res) => { + let maliciousInput = req.body.filter; // $ Source + const client = new S3Client({ region: "us-east-1" }); + const params = { + Bucket: "my-bucket", + Key: "data.csv", + ExpressionType: "SQL", + Expression: "SELECT * FROM S3Object WHERE " + maliciousInput, + }; + await client.send(new SelectObjectContentCommand(params)); // $ Alert + res.end(); +}); + +app.post('/client/v2/execute', async (req, res) => { + let maliciousInput = req.body.filter; // $ Source + const s3 = new AWS.S3({ region: "us-east-1" }); + const params = { + Bucket: "my-bucket", + Key: "data.csv", + ExpressionType: "SQL", + Expression: "SELECT * FROM S3Object WHERE " + maliciousInput, // $ Alert + }; + await s3.selectObjectContent(params).promise(); + res.end(); + + const params1 = { + Bucket: "my-bucket", + Key: "data.csv", + ExpressionType: "SQL", + Expression: "SELECT * FROM S3Object WHERE " + maliciousInput, // $ Alert + }; + + s3.selectObjectContent(params1, (err, data) => { + res.end(); + }); +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/dynamodb.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/dynamodb.js new file mode 100644 index 000000000000..ef9e3c3005ce --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/dynamodb.js @@ -0,0 +1,73 @@ +import {DynamoDBClient, ExecuteStatementCommand, BatchExecuteStatementCommand, DynamoDB} from "@aws-sdk/client-dynamodb"; +const express = require('express'); + +const app = express(); +const region = 'us-east-1'; + +app.post('/partiql/v3/execute', async (req, res) => { + const client = new DynamoDBClient({}); + let maliciousInput = req.body.data; // $ Source + + const statement = `SELECT * FROM Users WHERE username = '${maliciousInput}'`; + const command = new ExecuteStatementCommand({ + Statement: statement + }); + await client.send(command); // $ Alert + + const updateStatement = "UPDATE Users SET status = 'active' WHERE id = " + maliciousInput; + const updateCommand = new ExecuteStatementCommand({ + Statement: updateStatement + }); + await client.send(updateCommand); // $ Alert + + + const batchInput = { + Statements: [{ + Statement: `SELECT * FROM Users WHERE username = '${maliciousInput}'` + }, + { + Statement: "UPDATE Users SET role = 'user' WHERE username = bob" + } + ] + }; + + const batchCommand = new BatchExecuteStatementCommand(batchInput); + await client.send(batchCommand); // $ MISSING: Alert + + const batchInput2 = { + Statements: maliciousInput.map(input => ({ + Statement: `SELECT * FROM SensitiveData WHERE username = '${input}'` + })) + }; + + const batchCommand2 = new BatchExecuteStatementCommand(batchInput2); + await client.send(batchCommand2); // $ MISSING: Alert + + const client2 = new DynamoDB({}); + await client2.send(command); // $ Alert + await client2.send(batchCommand); // $ MISSING: Alert +}); + +app.post('/partiql/v2/execute', async (req, res) => { + const AWS = require('aws-sdk'); + const dynamodb = new AWS.DynamoDB({ + region: 'us-east-1' + }); + let maliciousInput = req.body.data; // $ Source + const params = { + Statement: `SELECT * FROM Users WHERE username = '${maliciousInput}'` // $ Alert + }; + + dynamodb.executeStatement(params, function(err, data) {}); + const params2 = { + Statements: [{ + Statement: `SELECT * FROM Users WHERE username = '${maliciousInput}'` // $ Alert + }, + { + Statement: `SELECT * FROM Users WHERE username = '${maliciousInput}'` // $ Alert + } + ] + }; + + dynamodb.batchExecuteStatement(params2, function(err, data) {}); +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/rds-client.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/rds-client.js new file mode 100644 index 000000000000..35d41e145f98 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/rds-client.js @@ -0,0 +1,68 @@ +const { RDSDataClient, BatchExecuteStatementCommand, ExecuteStatementCommand, ExecuteSqlCommand } = require("@aws-sdk/client-rds-data"); +const express = require('express'); +const bodyParser = require('body-parser'); +const app = express(); +app.use(bodyParser.json()); + +app.post('/v3/rds/all', async (req, res) => { + const userQuery = req.body.query; // $ Source + const userQueries = req.body.queries; // $ MISSING: Source + + const client = new RDSDataClient({ region: "us-east-1" }); + + const params1 = { + resourceArn: "arn:aws:rds:us-east-1:123456789012:cluster:my-aurora-cluster", + secretArn: "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret", + database: "userDatabase", + sql: userQuery + }; + await client.send(new ExecuteStatementCommand(params1)); // $ Alert + + const params2 = { + resourceArn: "arn:aws:rds:us-east-1:123456789012:cluster:my-aurora-cluster", + secretArn: "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret", + database: "userDatabase", + parameterSets: userQueries.map(sql => ({ sql })) + }; + await client.send(new BatchExecuteStatementCommand(params2)); // $ MISSING: Alert + + const params = { + resourceArn: "...", + secretArn: "...", + database: "userDatabase", + sqlStatements: userQuery + }; + + await client.send(new ExecuteSqlCommand(params)); // $ Alert + + res.end(); +}); + +const AWS = require('aws-sdk'); + +app.post('/v2/rds/all', async (req, res) => { + const userQuery = req.body.query; // $ Source + const userQueries = req.body.queries; // $ Source + + const rdsData = new AWS.RDSDataService({ region: "us-east-1" }); + + const params1 = { + resourceArn: "arn:aws:rds:us-east-1:123456789012:cluster:my-aurora-cluster", + secretArn: "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret", + database: "userDatabase", + sql: userQuery // $ Alert + }; + await rdsData.executeStatement(params1).promise(); + + const params2 = { + resourceArn: "arn:aws:rds:us-east-1:123456789012:cluster:my-aurora-cluster", + secretArn: "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret", + database: "userDatabase", + parameterSets: userQueries.map(sql => ({ sql })) // $ Alert + }; + await rdsData.batchExecuteStatement(params2).promise(); + + res.end(); +}); + +app.listen(3000);