diff --git a/.github/workflows/csv-coverage-pr-artifacts.yml b/.github/workflows/csv-coverage-pr-artifacts.yml
new file mode 100644
index 00000000000..0941adba3c3
--- /dev/null
+++ b/.github/workflows/csv-coverage-pr-artifacts.yml
@@ -0,0 +1,83 @@
+name: Check framework coverage changes
+
+on:
+ pull_request:
+ paths:
+ - '.github/workflows/csv-coverage-pr-comment.yml'
+ - '*/ql/src/**/*.ql'
+ - '*/ql/src/**/*.qll'
+ - 'misc/scripts/library-coverage/*.py'
+ # input data files
+ - '*/documentation/library-coverage/cwe-sink.csv'
+ - '*/documentation/library-coverage/frameworks.csv'
+ branches:
+ - main
+ - 'rc/*'
+
+jobs:
+ generate:
+ name: Generate framework coverage artifacts
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJSON(github.event) }}
+ run: echo "$GITHUB_CONTEXT"
+ - name: Clone self (github/codeql) - MERGE
+ uses: actions/checkout@v2
+ with:
+ path: merge
+ - name: Clone self (github/codeql) - BASE
+ uses: actions/checkout@v2
+ with:
+ ref: ${{ github.event.pull_request.base.sha }}
+ path: base
+ - name: Set up Python 3.8
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.8
+ - name: Download CodeQL CLI
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ gh release download --repo "github/codeql-cli-binaries" --pattern "codeql-linux64.zip"
+ - name: Unzip CodeQL CLI
+ run: unzip -d codeql-cli codeql-linux64.zip
+ - name: Generate CSV files on merge and base of the PR
+ run: |
+ echo "Running generator on ${{github.sha}}"
+ PATH="$PATH:codeql-cli/codeql" python merge/misc/scripts/library-coverage/generate-report.py ci merge merge
+ mkdir out_merge
+ cp framework-coverage-*.csv out_merge/
+ cp framework-coverage-*.rst out_merge/
+
+ echo "Running generator on ${{github.event.pull_request.base.sha}}"
+ PATH="$PATH:codeql-cli/codeql" python base/misc/scripts/library-coverage/generate-report.py ci base base
+ mkdir out_base
+ cp framework-coverage-*.csv out_base/
+ cp framework-coverage-*.rst out_base/
+ - name: Upload CSV package list
+ uses: actions/upload-artifact@v2
+ with:
+ name: csv-framework-coverage-merge
+ path: |
+ out_merge/framework-coverage-*.csv
+ out_merge/framework-coverage-*.rst
+ - name: Upload CSV package list
+ uses: actions/upload-artifact@v2
+ with:
+ name: csv-framework-coverage-base
+ path: |
+ out_base/framework-coverage-*.csv
+ out_base/framework-coverage-*.rst
+ - name: Save PR number
+ run: |
+ mkdir -p pr
+ echo ${{ github.event.pull_request.number }} > pr/NR
+ - name: Upload PR number
+ uses: actions/upload-artifact@v2
+ with:
+ name: pr
+ path: pr/
diff --git a/.github/workflows/csv-coverage-pr-comment.yml b/.github/workflows/csv-coverage-pr-comment.yml
new file mode 100644
index 00000000000..3fdb8963d05
--- /dev/null
+++ b/.github/workflows/csv-coverage-pr-comment.yml
@@ -0,0 +1,65 @@
+name: Comment on PR with framework coverage changes
+
+on:
+ workflow_run:
+ workflows: ["Check framework coverage changes"]
+ types:
+ - completed
+
+jobs:
+ check:
+ name: Check framework coverage differences and comment
+ runs-on: ubuntu-latest
+ if: >
+ ${{ github.event.workflow_run.event == 'pull_request' &&
+ github.event.workflow_run.conclusion == 'success' }}
+
+ steps:
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJSON(github.event) }}
+ run: echo "$GITHUB_CONTEXT"
+ - name: Clone self (github/codeql)
+ uses: actions/checkout@v2
+ - name: Set up Python 3.8
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.8
+
+ # download artifacts from the PR job:
+
+ - name: Download artifact - MERGE
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ RUN_ID: ${{ github.event.workflow_run.id }}
+ run: |
+ gh run download --name "csv-framework-coverage-merge" --dir "out_merge" "$RUN_ID"
+
+ - name: Download artifact - BASE
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ RUN_ID: ${{ github.event.workflow_run.id }}
+ run: |
+ gh run download --name "csv-framework-coverage-base" --dir "out_base" "$RUN_ID"
+
+ - name: Download artifact - PR
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ RUN_ID: ${{ github.event.workflow_run.id }}
+ run: |
+ gh run download --name "pr" --dir "pr" "$RUN_ID"
+
+ - name: Check coverage files
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ RUN_ID: ${{ github.event.workflow_run.id }}
+ run: |
+ PR=$(cat "pr/NR")
+ python misc/scripts/library-coverage/compare-files-comment-pr.py \
+ out_merge out_base comparison.md "$GITHUB_REPOSITORY" "$PR" "$RUN_ID"
+ - name: Upload comparison results
+ uses: actions/upload-artifact@v2
+ with:
+ name: comparison
+ path: |
+ comparison.md
diff --git a/.github/workflows/csv-coverage-timeseries.yml b/.github/workflows/csv-coverage-timeseries.yml
new file mode 100644
index 00000000000..e7c01623e04
--- /dev/null
+++ b/.github/workflows/csv-coverage-timeseries.yml
@@ -0,0 +1,42 @@
+name: Build framework coverage timeseries reports
+
+on:
+ workflow_dispatch:
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Clone self (github/codeql)
+ uses: actions/checkout@v2
+ with:
+ path: script
+ - name: Clone self (github/codeql) for analysis
+ uses: actions/checkout@v2
+ with:
+ path: codeqlModels
+ fetch-depth: 0
+ - name: Set up Python 3.8
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.8
+ - name: Download CodeQL CLI
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ gh release download --repo "github/codeql-cli-binaries" --pattern "codeql-linux64.zip"
+ - name: Unzip CodeQL CLI
+ run: unzip -d codeql-cli codeql-linux64.zip
+ - name: Build modeled package list
+ run: |
+ CLI=$(realpath "codeql-cli/codeql")
+ echo $CLI
+ PATH="$PATH:$CLI" python script/misc/scripts/library-coverage/generate-timeseries.py codeqlModels
+ - name: Upload timeseries CSV
+ uses: actions/upload-artifact@v2
+ with:
+ name: framework-coverage-timeseries
+ path: framework-coverage-timeseries-*.csv
+
diff --git a/.github/workflows/csv-coverage.yml b/.github/workflows/csv-coverage.yml
index 54c172d66d3..c7ab92eb0f3 100644
--- a/.github/workflows/csv-coverage.yml
+++ b/.github/workflows/csv-coverage.yml
@@ -1,4 +1,4 @@
-name: Build/check CSV flow coverage report
+name: Build framework coverage reports
on:
workflow_dispatch:
@@ -6,22 +6,6 @@ on:
qlModelShaOverride:
description: 'github/codeql repo SHA used for looking up the CSV models'
required: false
- push:
- branches:
- - main
- - 'rc/**'
- pull_request:
- paths:
- - '.github/workflows/csv-coverage.yml'
- - '*/ql/src/**/*.ql'
- - '*/ql/src/**/*.qll'
- - 'misc/scripts/library-coverage/*.py'
- # input data files
- - '*/documentation/library-coverage/cwe-sink.csv'
- - '*/documentation/library-coverage/frameworks.csv'
- # coverage report files
- - '*/documentation/library-coverage/flow-model-coverage.csv'
- - '*/documentation/library-coverage/flow-model-coverage.rst'
jobs:
build:
@@ -33,28 +17,20 @@ jobs:
uses: actions/checkout@v2
with:
path: script
- - name: Clone self (github/codeql) at a given SHA for analysis
- if: github.event.inputs.qlModelShaOverride != ''
- uses: actions/checkout@v2
- with:
- path: codeqlModels
- ref: github.event.inputs.qlModelShaOverride
- name: Clone self (github/codeql) for analysis
- if: github.event.inputs.qlModelShaOverride == ''
uses: actions/checkout@v2
with:
path: codeqlModels
+ ref: ${{ github.event.inputs.qlModelShaOverride || github.ref }}
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Download CodeQL CLI
- uses: dsaltares/fetch-gh-release-asset@aa37ae5c44d3c9820bc12fe675e8670ecd93bd1c
- with:
- repo: "github/codeql-cli-binaries"
- version: "latest"
- file: "codeql-linux64.zip"
- token: ${{ secrets.GITHUB_TOKEN }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ gh release download --repo "github/codeql-cli-binaries" --pattern "codeql-linux64.zip"
- name: Unzip CodeQL CLI
run: unzip -d codeql-cli codeql-linux64.zip
- name: Build modeled package list
@@ -63,15 +39,11 @@ jobs:
- name: Upload CSV package list
uses: actions/upload-artifact@v2
with:
- name: csv-flow-model-coverage
- path: flow-model-coverage-*.csv
+ name: framework-coverage-csv
+ path: framework-coverage-*.csv
- name: Upload RST package list
uses: actions/upload-artifact@v2
with:
- name: rst-flow-model-coverage
- path: flow-model-coverage-*.rst
- # - name: Check coverage files
- # if: github.event.pull_request
- # run: |
- # python script/misc/scripts/library-coverage/compare-files.py codeqlModels
+ name: framework-coverage-rst
+ path: framework-coverage-*.rst
diff --git a/cpp/ql/src/Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql b/cpp/ql/src/Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql
index ecf739b91be..c8bf3842773 100644
--- a/cpp/ql/src/Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql
+++ b/cpp/ql/src/Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/offset-use-before-range-check
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.2
* @precision medium
* @tags reliability
* security
diff --git a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql
index 24cd9dc16fd..3ef487fbec2 100644
--- a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql
+++ b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/descriptor-may-not-be-closed
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags efficiency
* security
* external/cwe/cwe-775
diff --git a/cpp/ql/src/Critical/DescriptorNeverClosed.ql b/cpp/ql/src/Critical/DescriptorNeverClosed.ql
index 331d787be62..85e41ad1928 100644
--- a/cpp/ql/src/Critical/DescriptorNeverClosed.ql
+++ b/cpp/ql/src/Critical/DescriptorNeverClosed.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/descriptor-never-closed
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags efficiency
* security
* external/cwe/cwe-775
diff --git a/cpp/ql/src/Critical/FileMayNotBeClosed.ql b/cpp/ql/src/Critical/FileMayNotBeClosed.ql
index 395bac61f0b..af38b437778 100644
--- a/cpp/ql/src/Critical/FileMayNotBeClosed.ql
+++ b/cpp/ql/src/Critical/FileMayNotBeClosed.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/file-may-not-be-closed
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags efficiency
* security
* external/cwe/cwe-775
diff --git a/cpp/ql/src/Critical/FileNeverClosed.ql b/cpp/ql/src/Critical/FileNeverClosed.ql
index eeeed80af92..b9e71978359 100644
--- a/cpp/ql/src/Critical/FileNeverClosed.ql
+++ b/cpp/ql/src/Critical/FileNeverClosed.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/file-never-closed
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags efficiency
* security
* external/cwe/cwe-775
diff --git a/cpp/ql/src/Critical/GlobalUseBeforeInit.ql b/cpp/ql/src/Critical/GlobalUseBeforeInit.ql
index 7abfaeb9ebe..6c3435eeba9 100644
--- a/cpp/ql/src/Critical/GlobalUseBeforeInit.ql
+++ b/cpp/ql/src/Critical/GlobalUseBeforeInit.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/global-use-before-init
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 7.8
* @tags reliability
* security
* external/cwe/cwe-457
diff --git a/cpp/ql/src/Critical/InconsistentNullnessTesting.ql b/cpp/ql/src/Critical/InconsistentNullnessTesting.ql
index b356c64b3fc..da64be1fdb9 100644
--- a/cpp/ql/src/Critical/InconsistentNullnessTesting.ql
+++ b/cpp/ql/src/Critical/InconsistentNullnessTesting.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/inconsistent-nullness-testing
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @tags reliability
* security
* external/cwe/cwe-476
diff --git a/cpp/ql/src/Critical/InitialisationNotRun.ql b/cpp/ql/src/Critical/InitialisationNotRun.ql
index d4bb90962f7..ba575c55921 100644
--- a/cpp/ql/src/Critical/InitialisationNotRun.ql
+++ b/cpp/ql/src/Critical/InitialisationNotRun.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/initialization-not-run
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 7.5
* @tags reliability
* security
* external/cwe/cwe-456
diff --git a/cpp/ql/src/Critical/LateNegativeTest.ql b/cpp/ql/src/Critical/LateNegativeTest.ql
index 98d1d7cba2b..5de36fcc5a9 100644
--- a/cpp/ql/src/Critical/LateNegativeTest.ql
+++ b/cpp/ql/src/Critical/LateNegativeTest.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/late-negative-test
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @tags reliability
* security
* external/cwe/cwe-823
diff --git a/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql b/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql
index 3726117615e..51467b52be8 100644
--- a/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql
+++ b/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/memory-may-not-be-freed
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @tags efficiency
* security
* external/cwe/cwe-401
diff --git a/cpp/ql/src/Critical/MemoryNeverFreed.ql b/cpp/ql/src/Critical/MemoryNeverFreed.ql
index 89ca2245d7f..e9593e9d749 100644
--- a/cpp/ql/src/Critical/MemoryNeverFreed.ql
+++ b/cpp/ql/src/Critical/MemoryNeverFreed.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/memory-never-freed
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @tags efficiency
* security
* external/cwe/cwe-401
diff --git a/cpp/ql/src/Critical/MissingNegativityTest.ql b/cpp/ql/src/Critical/MissingNegativityTest.ql
index 937510afec6..a4409f2dabf 100644
--- a/cpp/ql/src/Critical/MissingNegativityTest.ql
+++ b/cpp/ql/src/Critical/MissingNegativityTest.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/missing-negativity-test
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @tags reliability
* security
* external/cwe/cwe-823
diff --git a/cpp/ql/src/Critical/MissingNullTest.ql b/cpp/ql/src/Critical/MissingNullTest.ql
index dcd45f2baf1..b50d06a8dd1 100644
--- a/cpp/ql/src/Critical/MissingNullTest.ql
+++ b/cpp/ql/src/Critical/MissingNullTest.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/missing-null-test
* @problem.severity recommendation
- * @security-severity 3.6
+ * @security-severity 7.5
* @tags reliability
* security
* external/cwe/cwe-476
diff --git a/cpp/ql/src/Critical/NewFreeMismatch.ql b/cpp/ql/src/Critical/NewFreeMismatch.ql
index 09356762e43..19b9b197214 100644
--- a/cpp/ql/src/Critical/NewFreeMismatch.ql
+++ b/cpp/ql/src/Critical/NewFreeMismatch.ql
@@ -3,7 +3,7 @@
* @description An object that was allocated with 'malloc' or 'new' is being freed using a mismatching 'free' or 'delete'.
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision high
* @id cpp/new-free-mismatch
* @tags reliability
diff --git a/cpp/ql/src/Critical/OverflowCalculated.ql b/cpp/ql/src/Critical/OverflowCalculated.ql
index 01cb7b3eaa3..d8a08cc6a69 100644
--- a/cpp/ql/src/Critical/OverflowCalculated.ql
+++ b/cpp/ql/src/Critical/OverflowCalculated.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/overflow-calculated
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.8
* @tags reliability
* security
* external/cwe/cwe-131
diff --git a/cpp/ql/src/Critical/OverflowDestination.ql b/cpp/ql/src/Critical/OverflowDestination.ql
index c89ec46cb42..94d46001660 100644
--- a/cpp/ql/src/Critical/OverflowDestination.ql
+++ b/cpp/ql/src/Critical/OverflowDestination.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/overflow-destination
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision low
* @tags reliability
* security
diff --git a/cpp/ql/src/Critical/OverflowStatic.ql b/cpp/ql/src/Critical/OverflowStatic.ql
index d287f43b1c8..7c447c12323 100644
--- a/cpp/ql/src/Critical/OverflowStatic.ql
+++ b/cpp/ql/src/Critical/OverflowStatic.ql
@@ -4,7 +4,7 @@
* may result in a buffer overflow.
* @kind problem
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision medium
* @id cpp/static-buffer-overflow
* @tags reliability
diff --git a/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql b/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql
index 72ff93e24ab..40082ad5d9c 100644
--- a/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql
+++ b/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/return-stack-allocated-object
* @problem.severity warning
- * @security-severity 2.9
+ * @security-severity 2.1
* @tags reliability
* security
* external/cwe/cwe-562
diff --git a/cpp/ql/src/Critical/SizeCheck.ql b/cpp/ql/src/Critical/SizeCheck.ql
index 7fff35cf717..e7a00ea3621 100644
--- a/cpp/ql/src/Critical/SizeCheck.ql
+++ b/cpp/ql/src/Critical/SizeCheck.ql
@@ -4,7 +4,7 @@
* an instance of the type of the pointer may result in a buffer overflow
* @kind problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 8.1
* @precision medium
* @id cpp/allocation-too-small
* @tags reliability
diff --git a/cpp/ql/src/Critical/SizeCheck2.ql b/cpp/ql/src/Critical/SizeCheck2.ql
index f9a09b66352..eb3aec9a5fe 100644
--- a/cpp/ql/src/Critical/SizeCheck2.ql
+++ b/cpp/ql/src/Critical/SizeCheck2.ql
@@ -4,7 +4,7 @@
* multiple instances of the type of the pointer may result in a buffer overflow
* @kind problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 8.1
* @precision medium
* @id cpp/suspicious-allocation-size
* @tags reliability
diff --git a/cpp/ql/src/Critical/UseAfterFree.ql b/cpp/ql/src/Critical/UseAfterFree.ql
index 1b714267ef1..d770a42b3c2 100644
--- a/cpp/ql/src/Critical/UseAfterFree.ql
+++ b/cpp/ql/src/Critical/UseAfterFree.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/use-after-free
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.3
* @tags reliability
* security
* external/cwe/cwe-416
diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql b/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql
index 1037e4d9063..5a7389205f9 100644
--- a/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql
+++ b/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql
@@ -6,7 +6,7 @@
* to a larger type.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision very-high
* @id cpp/bad-addition-overflow-check
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql b/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
index 941fecc453d..03ad085b6d3 100644
--- a/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
+++ b/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
@@ -4,7 +4,7 @@
* be a sign that the result can overflow the type converted from.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision high
* @id cpp/integer-multiplication-cast-to-long
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql b/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
index 6da994e6729..7911049599a 100644
--- a/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
+++ b/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
@@ -5,7 +5,7 @@
* unsigned integer values.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision high
* @id cpp/signed-overflow-check
* @tags correctness
diff --git a/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql b/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql
index 19e50a3f368..9032919da44 100644
--- a/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql
+++ b/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql
@@ -6,7 +6,7 @@
* use the width of the base type, leading to misaligned reads.
* @kind path-problem
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision high
* @id cpp/upcast-array-pointer-arithmetic
* @tags correctness
diff --git a/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql b/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql
index f480501f7ba..f00dfa2213b 100644
--- a/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql
+++ b/cpp/ql/src/Likely Bugs/Format/NonConstantFormat.ql
@@ -6,7 +6,7 @@
* from an untrusted source, this can be used for exploits.
* @kind problem
* @problem.severity recommendation
- * @security-severity 6.9
+ * @security-severity 9.3
* @precision high
* @id cpp/non-constant-format
* @tags maintainability
diff --git a/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql b/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
index 78427655c22..7da8db7f226 100644
--- a/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
+++ b/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
@@ -3,7 +3,7 @@
* @description Using the return value from snprintf without proper checks can cause overflow.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision high
* @id cpp/overflowing-snprintf
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql b/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql
index 1147c6c66a1..cc3510ee5eb 100644
--- a/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql
+++ b/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql
@@ -4,7 +4,7 @@
* a source of security issues.
* @kind problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 5.0
* @precision high
* @id cpp/wrong-number-format-arguments
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
index d1624e484fe..a7306e401e4 100644
--- a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
+++ b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
@@ -4,7 +4,7 @@
* behavior.
* @kind problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision high
* @id cpp/wrong-type-format-argument
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.ql b/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.ql
index 1b20aa1b224..30664869adc 100644
--- a/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.ql
+++ b/cpp/ql/src/Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/incorrect-not-operator-usage
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision medium
* @tags security
* external/cwe/cwe-480
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql b/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
index 1af4ba839b5..61d7a266d86 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
@@ -3,7 +3,7 @@
* @description Using alloca in a loop can lead to a stack overflow
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision high
* @id cpp/alloca-in-loop
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql b/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql
index c72086060fd..7f1541f7ea8 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/improper-null-termination
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags security
* external/cwe/cwe-170
* external/cwe/cwe-665
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql b/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql
index 3035d3ba2ea..e11d114d1fb 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql
@@ -4,7 +4,7 @@
* on undefined behavior and may lead to memory corruption.
* @kind problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 2.1
* @precision high
* @id cpp/pointer-overflow-check
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.ql b/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.ql
index 4a9fc949f89..8e7bc5bfcf4 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/StrncpyFlippedArgs.ql
@@ -4,7 +4,7 @@
* as the third argument may result in a buffer overflow.
* @kind problem
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision medium
* @id cpp/bad-strncpy-size
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousCallToStrncat.ql b/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousCallToStrncat.ql
index 28742629b37..644c48622a2 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousCallToStrncat.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousCallToStrncat.ql
@@ -3,7 +3,7 @@
* @description Calling 'strncat' with an incorrect size argument may result in a buffer overflow.
* @kind problem
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision medium
* @id cpp/unsafe-strncat
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousSizeof.ql b/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousSizeof.ql
index 9198cd0497e..a80af562bda 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousSizeof.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/SuspiciousSizeof.ql
@@ -5,7 +5,7 @@
* the machine pointer size.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id cpp/suspicious-sizeof
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql b/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql
index 94e230e8838..5861167659f 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/uninitialized-local
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision medium
* @tags security
* external/cwe/cwe-665
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/UnsafeUseOfStrcat.ql b/cpp/ql/src/Likely Bugs/Memory Management/UnsafeUseOfStrcat.ql
index 2eb8d0b4060..d0b0f7f1e71 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/UnsafeUseOfStrcat.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/UnsafeUseOfStrcat.ql
@@ -4,7 +4,7 @@
* may result in a buffer overflow
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @id cpp/unsafe-strcat
* @tags reliability
diff --git a/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.ql b/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.ql
index 2702cbdcea7..9ddf445f4bf 100644
--- a/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.ql
+++ b/cpp/ql/src/Likely Bugs/OO/SelfAssignmentCheck.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/self-assignment-check
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.0
* @tags reliability
* security
* external/cwe/cwe-826
diff --git a/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql b/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql
index 746a2761e49..04325e8497e 100644
--- a/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql
+++ b/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql
@@ -6,7 +6,7 @@
* @kind path-problem
* @id cpp/unsafe-use-of-this
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision very-high
* @tags correctness
* language-features
diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql
index 3196143c5d1..bc53015c905 100644
--- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql
+++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql
@@ -7,7 +7,7 @@
* undefined data.
* @kind problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 5.0
* @precision very-high
* @id cpp/too-few-arguments
* @tags correctness
diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql
index 77c4f149cac..33c31972295 100644
--- a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql
+++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/memset-may-be-deleted
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 7.8
* @precision high
* @tags security
* external/cwe/cwe-14
diff --git a/cpp/ql/src/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.ql b/cpp/ql/src/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.ql
index 0396d5c7bb0..47a0bf14b7f 100644
--- a/cpp/ql/src/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.ql
+++ b/cpp/ql/src/Security/CWE/CWE-020/IRUntrustedDataToExternalAPI.ql
@@ -5,7 +5,7 @@
* @kind path-problem
* @precision low
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags security external/cwe/cwe-20
*/
diff --git a/cpp/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql b/cpp/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql
index 196fe57f74b..b85a5b26a7f 100644
--- a/cpp/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql
+++ b/cpp/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql
@@ -5,7 +5,7 @@
* @kind path-problem
* @precision low
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags security external/cwe/cwe-20
*/
diff --git a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql
index c96b6f6dc5b..5e22506d03a 100644
--- a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql
+++ b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql
@@ -4,7 +4,7 @@
* attacker to access unexpected resources.
* @kind path-problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision medium
* @id cpp/path-injection
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql b/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql
index d3020406f15..5f516eec83b 100644
--- a/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql
+++ b/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql
@@ -5,7 +5,7 @@
* to command injection.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision low
* @id cpp/command-line-injection
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql
index 0b56e972320..bb38609927e 100644
--- a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql
+++ b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql
@@ -4,7 +4,7 @@
* allows for a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 6.1
* @precision high
* @id cpp/cgi-xss
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql
index 1e4536f0942..a3f935170d7 100644
--- a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql
+++ b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql
@@ -5,7 +5,7 @@
* to SQL Injection.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 8.8
* @precision high
* @id cpp/sql-injection
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql b/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql
index 3aba72ed741..e75f62b0eb7 100644
--- a/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql
+++ b/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql
@@ -5,7 +5,7 @@
* commands.
* @kind path-problem
* @problem.severity warning
- * @security-severity 6.0
+ * @security-severity 8.2
* @precision medium
* @id cpp/uncontrolled-process-operation
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-119/OverflowBuffer.ql b/cpp/ql/src/Security/CWE/CWE-119/OverflowBuffer.ql
index c61498ac2e0..1c903081baf 100644
--- a/cpp/ql/src/Security/CWE/CWE-119/OverflowBuffer.ql
+++ b/cpp/ql/src/Security/CWE/CWE-119/OverflowBuffer.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/overflow-buffer
* @problem.severity recommendation
- * @security-severity 10.0
+ * @security-severity 9.3
* @tags security
* external/cwe/cwe-119
* external/cwe/cwe-121
diff --git a/cpp/ql/src/Security/CWE/CWE-120/BadlyBoundedWrite.ql b/cpp/ql/src/Security/CWE/CWE-120/BadlyBoundedWrite.ql
index 01d8d8db4e2..247606c683d 100644
--- a/cpp/ql/src/Security/CWE/CWE-120/BadlyBoundedWrite.ql
+++ b/cpp/ql/src/Security/CWE/CWE-120/BadlyBoundedWrite.ql
@@ -5,7 +5,7 @@
* overflow.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.3
* @precision high
* @id cpp/badly-bounded-write
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-120/OverrunWrite.ql b/cpp/ql/src/Security/CWE/CWE-120/OverrunWrite.ql
index 6832561e10c..ac4144d1c6f 100644
--- a/cpp/ql/src/Security/CWE/CWE-120/OverrunWrite.ql
+++ b/cpp/ql/src/Security/CWE/CWE-120/OverrunWrite.ql
@@ -4,7 +4,7 @@
* of data written may overflow.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.3
* @precision medium
* @id cpp/overrunning-write
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-120/OverrunWriteFloat.ql b/cpp/ql/src/Security/CWE/CWE-120/OverrunWriteFloat.ql
index 73ef5e62fb2..27adab9b06c 100644
--- a/cpp/ql/src/Security/CWE/CWE-120/OverrunWriteFloat.ql
+++ b/cpp/ql/src/Security/CWE/CWE-120/OverrunWriteFloat.ql
@@ -5,7 +5,7 @@
* take extreme values.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.3
* @precision medium
* @id cpp/overrunning-write-with-float
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql b/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql
index 656b52b03bf..b9922da9c75 100644
--- a/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql
+++ b/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql
@@ -4,7 +4,7 @@
* of data written may overflow.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.3
* @precision medium
* @id cpp/unbounded-write
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql b/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql
index 3dacc443a74..842798102bd 100644
--- a/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql
+++ b/cpp/ql/src/Security/CWE/CWE-121/UnterminatedVarargsCall.ql
@@ -5,7 +5,7 @@
* a specific value to terminate the argument list.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id cpp/unterminated-variadic-call
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql b/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql
index 59498017b1f..0621def4d98 100644
--- a/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql
+++ b/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/unclear-array-index-validation
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @tags security
* external/cwe/cwe-129
*/
diff --git a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
index b31213b09f3..1780c2a0199 100644
--- a/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
+++ b/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
@@ -5,7 +5,7 @@
* terminator can cause a buffer overrun.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cpp/no-space-for-terminator
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
index 0593679c3f5..f24510bba05 100644
--- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
+++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
@@ -5,7 +5,7 @@
* or data representation problems.
* @kind path-problem
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 9.3
* @precision high
* @id cpp/tainted-format-string
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql
index 67853b9e361..d2f5243d4a4 100644
--- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql
+++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql
@@ -5,7 +5,7 @@
* or data representation problems.
* @kind path-problem
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 9.3
* @precision high
* @id cpp/tainted-format-string-through-global
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql
index ad4d0389f0c..e3634734b5e 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql
@@ -4,7 +4,7 @@
* not validated can cause overflows.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.6
* @precision low
* @id cpp/tainted-arithmetic
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
index 359ac7a0d1a..fd486efdab0 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
@@ -4,7 +4,7 @@
* validated can cause overflows.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.6
* @precision medium
* @id cpp/uncontrolled-arithmetic
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql
index 9addbab5c1c..35668953acc 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/arithmetic-with-extreme-values
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.6
* @precision low
* @tags security
* reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
index 1ec3c6554fe..6636d100746 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
@@ -5,7 +5,7 @@
* @id cpp/comparison-with-wider-type
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision high
* @tags reliability
* security
diff --git a/cpp/ql/src/Security/CWE/CWE-190/IntegerOverflowTainted.ql b/cpp/ql/src/Security/CWE/CWE-190/IntegerOverflowTainted.ql
index 7e4880ffca6..bc0dff58244 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/IntegerOverflowTainted.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/IntegerOverflowTainted.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/integer-overflow-tainted
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision low
* @tags security
* external/cwe/cwe-190
diff --git a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql
index 765a2519a38..585875798cc 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql
@@ -4,7 +4,7 @@
* user can result in integer overflow.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision medium
* @id cpp/uncontrolled-allocation-size
* @tags reliability
diff --git a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql
index ddd7bf3430f..5be71472c92 100644
--- a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql
+++ b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/unsigned-difference-expression-compared-zero
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @tags security
* correctness
diff --git a/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql b/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
index bde1e265690..67ba5b0c45b 100644
--- a/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
+++ b/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cpp/hresult-boolean-conversion
* @problem.severity error
- * @security-severity 4.2
+ * @security-severity 7.5
* @precision high
* @tags security
* external/cwe/cwe-253
diff --git a/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql b/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql
index 7cdd5c34b8b..814c6aff21b 100644
--- a/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql
+++ b/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql
@@ -5,7 +5,7 @@
* vulnerable to spoofing attacks.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.8
+ * @security-severity 8.1
* @precision medium
* @id cpp/user-controlled-bypass
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql b/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql
index 6785700d077..696c5764fcd 100644
--- a/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql
+++ b/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql
@@ -4,7 +4,7 @@
* to an attacker.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.5
* @precision medium
* @id cpp/cleartext-storage-buffer
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql b/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql
index fcf2a00435e..aa90ff9567c 100644
--- a/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql
+++ b/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql
@@ -4,7 +4,7 @@
* to an attacker.
* @kind problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision medium
* @id cpp/cleartext-storage-file
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql b/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql
index ccb67f54d3a..bb9135a92ff 100644
--- a/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql
+++ b/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql
@@ -4,7 +4,7 @@
* database can expose it to an attacker.
* @kind path-problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision medium
* @id cpp/cleartext-storage-database
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql b/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql
index 848adfd7adc..aef114bcc4e 100644
--- a/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql
+++ b/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql
@@ -4,7 +4,7 @@
* an attacker to compromise security.
* @kind problem
* @problem.severity error
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision medium
* @id cpp/weak-cryptographic-algorithm
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-327/OpenSslHeartbleed.ql b/cpp/ql/src/Security/CWE/CWE-327/OpenSslHeartbleed.ql
index 5ee196994ac..38067ae200c 100644
--- a/cpp/ql/src/Security/CWE/CWE-327/OpenSslHeartbleed.ql
+++ b/cpp/ql/src/Security/CWE/CWE-327/OpenSslHeartbleed.ql
@@ -4,7 +4,7 @@
* attackers to retrieve portions of memory.
* @kind problem
* @problem.severity error
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision very-high
* @id cpp/openssl-heartbleed
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql b/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
index 7d19e323f2b..f5bed0bee64 100644
--- a/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
+++ b/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
@@ -5,7 +5,7 @@
* the two operations.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.7
* @precision medium
* @id cpp/toctou-race-condition
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql b/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql
index 73e0d8794ad..7c540e9d313 100644
--- a/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql
+++ b/cpp/ql/src/Security/CWE/CWE-428/UnsafeCreateProcessCall.ql
@@ -4,7 +4,7 @@
* @id cpp/unsafe-create-process-call
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision medium
* @msrc.severity important
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql
index 3d6c54e33ae..c6a797929bb 100644
--- a/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql
+++ b/cpp/ql/src/Security/CWE/CWE-457/ConditionallyUninitializedVariable.ql
@@ -5,7 +5,7 @@
* state, and reading the variable may result in undefined behavior.
* @kind problem
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 7.8
* @opaque-id SM02313
* @id cpp/conditionally-uninitialized-variable
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql
index a582813ed5f..ce99ce1ebce 100644
--- a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql
+++ b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql
@@ -4,7 +4,7 @@
* can cause buffer overflow conditions.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id cpp/suspicious-pointer-scaling
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingChar.ql b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingChar.ql
index c1bfb9c4ee9..5b7e3379929 100644
--- a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingChar.ql
+++ b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingChar.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/incorrect-pointer-scaling-char
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision low
* @tags security
* external/cwe/cwe-468
diff --git a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingVoid.ql b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingVoid.ql
index aa267a25f4e..460c98bf1e3 100644
--- a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingVoid.ql
+++ b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingVoid.ql
@@ -4,7 +4,7 @@
* can cause buffer overflow conditions.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id cpp/suspicious-pointer-scaling-void
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql b/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
index 7532f7e9fcf..4ac00fc42c6 100644
--- a/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
+++ b/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
@@ -5,7 +5,7 @@
* implicitly scaled.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision high
* @id cpp/suspicious-add-sizeof
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql b/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql
index ead50c9620e..bbe3b0805e1 100644
--- a/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql
+++ b/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql
@@ -5,7 +5,7 @@
* attack plan.
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 6.5
* @precision medium
* @id cpp/system-data-exposure
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.ql b/cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.ql
index 321684dc93c..65551a1f138 100644
--- a/cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.ql
+++ b/cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/incorrect-string-type-conversion
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision high
* @tags security
* external/cwe/cwe-704
diff --git a/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql b/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql
index 67dce658ed8..1fd55a02d01 100644
--- a/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql
+++ b/cpp/ql/src/Security/CWE/CWE-732/DoNotCreateWorldWritable.ql
@@ -3,7 +3,7 @@
* @description Creating a file that is world-writable can allow an attacker to write to the file.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision medium
* @id cpp/world-writable-file-creation
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql b/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql
index 72399cec376..bf673826347 100644
--- a/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql
+++ b/cpp/ql/src/Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql
@@ -7,7 +7,7 @@
* @id cpp/unsafe-dacl-security-descriptor
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision high
* @tags security
* external/cwe/cwe-732
diff --git a/cpp/ql/src/Security/CWE/CWE-764/LockOrderCycle.ql b/cpp/ql/src/Security/CWE/CWE-764/LockOrderCycle.ql
index 2a0d765f239..cd5d8771807 100644
--- a/cpp/ql/src/Security/CWE/CWE-764/LockOrderCycle.ql
+++ b/cpp/ql/src/Security/CWE/CWE-764/LockOrderCycle.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/lock-order-cycle
* @problem.severity error
- * @security-severity 6.9
+ * @security-severity 5.0
* @tags security
* external/cwe/cwe-764
* external/cwe/cwe-833
diff --git a/cpp/ql/src/Security/CWE/CWE-764/TwiceLocked.ql b/cpp/ql/src/Security/CWE/CWE-764/TwiceLocked.ql
index c32e747f3e4..051ad2eeeea 100644
--- a/cpp/ql/src/Security/CWE/CWE-764/TwiceLocked.ql
+++ b/cpp/ql/src/Security/CWE/CWE-764/TwiceLocked.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/twice-locked
* @problem.severity error
- * @security-severity 6.9
+ * @security-severity 5.0
* @precision low
* @tags security
* external/cwe/cwe-764
diff --git a/cpp/ql/src/Security/CWE/CWE-764/UnreleasedLock.ql b/cpp/ql/src/Security/CWE/CWE-764/UnreleasedLock.ql
index 8f3d9e92149..dd224352b12 100644
--- a/cpp/ql/src/Security/CWE/CWE-764/UnreleasedLock.ql
+++ b/cpp/ql/src/Security/CWE/CWE-764/UnreleasedLock.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cpp/unreleased-lock
* @problem.severity error
- * @security-severity 6.9
+ * @security-severity 5.0
* @precision low
* @tags security
* external/cwe/cwe-764
diff --git a/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql b/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql
index 08a5ceb49db..64505ee8283 100644
--- a/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql
+++ b/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql
@@ -5,7 +5,7 @@
* attack.
* @kind path-problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision medium
* @id cpp/tainted-permissions-check
* @tags security
diff --git a/cpp/ql/src/Security/CWE/CWE-835/InfiniteLoopWithUnsatisfiableExitCondition.ql b/cpp/ql/src/Security/CWE/CWE-835/InfiniteLoopWithUnsatisfiableExitCondition.ql
index cd85179d14d..3db5e15874b 100644
--- a/cpp/ql/src/Security/CWE/CWE-835/InfiniteLoopWithUnsatisfiableExitCondition.ql
+++ b/cpp/ql/src/Security/CWE/CWE-835/InfiniteLoopWithUnsatisfiableExitCondition.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cpp/infinite-loop-with-unsatisfiable-exit-condition
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @tags security
* external/cwe/cwe-835
*/
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll
index 4e1cd281488..a55e65a81f6 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll
@@ -168,7 +168,13 @@ module Consistency {
msg = "ArgumentNode is missing PostUpdateNode."
}
- query predicate postWithInFlow(PostUpdateNode n, string msg) {
+ // This predicate helps the compiler forget that in some languages
+ // it is impossible for a `PostUpdateNode` to be the target of
+ // `simpleLocalFlowStep`.
+ private predicate isPostUpdateNode(Node n) { n instanceof PostUpdateNode or none() }
+
+ query predicate postWithInFlow(Node n, string msg) {
+ isPostUpdateNode(n) and
simpleLocalFlowStep(_, n) and
msg = "PostUpdateNode should not be the target of local flow."
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll
index 4e1cd281488..a55e65a81f6 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll
@@ -168,7 +168,13 @@ module Consistency {
msg = "ArgumentNode is missing PostUpdateNode."
}
- query predicate postWithInFlow(PostUpdateNode n, string msg) {
+ // This predicate helps the compiler forget that in some languages
+ // it is impossible for a `PostUpdateNode` to be the target of
+ // `simpleLocalFlowStep`.
+ private predicate isPostUpdateNode(Node n) { n instanceof PostUpdateNode or none() }
+
+ query predicate postWithInFlow(Node n, string msg) {
+ isPostUpdateNode(n) and
simpleLocalFlowStep(_, n) and
msg = "PostUpdateNode should not be the target of local flow."
}
diff --git a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll
index e086b810478..d351bac89a8 100644
--- a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll
+++ b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll
@@ -181,14 +181,14 @@ private int getEndOfColumnPosition(int start, string content) {
min(string name, int cand |
exists(TNamedColumn(name)) and
cand = content.indexOf(name + ":") and
- cand > start
+ cand >= start
|
cand
)
or
not exists(string name |
exists(TNamedColumn(name)) and
- content.indexOf(name + ":") > start
+ content.indexOf(name + ":") >= start
) and
result = content.length()
}
diff --git a/csharp/change-notes/2021-06-15-effective-visibility.md b/csharp/change-notes/2021-06-15-effective-visibility.md
new file mode 100644
index 00000000000..f14e338079a
--- /dev/null
+++ b/csharp/change-notes/2021-06-15-effective-visibility.md
@@ -0,0 +1,2 @@
+lgtm,codescanning
+* The `isEffectivelyPrivate`, `isEffectivelyInternal` and `isEffectivelyPublic` predicates on `Modifiable` have been reworked to handle `private protected` and `internal protected` visibilities and explicitly implemented interfaces.
\ No newline at end of file
diff --git a/csharp/change-notes/2021-06-15-unsafe-non-source-code.md b/csharp/change-notes/2021-06-15-unsafe-non-source-code.md
new file mode 100644
index 00000000000..8e45080b132
--- /dev/null
+++ b/csharp/change-notes/2021-06-15-unsafe-non-source-code.md
@@ -0,0 +1,2 @@
+lgtm,codescanning
+* The `Modifiable::isUnsafe` predicate has been fixed to handle symbols that are not extracted from source code.
\ No newline at end of file
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs
index 806e73e3590..3d6cb01837e 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs
@@ -72,15 +72,11 @@ namespace Semmle.Extraction.CSharp.Entities
public static void ExtractModifiers(Context cx, TextWriter trapFile, IEntity key, ISymbol symbol)
{
- var interfaceDefinition = symbol.ContainingType is not null
- && symbol.ContainingType.Kind == SymbolKind.NamedType
- && symbol.ContainingType.TypeKind == TypeKind.Interface;
-
HasAccessibility(cx, trapFile, key, symbol.DeclaredAccessibility);
if (symbol.Kind == SymbolKind.ErrorType)
trapFile.has_modifiers(key, Modifier.Create(cx, Accessibility.Public));
- if (symbol.IsAbstract && (symbol.Kind != SymbolKind.NamedType || ((INamedTypeSymbol)symbol).TypeKind != TypeKind.Interface) && !interfaceDefinition)
+ if (symbol.IsAbstract && (symbol.Kind != SymbolKind.NamedType || ((INamedTypeSymbol)symbol).TypeKind != TypeKind.Interface))
HasModifier(cx, trapFile, key, "abstract");
if (symbol.IsSealed)
@@ -94,10 +90,6 @@ namespace Semmle.Extraction.CSharp.Entities
if (symbol.IsVirtual)
HasModifier(cx, trapFile, key, "virtual");
- // For some reason, method in interfaces are "virtual", not "abstract"
- if (symbol.IsAbstract && interfaceDefinition)
- HasModifier(cx, trapFile, key, "virtual");
-
if (symbol.Kind == SymbolKind.Field && ((IFieldSymbol)symbol).IsReadOnly)
HasModifier(cx, trapFile, key, "readonly");
diff --git a/csharp/ql/src/Bad Practices/UseOfHtmlInputHidden.ql b/csharp/ql/src/Bad Practices/UseOfHtmlInputHidden.ql
index 09ee699163f..47097fea753 100644
--- a/csharp/ql/src/Bad Practices/UseOfHtmlInputHidden.ql
+++ b/csharp/ql/src/Bad Practices/UseOfHtmlInputHidden.ql
@@ -3,7 +3,7 @@
* @description Finds uses of hidden fields on forms
* @kind problem
* @problem.severity recommendation
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision medium
* @id cs/web/html-hidden-input
* @tags security
diff --git a/csharp/ql/src/Configuration/EmptyPasswordInConfigurationFile.ql b/csharp/ql/src/Configuration/EmptyPasswordInConfigurationFile.ql
index e7dee2143c1..9fe53d2cc90 100644
--- a/csharp/ql/src/Configuration/EmptyPasswordInConfigurationFile.ql
+++ b/csharp/ql/src/Configuration/EmptyPasswordInConfigurationFile.ql
@@ -3,7 +3,7 @@
* @description Finds empty passwords in configuration files.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision medium
* @id cs/empty-password-in-configuration
* @tags security
diff --git a/csharp/ql/src/Configuration/PasswordInConfigurationFile.ql b/csharp/ql/src/Configuration/PasswordInConfigurationFile.ql
index eb4756ea962..8e4dd77febd 100644
--- a/csharp/ql/src/Configuration/PasswordInConfigurationFile.ql
+++ b/csharp/ql/src/Configuration/PasswordInConfigurationFile.ql
@@ -3,7 +3,7 @@
* @description Finds passwords in configuration files.
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision medium
* @id cs/password-in-configuration
* @tags security
diff --git a/csharp/ql/src/Input Validation/UseOfFileUpload.ql b/csharp/ql/src/Input Validation/UseOfFileUpload.ql
index 4eb96e2c072..e936962ad51 100644
--- a/csharp/ql/src/Input Validation/UseOfFileUpload.ql
+++ b/csharp/ql/src/Input Validation/UseOfFileUpload.ql
@@ -3,7 +3,7 @@
* @description Finds uses of file upload
* @kind problem
* @problem.severity recommendation
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/web/file-upload
* @tags security
diff --git a/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransform.ql b/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransform.ql
index 1ee9c4a2bfa..392c3e843d7 100644
--- a/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransform.ql
+++ b/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransform.ql
@@ -5,7 +5,7 @@
* but under some circumstances may also result in incorrect results.
* @kind problem
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 7.0
* @precision medium
* @id cs/thread-unsafe-icryptotransform-field-in-class
* @tags concurrency
diff --git a/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransformLambda.ql b/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransformLambda.ql
index 33f8a8ab47c..7787a1bd622 100644
--- a/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransformLambda.ql
+++ b/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransformLambda.ql
@@ -6,7 +6,7 @@
* but under some circumstances may also result in incorrect results.
* @kind problem
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 7.0
* @precision medium
* @id cs/thread-unsafe-icryptotransform-captured-in-lambda
* @tags concurrency
diff --git a/csharp/ql/src/Security Features/CWE-011/ASPNetDebug.ql b/csharp/ql/src/Security Features/CWE-011/ASPNetDebug.ql
index c9b2112b488..3bccd9b0331 100644
--- a/csharp/ql/src/Security Features/CWE-011/ASPNetDebug.ql
+++ b/csharp/ql/src/Security Features/CWE-011/ASPNetDebug.ql
@@ -4,7 +4,7 @@
* debug builds provide additional information useful to a malicious attacker.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.5
* @precision very-high
* @id cs/web/debug-binary
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-016/ASPNetMaxRequestLength.ql b/csharp/ql/src/Security Features/CWE-016/ASPNetMaxRequestLength.ql
index 6c58c910089..5a527c96084 100644
--- a/csharp/ql/src/Security Features/CWE-016/ASPNetMaxRequestLength.ql
+++ b/csharp/ql/src/Security Features/CWE-016/ASPNetMaxRequestLength.ql
@@ -4,7 +4,7 @@
* denial-of-service attacks.
* @kind problem
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 7.5
* @id cs/web/large-max-request-length
* @tags security
* frameworks/asp.net
diff --git a/csharp/ql/src/Security Features/CWE-016/ASPNetPagesValidateRequest.ql b/csharp/ql/src/Security Features/CWE-016/ASPNetPagesValidateRequest.ql
index 362b8a70ebe..f093a888446 100644
--- a/csharp/ql/src/Security Features/CWE-016/ASPNetPagesValidateRequest.ql
+++ b/csharp/ql/src/Security Features/CWE-016/ASPNetPagesValidateRequest.ql
@@ -3,7 +3,7 @@
* @description ASP.NET pages should not disable the built-in request validation.
* @kind problem
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 7.5
* @id cs/web/request-validation-disabled
* @tags security
* frameworks/asp.net
diff --git a/csharp/ql/src/Security Features/CWE-016/ASPNetRequestValidationMode.ql b/csharp/ql/src/Security Features/CWE-016/ASPNetRequestValidationMode.ql
index a270a5928bb..dd9ed5218ff 100644
--- a/csharp/ql/src/Security Features/CWE-016/ASPNetRequestValidationMode.ql
+++ b/csharp/ql/src/Security Features/CWE-016/ASPNetRequestValidationMode.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cs/insecure-request-validation-mode
* @problem.severity warning
- * @security-severity 6.9
+ * @security-severity 7.5
* @tags security
* external/cwe/cwe-016
*/
diff --git a/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql b/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql
index cda257234ab..6148f0f6ae9 100644
--- a/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql
+++ b/csharp/ql/src/Security Features/CWE-020/RuntimeChecksBypass.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cs/serialization-check-bypass
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision medium
* @tags security
* external/cwe/cwe-20
diff --git a/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql b/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql
index c378e31d8aa..ca21947ee9b 100644
--- a/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql
+++ b/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql
@@ -5,7 +5,7 @@
* @kind path-problem
* @precision low
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags security external/cwe/cwe-20
*/
diff --git a/csharp/ql/src/Security Features/CWE-022/TaintedPath.ql b/csharp/ql/src/Security Features/CWE-022/TaintedPath.ql
index bf75ab47904..b3659df1617 100644
--- a/csharp/ql/src/Security Features/CWE-022/TaintedPath.ql
+++ b/csharp/ql/src/Security Features/CWE-022/TaintedPath.ql
@@ -3,7 +3,7 @@
* @description Accessing paths influenced by users can allow an attacker to access unexpected resources.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision high
* @id cs/path-injection
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql b/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql
index 5f6855701ed..4203f94cb33 100644
--- a/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql
+++ b/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql
@@ -6,7 +6,7 @@
* @kind path-problem
* @id cs/zipslip
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision high
* @tags security
* external/cwe/cwe-022
diff --git a/csharp/ql/src/Security Features/CWE-078/CommandInjection.ql b/csharp/ql/src/Security Features/CWE-078/CommandInjection.ql
index 7056d3222f2..f66f86f290e 100644
--- a/csharp/ql/src/Security Features/CWE-078/CommandInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-078/CommandInjection.ql
@@ -4,7 +4,7 @@
* user to change the meaning of the command.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/command-line-injection
* @tags correctness
diff --git a/csharp/ql/src/Security Features/CWE-078/StoredCommandInjection.ql b/csharp/ql/src/Security Features/CWE-078/StoredCommandInjection.ql
index b8264b4d8a1..b15dd866e72 100644
--- a/csharp/ql/src/Security Features/CWE-078/StoredCommandInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-078/StoredCommandInjection.ql
@@ -4,7 +4,7 @@
* user to change the meaning of the command.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @id cs/stored-command-line-injection
* @tags correctness
diff --git a/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql b/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql
index fcf10553a6a..548e72dbd56 100644
--- a/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql
+++ b/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql
@@ -4,7 +4,7 @@
* scripting vulnerability if the data was originally user-provided.
* @kind path-problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 6.1
* @precision medium
* @id cs/web/stored-xss
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-079/XSS.ql b/csharp/ql/src/Security Features/CWE-079/XSS.ql
index d58a7828a6f..34a7ea87a72 100644
--- a/csharp/ql/src/Security Features/CWE-079/XSS.ql
+++ b/csharp/ql/src/Security Features/CWE-079/XSS.ql
@@ -4,7 +4,7 @@
* allows for a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 6.1
* @precision high
* @id cs/web/xss
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-089/SecondOrderSqlInjection.ql b/csharp/ql/src/Security Features/CWE-089/SecondOrderSqlInjection.ql
index fde86253edc..7b9bfef0ef9 100644
--- a/csharp/ql/src/Security Features/CWE-089/SecondOrderSqlInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-089/SecondOrderSqlInjection.ql
@@ -4,7 +4,7 @@
* of malicious SQL code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 8.8
* @precision medium
* @id cs/second-order-sql-injection
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-089/SqlInjection.ql b/csharp/ql/src/Security Features/CWE-089/SqlInjection.ql
index 456e36db36e..e818eaeb0af 100644
--- a/csharp/ql/src/Security Features/CWE-089/SqlInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-089/SqlInjection.ql
@@ -4,7 +4,7 @@
* malicious SQL code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 8.8
* @precision high
* @id cs/sql-injection
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-090/LDAPInjection.ql b/csharp/ql/src/Security Features/CWE-090/LDAPInjection.ql
index e0e667ed8da..4878b449eb8 100644
--- a/csharp/ql/src/Security Features/CWE-090/LDAPInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-090/LDAPInjection.ql
@@ -4,7 +4,7 @@
* malicious LDAP code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/ldap-injection
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-090/StoredLDAPInjection.ql b/csharp/ql/src/Security Features/CWE-090/StoredLDAPInjection.ql
index 0c705fbce33..c2791b8f2b1 100644
--- a/csharp/ql/src/Security Features/CWE-090/StoredLDAPInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-090/StoredLDAPInjection.ql
@@ -4,7 +4,7 @@
* insertion of malicious LDAP code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @id cs/stored-ldap-injection
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-091/XMLInjection.ql b/csharp/ql/src/Security Features/CWE-091/XMLInjection.ql
index 4e2548895ad..1ad4fad9e41 100644
--- a/csharp/ql/src/Security Features/CWE-091/XMLInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-091/XMLInjection.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cs/xml-injection
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision high
* @tags security
* external/cwe/cwe-091
diff --git a/csharp/ql/src/Security Features/CWE-094/CodeInjection.ql b/csharp/ql/src/Security Features/CWE-094/CodeInjection.ql
index 8c711400d61..2d85c9aabbc 100644
--- a/csharp/ql/src/Security Features/CWE-094/CodeInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-094/CodeInjection.ql
@@ -4,7 +4,7 @@
* malicious code.
* @kind path-problem
* @problem.severity error
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision high
* @id cs/code-injection
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-099/ResourceInjection.ql b/csharp/ql/src/Security Features/CWE-099/ResourceInjection.ql
index ca32d21b3cb..dee11139a58 100644
--- a/csharp/ql/src/Security Features/CWE-099/ResourceInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-099/ResourceInjection.ql
@@ -4,7 +4,7 @@
* malicious user providing an unintended resource.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/resource-injection
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-112/MissingXMLValidation.ql b/csharp/ql/src/Security Features/CWE-112/MissingXMLValidation.ql
index b13d357980b..24716639aa5 100644
--- a/csharp/ql/src/Security Features/CWE-112/MissingXMLValidation.ql
+++ b/csharp/ql/src/Security Features/CWE-112/MissingXMLValidation.ql
@@ -4,7 +4,7 @@
* schema.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 3.6
+ * @security-severity 4.3
* @precision high
* @id cs/xml/missing-validation
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-114/AssemblyPathInjection.ql b/csharp/ql/src/Security Features/CWE-114/AssemblyPathInjection.ql
index 54b578d3072..9c3b9b21bac 100644
--- a/csharp/ql/src/Security Features/CWE-114/AssemblyPathInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-114/AssemblyPathInjection.ql
@@ -6,7 +6,7 @@
* @kind problem
* @id cs/assembly-path-injection
* @problem.severity error
- * @security-severity 6.0
+ * @security-severity 8.2
* @precision high
* @tags security
* external/cwe/cwe-114
diff --git a/csharp/ql/src/Security Features/CWE-117/LogForging.ql b/csharp/ql/src/Security Features/CWE-117/LogForging.ql
index b7642d4e15a..4c31a02c86e 100644
--- a/csharp/ql/src/Security Features/CWE-117/LogForging.ql
+++ b/csharp/ql/src/Security Features/CWE-117/LogForging.ql
@@ -4,7 +4,7 @@
* insertion of forged log entries by a malicious user.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision high
* @id cs/log-forging
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-119/LocalUnvalidatedArithmetic.ql b/csharp/ql/src/Security Features/CWE-119/LocalUnvalidatedArithmetic.ql
index 263429e6995..57d6e500134 100644
--- a/csharp/ql/src/Security Features/CWE-119/LocalUnvalidatedArithmetic.ql
+++ b/csharp/ql/src/Security Features/CWE-119/LocalUnvalidatedArithmetic.ql
@@ -5,7 +5,7 @@
* to return any value.
* @kind problem
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision high
* @id cs/unvalidated-local-pointer-arithmetic
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-134/UncontrolledFormatString.ql b/csharp/ql/src/Security Features/CWE-134/UncontrolledFormatString.ql
index 7494412e3b3..d079c4f9ac9 100644
--- a/csharp/ql/src/Security Features/CWE-134/UncontrolledFormatString.ql
+++ b/csharp/ql/src/Security Features/CWE-134/UncontrolledFormatString.ql
@@ -4,7 +4,7 @@
* and cause a denial of service.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.9
+ * @security-severity 9.3
* @precision high
* @id cs/uncontrolled-format-string
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-201/ExposureInTransmittedData.ql b/csharp/ql/src/Security Features/CWE-201/ExposureInTransmittedData.ql
index fa40db533d5..ed3e5da0b1f 100644
--- a/csharp/ql/src/Security Features/CWE-201/ExposureInTransmittedData.ql
+++ b/csharp/ql/src/Security Features/CWE-201/ExposureInTransmittedData.ql
@@ -3,7 +3,7 @@
* @description Transmitting sensitive information to the user is a potential security risk.
* @kind path-problem
* @problem.severity error
- * @security-severity 1.4
+ * @security-severity 4.3
* @precision high
* @id cs/sensitive-data-transmission
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-209/ExceptionInformationExposure.ql b/csharp/ql/src/Security Features/CWE-209/ExceptionInformationExposure.ql
index 23e72e4e5e9..34f45c0c64e 100644
--- a/csharp/ql/src/Security Features/CWE-209/ExceptionInformationExposure.ql
+++ b/csharp/ql/src/Security Features/CWE-209/ExceptionInformationExposure.ql
@@ -5,7 +5,7 @@
* developing a subsequent exploit.
* @kind path-problem
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 5.4
* @precision high
* @id cs/information-exposure-through-exception
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-248/MissingASPNETGlobalErrorHandler.ql b/csharp/ql/src/Security Features/CWE-248/MissingASPNETGlobalErrorHandler.ql
index 323630d0c4e..416608b9115 100644
--- a/csharp/ql/src/Security Features/CWE-248/MissingASPNETGlobalErrorHandler.ql
+++ b/csharp/ql/src/Security Features/CWE-248/MissingASPNETGlobalErrorHandler.ql
@@ -4,7 +4,7 @@
* a global error handler, otherwise they may leak exception information.
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision high
* @id cs/web/missing-global-error-handler
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-312/CleartextStorage.ql b/csharp/ql/src/Security Features/CWE-312/CleartextStorage.ql
index b19ca4ff1bd..6e957788776 100644
--- a/csharp/ql/src/Security Features/CWE-312/CleartextStorage.ql
+++ b/csharp/ql/src/Security Features/CWE-312/CleartextStorage.ql
@@ -4,7 +4,7 @@
* attacker.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.5
* @precision high
* @id cs/cleartext-storage-of-sensitive-information
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-321/HardcodedEncryptionKey.ql b/csharp/ql/src/Security Features/CWE-321/HardcodedEncryptionKey.ql
index ff244adee95..20298cac6f7 100644
--- a/csharp/ql/src/Security Features/CWE-321/HardcodedEncryptionKey.ql
+++ b/csharp/ql/src/Security Features/CWE-321/HardcodedEncryptionKey.ql
@@ -4,7 +4,7 @@
* @kind problem
* @id cs/hardcoded-key
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 8.1
* @tags security
* external/cwe/cwe-320
*/
diff --git a/csharp/ql/src/Security Features/CWE-321/HardcodedSymmetricEncryptionKey.ql b/csharp/ql/src/Security Features/CWE-321/HardcodedSymmetricEncryptionKey.ql
index 2cabc38aa8b..4de91b9a214 100644
--- a/csharp/ql/src/Security Features/CWE-321/HardcodedSymmetricEncryptionKey.ql
+++ b/csharp/ql/src/Security Features/CWE-321/HardcodedSymmetricEncryptionKey.ql
@@ -4,7 +4,7 @@
* @kind path-problem
* @id cs/hard-coded-symmetric-encryption-key
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 7.5
* @tags security
* external/cwe/cwe-321
*/
diff --git a/csharp/ql/src/Security Features/CWE-327/DontInstallRootCert.ql b/csharp/ql/src/Security Features/CWE-327/DontInstallRootCert.ql
index a843008e582..a4f4d63d6ee 100644
--- a/csharp/ql/src/Security Features/CWE-327/DontInstallRootCert.ql
+++ b/csharp/ql/src/Security Features/CWE-327/DontInstallRootCert.ql
@@ -5,7 +5,7 @@
* @kind path-problem
* @id cs/adding-cert-to-root-store
* @problem.severity error
- * @security-severity 5.2
+ * @security-severity 7.5
* @tags security
* external/cwe/cwe-327
*/
diff --git a/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.ql b/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.ql
index a16358b1f90..fd4a37f7ee3 100644
--- a/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.ql
+++ b/csharp/ql/src/Security Features/CWE-327/InsecureSQLConnection.ql
@@ -4,7 +4,7 @@
* @kind path-problem
* @id cs/insecure-sql-connection
* @problem.severity error
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision medium
* @tags security
* external/cwe/cwe-327
diff --git a/csharp/ql/src/Security Features/CWE-352/MissingAntiForgeryTokenValidation.ql b/csharp/ql/src/Security Features/CWE-352/MissingAntiForgeryTokenValidation.ql
index fb40413716f..e50566d6ca9 100644
--- a/csharp/ql/src/Security Features/CWE-352/MissingAntiForgeryTokenValidation.ql
+++ b/csharp/ql/src/Security Features/CWE-352/MissingAntiForgeryTokenValidation.ql
@@ -4,7 +4,7 @@
* allows a malicious attacker to submit a request on behalf of the user.
* @kind problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 8.8
* @precision high
* @id cs/web/missing-token-validation
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-359/ExposureOfPrivateInformation.ql b/csharp/ql/src/Security Features/CWE-359/ExposureOfPrivateInformation.ql
index 20323b66bb9..de509e38a3c 100644
--- a/csharp/ql/src/Security Features/CWE-359/ExposureOfPrivateInformation.ql
+++ b/csharp/ql/src/Security Features/CWE-359/ExposureOfPrivateInformation.ql
@@ -4,7 +4,7 @@
* unauthorized persons.
* @kind path-problem
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 6.5
* @precision high
* @id cs/exposure-of-sensitive-information
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-384/AbandonSession.ql b/csharp/ql/src/Security Features/CWE-384/AbandonSession.ql
index 75daa5fc10c..87dab081188 100644
--- a/csharp/ql/src/Security Features/CWE-384/AbandonSession.ql
+++ b/csharp/ql/src/Security Features/CWE-384/AbandonSession.ql
@@ -5,7 +5,7 @@
* their session.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision high
* @id cs/session-reuse
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql
index 87757be5400..67f3ae1d7b8 100644
--- a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql
+++ b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql
@@ -4,7 +4,7 @@
* overlay their own UI on top of the site by using an iframe.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.5
* @precision high
* @id cs/web/missing-x-frame-options
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql b/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql
index 76035d9fcba..c0d0d7ad00b 100644
--- a/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql
+++ b/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cs/deserialized-delegate
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @tags security
* external/cwe/cwe-502
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
index 338347c0887..68c4822544d 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
@@ -5,7 +5,7 @@
* @kind problem
* @id cs/unsafe-deserialization
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision low
* @tags security
* external/cwe/cwe-502
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
index 32981563ab6..949daa4986c 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
@@ -5,7 +5,7 @@
* @kind path-problem
* @id cs/unsafe-deserialization-untrusted-input
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @tags security
* external/cwe/cwe-502
diff --git a/csharp/ql/src/Security Features/CWE-548/ASPNetDirectoryListing.ql b/csharp/ql/src/Security Features/CWE-548/ASPNetDirectoryListing.ql
index 82532ed40e0..9416fa32f0a 100644
--- a/csharp/ql/src/Security Features/CWE-548/ASPNetDirectoryListing.ql
+++ b/csharp/ql/src/Security Features/CWE-548/ASPNetDirectoryListing.ql
@@ -3,7 +3,7 @@
* @description Directory browsing should not be enabled in production as it can leak sensitive information.
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 6.5
* @precision very-high
* @id cs/web/directory-browse-enabled
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-601/UrlRedirect.ql b/csharp/ql/src/Security Features/CWE-601/UrlRedirect.ql
index 37594e7cf72..18aaed307b5 100644
--- a/csharp/ql/src/Security Features/CWE-601/UrlRedirect.ql
+++ b/csharp/ql/src/Security Features/CWE-601/UrlRedirect.ql
@@ -4,7 +4,7 @@
* may cause redirection to malicious web sites.
* @kind path-problem
* @problem.severity error
- * @security-severity 2.7
+ * @security-severity 6.1
* @precision high
* @id cs/web/unvalidated-url-redirection
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-611/UntrustedDataInsecureXml.ql b/csharp/ql/src/Security Features/CWE-611/UntrustedDataInsecureXml.ql
index 2b37eb33390..29bd2386316 100644
--- a/csharp/ql/src/Security Features/CWE-611/UntrustedDataInsecureXml.ql
+++ b/csharp/ql/src/Security Features/CWE-611/UntrustedDataInsecureXml.ql
@@ -3,7 +3,7 @@
* @description Untrusted XML is read with an insecure resolver and DTD processing enabled.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.1
* @precision high
* @id cs/xml/insecure-dtd-handling
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-611/UseXmlSecureResolver.ql b/csharp/ql/src/Security Features/CWE-611/UseXmlSecureResolver.ql
index 1073c873d8c..afda204d115 100644
--- a/csharp/ql/src/Security Features/CWE-611/UseXmlSecureResolver.ql
+++ b/csharp/ql/src/Security Features/CWE-611/UseXmlSecureResolver.ql
@@ -4,7 +4,7 @@
* be restricted using a secure resolver or disabling DTD processing.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.1
* @precision low
* @id cs/insecure-xml-read
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-614/RequireSSL.ql b/csharp/ql/src/Security Features/CWE-614/RequireSSL.ql
index 49dd6e52e13..3e5e64ca22e 100644
--- a/csharp/ql/src/Security Features/CWE-614/RequireSSL.ql
+++ b/csharp/ql/src/Security Features/CWE-614/RequireSSL.ql
@@ -5,7 +5,7 @@
* is used at all times.
* @kind problem
* @problem.severity error
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision high
* @id cs/web/requiressl-not-set
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-643/StoredXPathInjection.ql b/csharp/ql/src/Security Features/CWE-643/StoredXPathInjection.ql
index 5d3ee1db4e7..c63ed490d09 100644
--- a/csharp/ql/src/Security Features/CWE-643/StoredXPathInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-643/StoredXPathInjection.ql
@@ -4,7 +4,7 @@
* user is vulnerable to insertion of malicious code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @id cs/xml/stored-xpath-injection
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-643/XPathInjection.ql b/csharp/ql/src/Security Features/CWE-643/XPathInjection.ql
index a158ccfab69..15a5cf11be9 100644
--- a/csharp/ql/src/Security Features/CWE-643/XPathInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-643/XPathInjection.ql
@@ -4,7 +4,7 @@
* malicious code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/xml/xpath-injection
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-730/ReDoS.ql b/csharp/ql/src/Security Features/CWE-730/ReDoS.ql
index 79ade61af90..7a933dc18bd 100644
--- a/csharp/ql/src/Security Features/CWE-730/ReDoS.ql
+++ b/csharp/ql/src/Security Features/CWE-730/ReDoS.ql
@@ -4,7 +4,7 @@
* exponential time on certain input.
* @kind path-problem
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision high
* @id cs/redos
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql b/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql
index 5aca2ad9c49..e358e59b612 100644
--- a/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql
+++ b/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql
@@ -5,7 +5,7 @@
* exponential time on certain inputs.
* @kind path-problem
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision high
* @id cs/regex-injection
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql b/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql
index 0aa5f9026d1..697ce99d127 100644
--- a/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql
+++ b/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql
@@ -3,7 +3,7 @@
* @description Credentials are hard-coded in a connection string in the source code of the application.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/hardcoded-connection-string-credentials
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql b/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql
index 7b183189921..34961ac0953 100644
--- a/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql
+++ b/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql
@@ -3,7 +3,7 @@
* @description Credentials are hard coded in the source code of the application.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id cs/hardcoded-credentials
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-807/ConditionalBypass.ql b/csharp/ql/src/Security Features/CWE-807/ConditionalBypass.ql
index 3922c262031..9069c77b603 100644
--- a/csharp/ql/src/Security Features/CWE-807/ConditionalBypass.ql
+++ b/csharp/ql/src/Security Features/CWE-807/ConditionalBypass.ql
@@ -4,7 +4,7 @@
* passing through authentication systems.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision high
* @id cs/user-controlled-bypass
* @tags security
diff --git a/csharp/ql/src/Security Features/CWE-838/InappropriateEncoding.ql b/csharp/ql/src/Security Features/CWE-838/InappropriateEncoding.ql
index 8b8bd478031..75982a02943 100644
--- a/csharp/ql/src/Security Features/CWE-838/InappropriateEncoding.ql
+++ b/csharp/ql/src/Security Features/CWE-838/InappropriateEncoding.ql
@@ -4,7 +4,7 @@
* pose a security risk.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision low
* @id cs/inappropriate-encoding
* @tags security
diff --git a/csharp/ql/src/Security Features/CookieWithOverlyBroadDomain.ql b/csharp/ql/src/Security Features/CookieWithOverlyBroadDomain.ql
index 472a87441ed..ca59bd42bdc 100644
--- a/csharp/ql/src/Security Features/CookieWithOverlyBroadDomain.ql
+++ b/csharp/ql/src/Security Features/CookieWithOverlyBroadDomain.ql
@@ -3,7 +3,7 @@
* @description Finds cookies with an overly broad domain.
* @kind problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 9.3
* @precision high
* @id cs/web/broad-cookie-domain
* @tags security
diff --git a/csharp/ql/src/Security Features/CookieWithOverlyBroadPath.ql b/csharp/ql/src/Security Features/CookieWithOverlyBroadPath.ql
index ec6953f72e1..bfb2f24f360 100644
--- a/csharp/ql/src/Security Features/CookieWithOverlyBroadPath.ql
+++ b/csharp/ql/src/Security Features/CookieWithOverlyBroadPath.ql
@@ -3,7 +3,7 @@
* @description Finds cookies with an overly broad path.
* @kind problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 9.3
* @precision high
* @id cs/web/broad-cookie-path
* @tags security
diff --git a/csharp/ql/src/Security Features/Encryption using ECB.ql b/csharp/ql/src/Security Features/Encryption using ECB.ql
index 72c63b9c565..ec9719aa781 100644
--- a/csharp/ql/src/Security Features/Encryption using ECB.ql
+++ b/csharp/ql/src/Security Features/Encryption using ECB.ql
@@ -3,7 +3,7 @@
* @description Highlights uses of the encryption mode 'CipherMode.ECB'. This mode should normally not be used because it is vulnerable to replay attacks.
* @kind problem
* @problem.severity warning
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision high
* @id cs/ecb-encryption
* @tags security
diff --git a/csharp/ql/src/Security Features/HeaderCheckingDisabled.ql b/csharp/ql/src/Security Features/HeaderCheckingDisabled.ql
index 94d01609100..631b408a5a3 100644
--- a/csharp/ql/src/Security Features/HeaderCheckingDisabled.ql
+++ b/csharp/ql/src/Security Features/HeaderCheckingDisabled.ql
@@ -3,7 +3,7 @@
* @description Finds places where header checking is disabled.
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 6.1
* @precision high
* @id cs/web/disabled-header-checking
* @tags security
diff --git a/csharp/ql/src/Security Features/InadequateRSAPadding.ql b/csharp/ql/src/Security Features/InadequateRSAPadding.ql
index ddeb9b370f6..2968b39b6b3 100644
--- a/csharp/ql/src/Security Features/InadequateRSAPadding.ql
+++ b/csharp/ql/src/Security Features/InadequateRSAPadding.ql
@@ -3,7 +3,7 @@
* @description Finds uses of RSA encryption with inadequate padding.
* @kind problem
* @problem.severity warning
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision high
* @id cs/inadequate-rsa-padding
* @tags security
diff --git a/csharp/ql/src/Security Features/InsecureRandomness.ql b/csharp/ql/src/Security Features/InsecureRandomness.ql
index 434f8c287f2..b618bff07a5 100644
--- a/csharp/ql/src/Security Features/InsecureRandomness.ql
+++ b/csharp/ql/src/Security Features/InsecureRandomness.ql
@@ -5,7 +5,7 @@
* be generated.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision high
* @id cs/insecure-randomness
* @tags security
diff --git a/csharp/ql/src/Security Features/InsufficientKeySize.ql b/csharp/ql/src/Security Features/InsufficientKeySize.ql
index 70caea4b179..9829d1dcf4d 100644
--- a/csharp/ql/src/Security Features/InsufficientKeySize.ql
+++ b/csharp/ql/src/Security Features/InsufficientKeySize.ql
@@ -3,7 +3,7 @@
* @description Finds uses of encryption algorithms with too small a key size
* @kind problem
* @problem.severity warning
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision high
* @id cs/insufficient-key-size
* @tags security
diff --git a/csharp/ql/src/Security Features/PersistentCookie.ql b/csharp/ql/src/Security Features/PersistentCookie.ql
index c7041cb7a36..be99e63b906 100644
--- a/csharp/ql/src/Security Features/PersistentCookie.ql
+++ b/csharp/ql/src/Security Features/PersistentCookie.ql
@@ -3,7 +3,7 @@
* @description Persistent cookies are vulnerable to attacks.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.2
* @precision high
* @id cs/web/persistent-cookie
* @tags security
diff --git a/csharp/ql/src/Security Features/WeakEncryption.ql b/csharp/ql/src/Security Features/WeakEncryption.ql
index b6d543d6de7..9bf7fae7356 100644
--- a/csharp/ql/src/Security Features/WeakEncryption.ql
+++ b/csharp/ql/src/Security Features/WeakEncryption.ql
@@ -3,7 +3,7 @@
* @description Finds uses of encryption algorithms that are weak and obsolete
* @kind problem
* @problem.severity warning
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision high
* @id cs/weak-encryption
* @tags security
diff --git a/csharp/ql/src/semmle/code/csharp/Member.qll b/csharp/ql/src/semmle/code/csharp/Member.qll
index 520df43cfb8..191c7c85516 100644
--- a/csharp/ql/src/semmle/code/csharp/Member.qll
+++ b/csharp/ql/src/semmle/code/csharp/Member.qll
@@ -86,32 +86,69 @@ class Modifiable extends Declaration, @modifiable {
predicate isConst() { this.hasModifier("const") }
/** Holds if this declaration is `unsafe`. */
- predicate isUnsafe() { this.hasModifier("unsafe") }
+ predicate isUnsafe() {
+ this.hasModifier("unsafe") or
+ this.(Parameterizable).getAParameter().getType() instanceof PointerType or
+ this.(Property).getType() instanceof PointerType or
+ this.(Callable).getReturnType() instanceof PointerType
+ }
/** Holds if this declaration is `async`. */
predicate isAsync() { this.hasModifier("async") }
+ private predicate isReallyPrivate() {
+ this.isPrivate() and
+ not this.isProtected() and
+ // Rare case when a member is defined with the same name in multiple assemblies with different visibility
+ not this.isPublic()
+ }
+
/**
- * Holds if this declaration is effectively `private` (either directly or
- * because one of the enclosing types is `private`).
+ * Holds if this declaration is effectively `private`. A declaration is considered
+ * effectively `private` if it can only be referenced from
+ * - the declaring and its nested types, similarly to `private` declarations, and
+ * - the enclosing types.
+ *
+ * Note that explicit interface implementations are also considered effectively
+ * `private` if the implemented interface is itself effectively `private`. Finally,
+ * `private protected` members are not considered effectively `private`, because
+ * they can be overriden within the declaring assembly.
*/
predicate isEffectivelyPrivate() {
- this.isPrivate() or
- this.getDeclaringType+().isPrivate()
+ this.isReallyPrivate() or
+ this.getDeclaringType+().(Modifiable).isReallyPrivate() or
+ this.(Virtualizable).getExplicitlyImplementedInterface().isEffectivelyPrivate()
+ }
+
+ private predicate isReallyInternal() {
+ (
+ this.isInternal() and not this.isProtected()
+ or
+ this.isPrivate() and this.isProtected()
+ ) and
+ // Rare case when a member is defined with the same name in multiple assemblies with different visibility
+ not this.isPublic()
}
/**
- * Holds if this declaration is effectively `internal` (either directly or
- * because one of the enclosing types is `internal`).
+ * Holds if this declaration is effectively `internal`. A declaration is considered
+ * effectively `internal` if it can only be referenced from the declaring assembly.
+ *
+ * Note that friend assemblies declared in `InternalsVisibleToAttribute` are not
+ * considered. Explicit interface implementations are also considered effectively
+ * `internal` if the implemented interface is itself effectively `internal`. Finally,
+ * `internal protected` members are not considered effectively `internal`, because
+ * they can be overriden outside the declaring assembly.
*/
predicate isEffectivelyInternal() {
- this.isInternal() or
- this.getDeclaringType+().isInternal()
+ this.isReallyInternal() or
+ this.getDeclaringType+().(Modifiable).isReallyInternal() or
+ this.(Virtualizable).getExplicitlyImplementedInterface().isEffectivelyInternal()
}
/**
- * Holds if this declaration is effectively `public`, because it
- * and all enclosing types are `public`.
+ * Holds if this declaration is effectively `public`, meaning that it can be
+ * referenced outside the declaring assembly.
*/
predicate isEffectivelyPublic() { not isEffectivelyPrivate() and not isEffectivelyInternal() }
}
@@ -154,6 +191,11 @@ class Virtualizable extends Member, @virtualizable {
implementsExplicitInterface()
}
+ override predicate isPrivate() {
+ super.isPrivate() and
+ not implementsExplicitInterface()
+ }
+
/**
* Gets any interface this member explicitly implements; this only applies
* to members that can be declared on an interface, i.e. methods, properties,
diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll
index 4e1cd281488..a55e65a81f6 100644
--- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll
+++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll
@@ -168,7 +168,13 @@ module Consistency {
msg = "ArgumentNode is missing PostUpdateNode."
}
- query predicate postWithInFlow(PostUpdateNode n, string msg) {
+ // This predicate helps the compiler forget that in some languages
+ // it is impossible for a `PostUpdateNode` to be the target of
+ // `simpleLocalFlowStep`.
+ private predicate isPostUpdateNode(Node n) { n instanceof PostUpdateNode or none() }
+
+ query predicate postWithInFlow(Node n, string msg) {
+ isPostUpdateNode(n) and
simpleLocalFlowStep(_, n) and
msg = "PostUpdateNode should not be the target of local flow."
}
diff --git a/csharp/ql/test/library-tests/modifiers/Effectively.expected b/csharp/ql/test/library-tests/modifiers/Effectively.expected
index 454295f0065..36afd1bc288 100644
--- a/csharp/ql/test/library-tests/modifiers/Effectively.expected
+++ b/csharp/ql/test/library-tests/modifiers/Effectively.expected
@@ -21,3 +21,11 @@
| Modifiers.cs:54:52:54:54 | set_P1 | public |
| Modifiers.cs:55:20:55:21 | P2 | public |
| Modifiers.cs:55:36:55:38 | get_P2 | public |
+| Modifiers.cs:60:22:60:23 | I1 | public |
+| Modifiers.cs:62:14:62:15 | M1 | public |
+| Modifiers.cs:63:14:63:15 | M2 | public |
+| Modifiers.cs:68:14:68:15 | M1 | internal |
+| Modifiers.cs:71:18:71:19 | C2 | public |
+| Modifiers.cs:73:17:73:18 | M1 | internal |
+| Modifiers.cs:75:32:75:33 | M2 | internal |
+| Modifiers.cs:76:33:76:34 | M3 | public |
diff --git a/csharp/ql/test/library-tests/modifiers/Modifiers.cs b/csharp/ql/test/library-tests/modifiers/Modifiers.cs
index c0377abb9e0..3868b5f9cc4 100644
--- a/csharp/ql/test/library-tests/modifiers/Modifiers.cs
+++ b/csharp/ql/test/library-tests/modifiers/Modifiers.cs
@@ -56,4 +56,23 @@ namespace N
/*private*/
int P3 { /*private*/ get; /*private*/ set; }
}
+
+ public interface I1
+ {
+ void M1();
+ void M2() => throw null;
+ }
+
+ internal interface I2
+ {
+ void M1() => throw null;
+ }
+
+ public class C2 : I2
+ {
+ void I2.M1() => throw null;
+
+ protected private void M2() { }
+ protected internal void M3() { }
+ }
}
diff --git a/csharp/ql/test/library-tests/modifiers/Modifiers.expected b/csharp/ql/test/library-tests/modifiers/Modifiers.expected
index 8f89e302453..50f6ee31a0b 100644
--- a/csharp/ql/test/library-tests/modifiers/Modifiers.expected
+++ b/csharp/ql/test/library-tests/modifiers/Modifiers.expected
@@ -44,3 +44,17 @@
| Modifiers.cs:57:13:57:14 | P3 | file://:0:0:0:0 | private |
| Modifiers.cs:57:30:57:32 | get_P3 | file://:0:0:0:0 | private |
| Modifiers.cs:57:47:57:49 | set_P3 | file://:0:0:0:0 | private |
+| Modifiers.cs:60:22:60:23 | I1 | file://:0:0:0:0 | public |
+| Modifiers.cs:62:14:62:15 | M1 | file://:0:0:0:0 | abstract |
+| Modifiers.cs:62:14:62:15 | M1 | file://:0:0:0:0 | public |
+| Modifiers.cs:63:14:63:15 | M2 | file://:0:0:0:0 | public |
+| Modifiers.cs:63:14:63:15 | M2 | file://:0:0:0:0 | virtual |
+| Modifiers.cs:66:24:66:25 | I2 | file://:0:0:0:0 | internal |
+| Modifiers.cs:68:14:68:15 | M1 | file://:0:0:0:0 | public |
+| Modifiers.cs:68:14:68:15 | M1 | file://:0:0:0:0 | virtual |
+| Modifiers.cs:71:18:71:19 | C2 | file://:0:0:0:0 | public |
+| Modifiers.cs:73:17:73:18 | M1 | file://:0:0:0:0 | private |
+| Modifiers.cs:75:32:75:33 | M2 | file://:0:0:0:0 | private |
+| Modifiers.cs:75:32:75:33 | M2 | file://:0:0:0:0 | protected |
+| Modifiers.cs:76:33:76:34 | M3 | file://:0:0:0:0 | internal |
+| Modifiers.cs:76:33:76:34 | M3 | file://:0:0:0:0 | protected |
diff --git a/csharp/ql/test/library-tests/unsafe/unsafe4.ql b/csharp/ql/test/library-tests/unsafe/unsafe4.ql
index 8aa38fc8fbb..c086e0c00a5 100644
--- a/csharp/ql/test/library-tests/unsafe/unsafe4.ql
+++ b/csharp/ql/test/library-tests/unsafe/unsafe4.ql
@@ -1,3 +1,3 @@
import csharp
-select any(Modifiable m | m.isUnsafe())
+select any(Modifiable m | m.isUnsafe() and m.fromSource())
diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst
index 0205c4b2df9..790cfd0ada7 100644
--- a/docs/codeql/support/reusables/frameworks.rst
+++ b/docs/codeql/support/reusables/frameworks.rst
@@ -1,7 +1,7 @@
C and C++ built-in support
================================
-.. csv-table::
+.. csv-table::
:header-rows: 1
:class: fullWidthTable
:widths: auto
@@ -14,7 +14,7 @@ C and C++ built-in support
C# built-in support
================================
-.. csv-table::
+.. csv-table::
:header-rows: 1
:class: fullWidthTable
:widths: auto
@@ -84,7 +84,7 @@ Go built-in support
Java built-in support
==================================
-.. csv-table::
+.. csv-table::
:header-rows: 1
:class: fullWidthTable
:widths: auto
@@ -109,7 +109,7 @@ Java built-in support
JavaScript and TypeScript built-in support
=======================================================
-.. csv-table::
+.. csv-table::
:header-rows: 1
:class: fullWidthTable
:widths: auto
@@ -165,6 +165,8 @@ Python built-in support
invoke, Utility library
multidict, Utility library
yarl, Utility library
+ aioch, Database
+ clickhouse-driver, Database
mysql-connector-python, Database
mysql-connector, Database
MySQL-python, Database
diff --git a/docs/codeql/support/reusables/versions-compilers.rst b/docs/codeql/support/reusables/versions-compilers.rst
index 74b9c196564..52f373d1d2a 100644
--- a/docs/codeql/support/reusables/versions-compilers.rst
+++ b/docs/codeql/support/reusables/versions-compilers.rst
@@ -4,9 +4,9 @@
:stub-columns: 1
Language,Variants,Compilers,Extensions
- C/C++,"C89, C99, C11, C18, C++98, C++03, C++11, C++14, C++17","Clang (and clang-cl [1]_) extensions (up to Clang 9.0),
+ C/C++,"C89, C99, C11, C18, C++98, C++03, C++11, C++14, C++17","Clang (and clang-cl [1]_) extensions (up to Clang 12.0),
- GNU extensions (up to GCC 9.2),
+ GNU extensions (up to GCC 11.1),
Microsoft extensions (up to VS 2019),
diff --git a/java/change-notes/2021-03-22-jax-rs-improvements.md b/java/change-notes/2021-03-22-jax-rs-improvements.md
new file mode 100644
index 00000000000..0fe567fab89
--- /dev/null
+++ b/java/change-notes/2021-03-22-jax-rs-improvements.md
@@ -0,0 +1,2 @@
+lgtm,codescanning
+* Added support for detecting XSS via JAX-RS sinks, and propagating tainted data via various container types (e.g. Form, Cookie, MultivaluedMap).
diff --git a/java/change-notes/2021-04-06-ssrf-query.md b/java/change-notes/2021-04-06-ssrf-query.md
new file mode 100644
index 00000000000..96afb56f1f8
--- /dev/null
+++ b/java/change-notes/2021-04-06-ssrf-query.md
@@ -0,0 +1,4 @@
+lgtm,codescanning
+* The query "Server-side request forgery (SSRF)" (`java/ssrf`) has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally [submitted as an experimental query by @porcupineyhairs](https://github.com/github/codeql/pull/3454).
+* Models for `URI` and `HttpRequest` in the `java.net` package have been improved. This may lead to more results from any query where these types' methods are relevant.
+* Models for Apache HttpComponents' `RequestLine` and `BasicRequestLine` types. This may lead to more results from any query where these types' methods are relevant.
diff --git a/java/change-notes/2021-05-11-apache-tuples.md b/java/change-notes/2021-05-11-apache-tuples.md
new file mode 100644
index 00000000000..2eab20ecd4f
--- /dev/null
+++ b/java/change-notes/2021-05-11-apache-tuples.md
@@ -0,0 +1,2 @@
+lgtm,codescanning
+* Added models for the Apache Commons Lang tuple types (Pair, Triple and their immutable and mutable implementations). This may lead to more results from any query using data-flow analysis where a relevant path uses one of these container types.
diff --git a/java/change-notes/2021-05-17-add-unsafe-deserialization-sinks.md b/java/change-notes/2021-05-17-add-unsafe-deserialization-sinks.md
new file mode 100644
index 00000000000..f294b223d01
--- /dev/null
+++ b/java/change-notes/2021-05-17-add-unsafe-deserialization-sinks.md
@@ -0,0 +1,3 @@
+lgtm,codescanning
+* The "Deserialization of user-controlled data" (`java/unsafe-deserialization`) query
+ now recognizes `JYaml`, `JsonIO`, `YAMLBeans`, `Castor`, `Hessian` and `Burlap` deserialization.
diff --git a/java/documentation/library-coverage/coverage.csv b/java/documentation/library-coverage/coverage.csv
new file mode 100644
index 00000000000..b7b83a6c217
--- /dev/null
+++ b/java/documentation/library-coverage/coverage.csv
@@ -0,0 +1,44 @@
+package,sink,source,summary,sink:bean-validation,sink:create-file,sink:header-splitting,sink:information-leak,sink:jexl,sink:ldap,sink:open-url,sink:set-hostname-verifier,sink:url-open-stream,sink:xpath,sink:xss,source:remote,summary:taint,summary:value
+android.util,,16,,,,,,,,,,,,,16,,
+android.webkit,3,2,,,,,,,,,,,,3,2,,
+com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,,1,
+com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,,1,
+com.fasterxml.jackson.databind,,,3,,,,,,,,,,,,,3,
+com.google.common.base,,,34,,,,,,,,,,,,,28,6
+com.google.common.io,6,,73,,,,,,,,,6,,,,72,1
+com.unboundid.ldap.sdk,17,,,,,,,,17,,,,,,,,
+java.beans,,,1,,,,,,,,,,,,,1,
+java.io,3,,20,,3,,,,,,,,,,,20,
+java.lang,,,3,,,,,,,,,,,,,1,2
+java.net,2,3,4,,,,,,,2,,,,,3,4,
+java.nio,10,,2,,10,,,,,,,,,,,2,
+java.util,,,283,,,,,,,,,,,,,15,268
+javax.naming.directory,1,,,,,,,,1,,,,,,,,
+javax.net.ssl,2,,,,,,,,,,2,,,,,,
+javax.servlet,4,21,2,,,3,1,,,,,,,,21,2,
+javax.validation,1,1,,1,,,,,,,,,,,1,,
+javax.ws.rs.core,1,,,,,1,,,,,,,,,,,
+javax.xml.transform.sax,,,4,,,,,,,,,,,,,4,
+javax.xml.transform.stream,,,2,,,,,,,,,,,,,2,
+javax.xml.xpath,3,,,,,,,,,,,,3,,,,
+org.apache.commons.codec,,,2,,,,,,,,,,,,,2,
+org.apache.commons.io,,,22,,,,,,,,,,,,,22,
+org.apache.commons.jexl2,15,,,,,,,15,,,,,,,,,
+org.apache.commons.jexl3,15,,,,,,,15,,,,,,,,,
+org.apache.commons.lang3,,,370,,,,,,,,,,,,,324,46
+org.apache.commons.text,,,272,,,,,,,,,,,,,220,52
+org.apache.directory.ldap.client.api,1,,,,,,,,1,,,,,,,,
+org.apache.hc.core5.function,,,1,,,,,,,,,,,,,1,
+org.apache.hc.core5.http,1,2,39,,,,,,,,,,,1,2,39,
+org.apache.hc.core5.net,,,2,,,,,,,,,,,,,2,
+org.apache.hc.core5.util,,,24,,,,,,,,,,,,,18,6
+org.apache.http,2,3,67,,,,,,,,,,,2,3,59,8
+org.dom4j,20,,,,,,,,,,,,20,,,,
+org.springframework.ldap.core,14,,,,,,,,14,,,,,,,,
+org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,,6,,
+org.springframework.web.client,,3,,,,,,,,,,,,,3,,
+org.springframework.web.context.request,,8,,,,,,,,,,,,,8,,
+org.springframework.web.multipart,,12,,,,,,,,,,,,,12,,
+org.xml.sax,,,1,,,,,,,,,,,,,1,
+org.xmlpull.v1,,3,,,,,,,,,,,,,3,,
+play.mvc,,4,,,,,,,,,,,,,4,,
diff --git a/java/documentation/library-coverage/flow-model-coverage.rst b/java/documentation/library-coverage/coverage.rst
similarity index 53%
rename from java/documentation/library-coverage/flow-model-coverage.rst
rename to java/documentation/library-coverage/coverage.rst
index b9b54aad158..c99a41d3be2 100644
--- a/java/documentation/library-coverage/flow-model-coverage.rst
+++ b/java/documentation/library-coverage/coverage.rst
@@ -8,12 +8,14 @@ Java framework & library support
Framework / library,Package,Remote flow sources,Taint & value steps,Sinks (total),`CWE‑022` :sub:`Path injection`,`CWE‑036` :sub:`Path traversal`,`CWE‑079` :sub:`Cross-site scripting`,`CWE‑089` :sub:`SQL injection`,`CWE‑090` :sub:`LDAP injection`,`CWE‑094` :sub:`Code injection`,`CWE‑319` :sub:`Cleartext transmission`
Android,``android.*``,18,,3,,,3,,,,
- Apache,``org.apache.*``,5,648,4,,,3,,1,,
`Apache Commons IO `_,``org.apache.commons.io``,,22,,,,,,,,
- Google,``com.google.common.*``,,97,6,,6,,,,,
- Java Standard Library,``java.*``,3,41,15,13,,,,,,2
+ `Apache Commons Lang `_,``org.apache.commons.lang3``,,370,,,,,,,,
+ `Apache Commons Text `_,``org.apache.commons.text``,,272,,,,,,,,
+ `Apache HttpComponents `_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,133,3,,,3,,,,
+ `Google Guava `_,``com.google.common.*``,,107,6,,6,,,,,
+ Java Standard Library,``java.*``,3,313,15,13,,,,,,2
Java extensions,``javax.*``,22,8,12,,,,,1,1,
`Spring `_,``org.springframework.*``,29,,14,,,,,14,,
- Others,"``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.databind``, ``com.unboundid.ldap.sdk``, ``org.dom4j``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``",7,5,37,,,,,17,,
- Totals,,84,821,91,13,6,6,,33,1,2
+ Others,"``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.databind``, ``com.unboundid.ldap.sdk``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.directory.ldap.client.api``, ``org.dom4j``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``",7,8,68,,,,,18,,
+ Totals,,84,1233,121,13,6,6,,33,1,2
diff --git a/java/documentation/library-coverage/flow-model-coverage.csv b/java/documentation/library-coverage/flow-model-coverage.csv
deleted file mode 100644
index 464228bb022..00000000000
--- a/java/documentation/library-coverage/flow-model-coverage.csv
+++ /dev/null
@@ -1,42 +0,0 @@
-package,sink,source,summary,sink:bean-validation,sink:create-file,sink:header-splitting,sink:information-leak,sink:ldap,sink:open-url,sink:set-hostname-verifier,sink:url-open-stream,sink:xpath,sink:xss,source:remote,summary:taint,summary:value
-android.util,,16,,,,,,,,,,,,16,,
-android.webkit,3,2,,,,,,,,,,,3,2,,
-com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,1,
-com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,1,
-com.fasterxml.jackson.databind,,,2,,,,,,,,,,,,2,
-com.google.common.base,,,28,,,,,,,,,,,,22,6
-com.google.common.io,6,,69,,,,,,,,6,,,,68,1
-com.unboundid.ldap.sdk,17,,,,,,,17,,,,,,,,
-java.beans,,,1,,,,,,,,,,,,1,
-java.io,3,,20,,3,,,,,,,,,,20,
-java.lang,,,1,,,,,,,,,,,,1,
-java.net,2,3,4,,,,,,2,,,,,3,4,
-java.nio,10,,2,,10,,,,,,,,,,2,
-java.util,,,13,,,,,,,,,,,,13,
-javax.naming.directory,1,,,,,,,1,,,,,,,,
-javax.net.ssl,2,,,,,,,,,2,,,,,,
-javax.servlet,4,21,2,,,3,1,,,,,,,21,2,
-javax.validation,1,1,,1,,,,,,,,,,1,,
-javax.ws.rs.core,1,,,,,1,,,,,,,,,,
-javax.xml.transform.sax,,,4,,,,,,,,,,,,4,
-javax.xml.transform.stream,,,2,,,,,,,,,,,,2,
-javax.xml.xpath,3,,,,,,,,,,,3,,,,
-org.apache.commons.codec,,,2,,,,,,,,,,,,2,
-org.apache.commons.io,,,22,,,,,,,,,,,,22,
-org.apache.commons.lang3,,,313,,,,,,,,,,,,299,14
-org.apache.commons.text,,,203,,,,,,,,,,,,203,
-org.apache.directory.ldap.client.api,1,,,,,,,1,,,,,,,,
-org.apache.hc.core5.function,,,1,,,,,,,,,,,,1,
-org.apache.hc.core5.http,1,2,39,,,,,,,,,,1,2,39,
-org.apache.hc.core5.net,,,2,,,,,,,,,,,,2,
-org.apache.hc.core5.util,,,22,,,,,,,,,,,,18,4
-org.apache.http,2,3,66,,,,,,,,,,2,3,59,7
-org.dom4j,20,,,,,,,,,,,20,,,,
-org.springframework.ldap.core,14,,,,,,,14,,,,,,,,
-org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,6,,
-org.springframework.web.client,,3,,,,,,,,,,,,3,,
-org.springframework.web.context.request,,8,,,,,,,,,,,,8,,
-org.springframework.web.multipart,,12,,,,,,,,,,,,12,,
-org.xml.sax,,,1,,,,,,,,,,,,1,
-org.xmlpull.v1,,3,,,,,,,,,,,,3,,
-play.mvc,,4,,,,,,,,,,,,4,,
diff --git a/java/documentation/library-coverage/frameworks.csv b/java/documentation/library-coverage/frameworks.csv
index 0e39bc51836..751883eaf4b 100644
--- a/java/documentation/library-coverage/frameworks.csv
+++ b/java/documentation/library-coverage/frameworks.csv
@@ -1,8 +1,10 @@
-Framework name,URL,Package prefix
+Framework name,URL,Package prefixes
Java Standard Library,,java.*
-Google,,com.google.common.*
-Apache,,org.apache.*
+Java extensions,,javax.*
+Google Guava,https://guava.dev/,com.google.common.*
Apache Commons IO,https://commons.apache.org/proper/commons-io/,org.apache.commons.io
+Apache Commons Lang,https://commons.apache.org/proper/commons-lang/,org.apache.commons.lang3
+Apache Commons Text,https://commons.apache.org/proper/commons-text/,org.apache.commons.text
+Apache HttpComponents,https://hc.apache.org/,org.apache.hc.core5.* org.apache.http
Android,,android.*
-Spring,https://spring.io/,org.springframework.*
-Java extensions,,javax.*
\ No newline at end of file
+Spring,https://spring.io/,org.springframework.*
\ No newline at end of file
diff --git a/java/ql/src/Frameworks/JavaEE/EJB/EjbContainerInterference.ql b/java/ql/src/Frameworks/JavaEE/EJB/EjbContainerInterference.ql
index 6b08a14c244..cbd74a838f3 100644
--- a/java/ql/src/Frameworks/JavaEE/EJB/EjbContainerInterference.ql
+++ b/java/ql/src/Frameworks/JavaEE/EJB/EjbContainerInterference.ql
@@ -7,7 +7,7 @@
* Such operations could interfere with the EJB container's operation.
* @kind problem
* @problem.severity error
- * @security-severity 4.9
+ * @security-severity 5.8
* @precision low
* @id java/ejb/container-interference
* @tags reliability
diff --git a/java/ql/src/Frameworks/JavaEE/EJB/EjbFileIO.ql b/java/ql/src/Frameworks/JavaEE/EJB/EjbFileIO.ql
index 62b2d5f48ec..ec406ac3171 100644
--- a/java/ql/src/Frameworks/JavaEE/EJB/EjbFileIO.ql
+++ b/java/ql/src/Frameworks/JavaEE/EJB/EjbFileIO.ql
@@ -5,7 +5,7 @@
* for enterprise components.
* @kind problem
* @problem.severity error
- * @security-severity 4.9
+ * @security-severity 5.8
* @precision low
* @id java/ejb/file-io
* @tags reliability
diff --git a/java/ql/src/Frameworks/JavaEE/EJB/EjbNative.ql b/java/ql/src/Frameworks/JavaEE/EJB/EjbNative.ql
index 787ae9a72c5..bbc57fca5e9 100644
--- a/java/ql/src/Frameworks/JavaEE/EJB/EjbNative.ql
+++ b/java/ql/src/Frameworks/JavaEE/EJB/EjbNative.ql
@@ -4,7 +4,7 @@
* Such use could compromise security and system stability.
* @kind problem
* @problem.severity error
- * @security-severity 4.9
+ * @security-severity 5.8
* @precision low
* @id java/ejb/native-code
* @tags reliability
diff --git a/java/ql/src/Frameworks/JavaEE/EJB/EjbReflection.ql b/java/ql/src/Frameworks/JavaEE/EJB/EjbReflection.ql
index 4e6eea2cbf1..7bc062209df 100644
--- a/java/ql/src/Frameworks/JavaEE/EJB/EjbReflection.ql
+++ b/java/ql/src/Frameworks/JavaEE/EJB/EjbReflection.ql
@@ -4,7 +4,7 @@
* as this could compromise security.
* @kind problem
* @problem.severity error
- * @security-severity 4.9
+ * @security-severity 5.8
* @precision low
* @id java/ejb/reflection
* @tags external/cwe/cwe-573
diff --git a/java/ql/src/Frameworks/JavaEE/EJB/EjbSecurityConfiguration.ql b/java/ql/src/Frameworks/JavaEE/EJB/EjbSecurityConfiguration.ql
index 4efde8d82bf..ea8a7087d26 100644
--- a/java/ql/src/Frameworks/JavaEE/EJB/EjbSecurityConfiguration.ql
+++ b/java/ql/src/Frameworks/JavaEE/EJB/EjbSecurityConfiguration.ql
@@ -5,7 +5,7 @@
* This functionality is reserved for the EJB container for security reasons.
* @kind problem
* @problem.severity error
- * @security-severity 4.9
+ * @security-severity 5.8
* @precision low
* @id java/ejb/security-configuration-access
* @tags external/cwe/cwe-573
diff --git a/java/ql/src/Frameworks/JavaEE/EJB/EjbSerialization.ql b/java/ql/src/Frameworks/JavaEE/EJB/EjbSerialization.ql
index 02c493c7a70..7de0a0f8aed 100644
--- a/java/ql/src/Frameworks/JavaEE/EJB/EjbSerialization.ql
+++ b/java/ql/src/Frameworks/JavaEE/EJB/EjbSerialization.ql
@@ -4,7 +4,7 @@
* the Java serialization protocol, since their use could compromise security.
* @kind problem
* @problem.severity error
- * @security-severity 4.9
+ * @security-severity 5.8
* @precision low
* @id java/ejb/substitution-in-serialization
* @tags external/cwe/cwe-573
diff --git a/java/ql/src/Frameworks/JavaEE/EJB/EjbSetSocketOrUrlFactory.ql b/java/ql/src/Frameworks/JavaEE/EJB/EjbSetSocketOrUrlFactory.ql
index 8011b3c1d22..e8b898b00cc 100644
--- a/java/ql/src/Frameworks/JavaEE/EJB/EjbSetSocketOrUrlFactory.ql
+++ b/java/ql/src/Frameworks/JavaEE/EJB/EjbSetSocketOrUrlFactory.ql
@@ -5,7 +5,7 @@
* compromise security or interfere with the EJB container's operation.
* @kind problem
* @problem.severity error
- * @security-severity 4.9
+ * @security-severity 5.8
* @precision low
* @id java/ejb/socket-or-stream-handler-factory
* @tags reliability
diff --git a/java/ql/src/Likely Bugs/Arithmetic/InformationLoss.ql b/java/ql/src/Likely Bugs/Arithmetic/InformationLoss.ql
index 52bb9f04289..29b60cae012 100644
--- a/java/ql/src/Likely Bugs/Arithmetic/InformationLoss.ql
+++ b/java/ql/src/Likely Bugs/Arithmetic/InformationLoss.ql
@@ -5,7 +5,7 @@
* numeric errors such as overflows.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision very-high
* @id java/implicit-cast-in-compound-assignment
* @tags reliability
diff --git a/java/ql/src/Likely Bugs/Arithmetic/RandomUsedOnce.ql b/java/ql/src/Likely Bugs/Arithmetic/RandomUsedOnce.ql
index fb1a44b2222..f2b78dcaf18 100644
--- a/java/ql/src/Likely Bugs/Arithmetic/RandomUsedOnce.ql
+++ b/java/ql/src/Likely Bugs/Arithmetic/RandomUsedOnce.ql
@@ -4,7 +4,7 @@
* guarantee an evenly distributed sequence of random numbers.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @id java/random-used-once
* @tags reliability
diff --git a/java/ql/src/Likely Bugs/Concurrency/UnreleasedLock.ql b/java/ql/src/Likely Bugs/Concurrency/UnreleasedLock.ql
index 4a3fc548085..10a054f4106 100644
--- a/java/ql/src/Likely Bugs/Concurrency/UnreleasedLock.ql
+++ b/java/ql/src/Likely Bugs/Concurrency/UnreleasedLock.ql
@@ -4,7 +4,7 @@
* may cause a deadlock.
* @kind problem
* @problem.severity error
- * @security-severity 6.9
+ * @security-severity 5.0
* @precision medium
* @id java/unreleased-lock
* @tags reliability
diff --git a/java/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql b/java/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql
index bf2e3f06f26..63c66ffa9d0 100644
--- a/java/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql
+++ b/java/ql/src/Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql
@@ -5,7 +5,7 @@
* @kind path-problem
* @precision low
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @tags security external/cwe/cwe-20
*/
diff --git a/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql b/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql
index ac3ec8664a2..adb51f751b4 100644
--- a/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql
+++ b/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql
@@ -3,7 +3,7 @@
* @description Accessing paths influenced by users can allow an attacker to access unexpected resources.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision high
* @id java/path-injection
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql b/java/ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql
index 90b77661500..ebd9c4f079d 100644
--- a/java/ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql
+++ b/java/ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql
@@ -3,7 +3,7 @@
* @description Accessing paths influenced by users can allow an attacker to access unexpected resources.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision medium
* @id java/path-injection-local
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql b/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql
index 1a70b273d84..a7c15a82b87 100644
--- a/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql
+++ b/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql
@@ -6,7 +6,7 @@
* @kind path-problem
* @id java/zipslip
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision high
* @tags security
* external/cwe/cwe-022
diff --git a/java/ql/src/Security/CWE/CWE-078/ExecRelative.ql b/java/ql/src/Security/CWE/CWE-078/ExecRelative.ql
index f7d844f225a..501826c6426 100644
--- a/java/ql/src/Security/CWE/CWE-078/ExecRelative.ql
+++ b/java/ql/src/Security/CWE/CWE-078/ExecRelative.ql
@@ -4,7 +4,7 @@
* malicious changes in the PATH environment variable.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @id java/relative-path-command
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql b/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql
index fc409bcfd5a..e95d81dcf06 100644
--- a/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql
+++ b/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql
@@ -4,7 +4,7 @@
* changes in the strings.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id java/command-line-injection
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-078/ExecTaintedLocal.ql b/java/ql/src/Security/CWE/CWE-078/ExecTaintedLocal.ql
index c98a45a06d8..febd020db46 100644
--- a/java/ql/src/Security/CWE/CWE-078/ExecTaintedLocal.ql
+++ b/java/ql/src/Security/CWE/CWE-078/ExecTaintedLocal.ql
@@ -4,7 +4,7 @@
* changes in the strings.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @id java/command-line-injection-local
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql
index a3b88b40ae7..d250b242c05 100644
--- a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql
+++ b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql
@@ -4,7 +4,7 @@
* insertion of special characters in the strings.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id java/concatenated-command-line
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-079/XSS.ql b/java/ql/src/Security/CWE/CWE-079/XSS.ql
index d864d24a95e..f1f8a5afa9b 100644
--- a/java/ql/src/Security/CWE/CWE-079/XSS.ql
+++ b/java/ql/src/Security/CWE/CWE-079/XSS.ql
@@ -4,7 +4,7 @@
* allows for a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 6.1
* @precision high
* @id java/xss
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-079/XSSLocal.ql b/java/ql/src/Security/CWE/CWE-079/XSSLocal.ql
index 44ab185b3b5..e16a9bbc2e9 100644
--- a/java/ql/src/Security/CWE/CWE-079/XSSLocal.ql
+++ b/java/ql/src/Security/CWE/CWE-079/XSSLocal.ql
@@ -4,7 +4,7 @@
* allows for a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 2.9
+ * @security-severity 6.1
* @precision medium
* @id java/xss-local
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql b/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql
index d002bb96ce1..28b09d37dbb 100644
--- a/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql
+++ b/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql
@@ -4,7 +4,7 @@
* malicious code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 8.8
* @precision high
* @id java/sql-injection
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-089/SqlTaintedLocal.ql b/java/ql/src/Security/CWE/CWE-089/SqlTaintedLocal.ql
index ada846dcf47..df5807f3f5f 100644
--- a/java/ql/src/Security/CWE/CWE-089/SqlTaintedLocal.ql
+++ b/java/ql/src/Security/CWE/CWE-089/SqlTaintedLocal.ql
@@ -4,7 +4,7 @@
* malicious code by the user.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 6.4
+ * @security-severity 8.8
* @precision medium
* @id java/sql-injection-local
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql b/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql
index 9ddd5def883..6ec2be3e1c8 100644
--- a/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql
+++ b/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql
@@ -4,7 +4,7 @@
* characters is vulnerable to insertion of malicious code.
* @kind problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 8.8
* @precision high
* @id java/concatenated-sql-query
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-090/LdapInjection.ql b/java/ql/src/Security/CWE/CWE-090/LdapInjection.ql
index 5a7ab632a55..df57a810033 100644
--- a/java/ql/src/Security/CWE/CWE-090/LdapInjection.ql
+++ b/java/ql/src/Security/CWE/CWE-090/LdapInjection.ql
@@ -4,7 +4,7 @@
* malicious LDAP code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id java/ldap-injection
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-094/InsecureBeanValidation.ql b/java/ql/src/Security/CWE/CWE-094/InsecureBeanValidation.ql
index f865d7d16b1..a673142f810 100644
--- a/java/ql/src/Security/CWE/CWE-094/InsecureBeanValidation.ql
+++ b/java/ql/src/Security/CWE/CWE-094/InsecureBeanValidation.ql
@@ -3,7 +3,7 @@
* @description User-controlled data may be evaluated as a Java EL expression, leading to arbitrary code execution.
* @kind path-problem
* @problem.severity error
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision high
* @id java/insecure-bean-validation
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-094/JexlInjection.ql b/java/ql/src/Security/CWE/CWE-094/JexlInjection.ql
index cf555aa3442..c780fa60f20 100644
--- a/java/ql/src/Security/CWE/CWE-094/JexlInjection.ql
+++ b/java/ql/src/Security/CWE/CWE-094/JexlInjection.ql
@@ -4,7 +4,7 @@
* may lead to arbitrary code execution.
* @kind path-problem
* @problem.severity error
- * @security-severity 10.0
+ * @security-severity 9.3
* @precision high
* @id java/jexl-expression-injection
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-113/NettyResponseSplitting.ql b/java/ql/src/Security/CWE/CWE-113/NettyResponseSplitting.ql
index 76fa154ae7b..350358b69c1 100644
--- a/java/ql/src/Security/CWE/CWE-113/NettyResponseSplitting.ql
+++ b/java/ql/src/Security/CWE/CWE-113/NettyResponseSplitting.ql
@@ -5,7 +5,7 @@
* an HTTP header.
* @kind problem
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 6.1
* @precision high
* @id java/netty-http-response-splitting
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql b/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql
index 92468d61936..d32e7544f3e 100644
--- a/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql
+++ b/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql
@@ -4,7 +4,7 @@
* makes code vulnerable to attack by header splitting.
* @kind path-problem
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 6.1
* @precision high
* @id java/http-response-splitting
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-113/ResponseSplittingLocal.ql b/java/ql/src/Security/CWE/CWE-113/ResponseSplittingLocal.ql
index ff9a379d1f7..608636982c9 100644
--- a/java/ql/src/Security/CWE/CWE-113/ResponseSplittingLocal.ql
+++ b/java/ql/src/Security/CWE/CWE-113/ResponseSplittingLocal.ql
@@ -4,7 +4,7 @@
* makes code vulnerable to attack by header splitting.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 3.6
+ * @security-severity 6.1
* @precision medium
* @id java/http-response-splitting-local
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstruction.ql b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstruction.ql
index ca5d05db10c..8ccf937355c 100644
--- a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstruction.ql
+++ b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstruction.ql
@@ -3,7 +3,7 @@
* @description Using unvalidated external input as the argument to a construction of an array can lead to index out of bound exceptions.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id java/improper-validation-of-array-construction
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionCodeSpecified.ql b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionCodeSpecified.ql
index f3471027561..62038fe73a6 100644
--- a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionCodeSpecified.ql
+++ b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionCodeSpecified.ql
@@ -4,7 +4,7 @@
* a construction of an array can lead to index out of bound exceptions.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id java/improper-validation-of-array-construction-code-specified
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionLocal.ql b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionLocal.ql
index 94e06109da4..db7dfc0aec5 100644
--- a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionLocal.ql
+++ b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayConstructionLocal.ql
@@ -4,7 +4,7 @@
* a construction of an array can lead to index out of bound exceptions.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id java/improper-validation-of-array-construction-local
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndex.ql b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndex.ql
index 5fe23b564d6..4cc9c58e64f 100644
--- a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndex.ql
+++ b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndex.ql
@@ -3,7 +3,7 @@
* @description Using external input as an index to an array, without proper validation, can lead to index out of bound exceptions.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id java/improper-validation-of-array-index
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexCodeSpecified.ql b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexCodeSpecified.ql
index 99c819533cb..79911f5422d 100644
--- a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexCodeSpecified.ql
+++ b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexCodeSpecified.ql
@@ -4,7 +4,7 @@
* proper validation, can lead to index out of bound exceptions.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id java/improper-validation-of-array-index-code-specified
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexLocal.ql b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexLocal.ql
index c246bcff158..537c47b34cc 100644
--- a/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexLocal.ql
+++ b/java/ql/src/Security/CWE/CWE-129/ImproperValidationOfArrayIndexLocal.ql
@@ -4,7 +4,7 @@
* proper validation, can lead to index out of bound exceptions.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 5.9
+ * @security-severity 8.8
* @precision medium
* @id java/improper-validation-of-array-index-local
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql b/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql
index 0208955e10f..4e319b388e6 100644
--- a/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql
+++ b/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql
@@ -3,7 +3,7 @@
* @description Using external input in format strings can lead to exceptions or information leaks.
* @kind path-problem
* @problem.severity error
- * @security-severity 6.9
+ * @security-severity 9.3
* @precision high
* @id java/tainted-format-string
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatStringLocal.ql b/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatStringLocal.ql
index 5dd2f629393..36027f97c30 100644
--- a/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatStringLocal.ql
+++ b/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatStringLocal.ql
@@ -3,7 +3,7 @@
* @description Using external input in format strings can lead to exceptions or information leaks.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 6.9
+ * @security-severity 9.3
* @precision medium
* @id java/tainted-format-string-local
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql b/java/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql
index 261c6891039..5fa48ee10d1 100644
--- a/java/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql
+++ b/java/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql
@@ -4,7 +4,7 @@
* overflows.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.6
* @precision medium
* @id java/tainted-arithmetic
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-190/ArithmeticTaintedLocal.ql b/java/ql/src/Security/CWE/CWE-190/ArithmeticTaintedLocal.ql
index 54e3fa1b10a..20bec26dd9f 100644
--- a/java/ql/src/Security/CWE/CWE-190/ArithmeticTaintedLocal.ql
+++ b/java/ql/src/Security/CWE/CWE-190/ArithmeticTaintedLocal.ql
@@ -4,7 +4,7 @@
* overflows.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 5.9
+ * @security-severity 8.6
* @precision medium
* @id java/tainted-arithmetic-local
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql b/java/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
index ad67e3b55bc..9cc3dfbabeb 100644
--- a/java/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
+++ b/java/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
@@ -4,7 +4,7 @@
* overflows.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.6
* @precision medium
* @id java/uncontrolled-arithmetic
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql b/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql
index 0ffcbec38e6..5c49e1b3229 100644
--- a/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql
+++ b/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql
@@ -4,7 +4,7 @@
* is then used in an arithmetic expression, this may result in an overflow.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 5.9
+ * @security-severity 8.6
* @precision medium
* @id java/extreme-value-arithmetic
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql b/java/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
index c6e72a94b65..259f36fb42b 100644
--- a/java/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
+++ b/java/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
@@ -4,7 +4,7 @@
* to behave unexpectedly.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision medium
* @id java/comparison-with-wider-type
* @tags reliability
diff --git a/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql b/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql
index bf96ee8d1bb..3b085b609b2 100644
--- a/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql
+++ b/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql
@@ -5,7 +5,7 @@
* that are useful to an attacker for developing a subsequent exploit.
* @kind problem
* @problem.severity error
- * @security-severity 3.6
+ * @security-severity 5.4
* @precision high
* @id java/stack-trace-exposure
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-297/UnsafeHostnameVerification.ql b/java/ql/src/Security/CWE/CWE-297/UnsafeHostnameVerification.ql
index d7a5f374953..1828b924752 100644
--- a/java/ql/src/Security/CWE/CWE-297/UnsafeHostnameVerification.ql
+++ b/java/ql/src/Security/CWE/CWE-297/UnsafeHostnameVerification.ql
@@ -3,7 +3,7 @@
* @description Marking a certificate as valid for a host without checking the certificate hostname allows an attacker to perform a machine-in-the-middle attack.
* @kind path-problem
* @problem.severity error
- * @security-severity 4.9
+ * @security-severity 5.9
* @precision high
* @id java/unsafe-hostname-verification
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-312/CleartextStorageClass.ql b/java/ql/src/Security/CWE/CWE-312/CleartextStorageClass.ql
index 00527d4ab60..e14b9bfe552 100644
--- a/java/ql/src/Security/CWE/CWE-312/CleartextStorageClass.ql
+++ b/java/ql/src/Security/CWE/CWE-312/CleartextStorageClass.ql
@@ -3,7 +3,7 @@
* @description Storing sensitive information in cleartext can expose it to an attacker.
* @kind problem
* @problem.severity recommendation
- * @security-severity 5.9
+ * @security-severity 7.5
* @precision medium
* @id java/cleartext-storage-in-class
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-312/CleartextStorageCookie.ql b/java/ql/src/Security/CWE/CWE-312/CleartextStorageCookie.ql
index 7a3c55379de..c5a76434dcd 100644
--- a/java/ql/src/Security/CWE/CWE-312/CleartextStorageCookie.ql
+++ b/java/ql/src/Security/CWE/CWE-312/CleartextStorageCookie.ql
@@ -3,7 +3,7 @@
* @description Storing sensitive information in cleartext can expose it to an attacker.
* @kind problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 5.0
* @precision high
* @id java/cleartext-storage-in-cookie
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-312/CleartextStorageProperties.ql b/java/ql/src/Security/CWE/CWE-312/CleartextStorageProperties.ql
index 7f05192357d..495fd3f6f20 100644
--- a/java/ql/src/Security/CWE/CWE-312/CleartextStorageProperties.ql
+++ b/java/ql/src/Security/CWE/CWE-312/CleartextStorageProperties.ql
@@ -3,7 +3,7 @@
* @description Storing sensitive information in cleartext can expose it to an attacker.
* @kind problem
* @problem.severity warning
- * @security-severity 6.4
+ * @security-severity 7.5
* @precision medium
* @id java/cleartext-storage-in-properties
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql b/java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql
index 544197f0252..001afb8efb1 100644
--- a/java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql
+++ b/java/ql/src/Security/CWE/CWE-319/HttpsUrls.ql
@@ -3,7 +3,7 @@
* @description Non-HTTPS connections can be intercepted by third parties.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision medium
* @id java/non-https-url
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-319/UseSSL.ql b/java/ql/src/Security/CWE/CWE-319/UseSSL.ql
index b4fabf15940..1b267af52cf 100644
--- a/java/ql/src/Security/CWE/CWE-319/UseSSL.ql
+++ b/java/ql/src/Security/CWE/CWE-319/UseSSL.ql
@@ -3,7 +3,7 @@
* @description Non-SSL connections can be intercepted by third parties.
* @kind problem
* @problem.severity recommendation
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision medium
* @id java/non-ssl-connection
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-319/UseSSLSocketFactories.ql b/java/ql/src/Security/CWE/CWE-319/UseSSLSocketFactories.ql
index 6fa51d4caf2..5defe0cd612 100644
--- a/java/ql/src/Security/CWE/CWE-319/UseSSLSocketFactories.ql
+++ b/java/ql/src/Security/CWE/CWE-319/UseSSLSocketFactories.ql
@@ -4,7 +4,7 @@
* third parties.
* @kind problem
* @problem.severity recommendation
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision medium
* @id java/non-ssl-socket-factory
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql b/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql
index 194d7ecf7d5..5c8a5b51df0 100644
--- a/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql
+++ b/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql
@@ -3,7 +3,7 @@
* @description Using broken or weak cryptographic algorithms can allow an attacker to compromise security.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision high
* @id java/weak-cryptographic-algorithm
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql b/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql
index fac3d66f2b8..1b99c53561b 100644
--- a/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql
+++ b/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql
@@ -3,7 +3,7 @@
* @description Using broken or weak cryptographic algorithms can allow an attacker to compromise security.
* @kind path-problem
* @problem.severity warning
- * @security-severity 5.2
+ * @security-severity 7.5
* @precision medium
* @id java/potentially-weak-cryptographic-algorithm
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-335/PredictableSeed.ql b/java/ql/src/Security/CWE/CWE-335/PredictableSeed.ql
index 2cd7bbae1dd..9b873aa407f 100644
--- a/java/ql/src/Security/CWE/CWE-335/PredictableSeed.ql
+++ b/java/ql/src/Security/CWE/CWE-335/PredictableSeed.ql
@@ -3,7 +3,7 @@
* @description Using a predictable seed in a pseudo-random number generator can lead to predictability of the numbers generated by it.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id java/predictable-seed
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-338/JHipsterGeneratedPRNG.ql b/java/ql/src/Security/CWE/CWE-338/JHipsterGeneratedPRNG.ql
index 6a456fbae32..9a530e5078f 100644
--- a/java/ql/src/Security/CWE/CWE-338/JHipsterGeneratedPRNG.ql
+++ b/java/ql/src/Security/CWE/CWE-338/JHipsterGeneratedPRNG.ql
@@ -3,7 +3,7 @@
* @description Using a vulnerable version of JHipster to generate random numbers makes it easier for attackers to take over accounts.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision very-high
* @id java/jhipster-prng
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-352/SpringCSRFProtection.ql b/java/ql/src/Security/CWE/CWE-352/SpringCSRFProtection.ql
index d7fe7b8611e..9bca9dc3ed9 100644
--- a/java/ql/src/Security/CWE/CWE-352/SpringCSRFProtection.ql
+++ b/java/ql/src/Security/CWE/CWE-352/SpringCSRFProtection.ql
@@ -4,7 +4,7 @@
* a Cross-Site Request Forgery (CSRF) attack.
* @kind problem
* @problem.severity error
- * @security-severity 6.4
+ * @security-severity 8.8
* @precision high
* @id java/spring-disabled-csrf-protection
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-367/TOCTOURace.ql b/java/ql/src/Security/CWE/CWE-367/TOCTOURace.ql
index 740dd6ba314..2fb46ad8943 100644
--- a/java/ql/src/Security/CWE/CWE-367/TOCTOURace.ql
+++ b/java/ql/src/Security/CWE/CWE-367/TOCTOURace.ql
@@ -4,7 +4,7 @@
* if the state may be changed between the check and use.
* @kind problem
* @problem.severity warning
- * @security-severity 5.9
+ * @security-severity 7.7
* @precision medium
* @id java/toctou-race-condition
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-421/SocketAuthRace.ql b/java/ql/src/Security/CWE/CWE-421/SocketAuthRace.ql
index d4301a3d620..c8515f2b085 100644
--- a/java/ql/src/Security/CWE/CWE-421/SocketAuthRace.ql
+++ b/java/ql/src/Security/CWE/CWE-421/SocketAuthRace.ql
@@ -3,7 +3,7 @@
* @description Opening a socket after authenticating via a different channel may allow an attacker to connect to the port first.
* @kind problem
* @problem.severity warning
- * @security-severity 10.0
+ * @security-severity 7.2
* @precision medium
* @id java/socket-auth-race-condition
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
index 0d1f21ca87f..e9600f11b93 100644
--- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
+++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
@@ -14,8 +14,8 @@ may have unforeseen effects, such as the execution of arbitrary code.
There are many different serialization frameworks. This query currently
-supports Kryo, XmlDecoder, XStream, SnakeYaml, and Java IO serialization through
-ObjectInputStream/ObjectOutputStream.
+supports Kryo, XmlDecoder, XStream, SnakeYaml, JYaml, JsonIO, YAMLBeans, HessianBurlap, Castor, Burlap
+and Java IO serialization through ObjectInputStream/ObjectOutputStream.
@@ -75,6 +75,22 @@ Alvaro Muñoz & Christian Schneider, RSAConference 2016:
SnakeYaml documentation on deserialization:
SnakeYaml deserialization.
+
+Hessian deserialization and related gadget chains:
+Hessian deserialization.
+
+
+Castor and Hessian java deserialization vulnerabilities:
+Castor and Hessian deserialization.
+
+
+Remote code execution in JYaml library:
+JYaml deserialization.
+
+
+JsonIO deserialization vulnerabilities:
+JsonIO deserialization.
+
diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql
index 82dd42c3c32..606468d451d 100644
--- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql
+++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql
@@ -4,7 +4,7 @@
* execute arbitrary code.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id java/unsafe-deserialization
* @tags security
@@ -22,6 +22,39 @@ class UnsafeDeserializationConfig extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeDeserializationSink }
+
+ override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
+ exists(ClassInstanceExpr cie |
+ cie.getArgument(0) = pred.asExpr() and
+ cie = succ.asExpr() and
+ (
+ cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader or
+ cie.getConstructor().getDeclaringType() instanceof YamlBeansReader or
+ cie.getConstructor().getDeclaringType().getASupertype*() instanceof UnsafeHessianInput or
+ cie.getConstructor().getDeclaringType() instanceof BurlapInput
+ )
+ )
+ or
+ exists(MethodAccess ma |
+ ma.getMethod() instanceof BurlapInputInitMethod and
+ ma.getArgument(0) = pred.asExpr() and
+ ma.getQualifier() = succ.asExpr()
+ )
+ }
+
+ override predicate isSanitizer(DataFlow::Node node) {
+ exists(ClassInstanceExpr cie |
+ cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader and
+ cie = node.asExpr() and
+ exists(SafeJsonIoConfig sji | sji.hasFlowToExpr(cie.getArgument(1)))
+ )
+ or
+ exists(MethodAccess ma |
+ ma.getMethod() instanceof JsonIoJsonToJavaMethod and
+ ma.getArgument(0) = node.asExpr() and
+ exists(SafeJsonIoConfig sji | sji.hasFlowToExpr(ma.getArgument(1)))
+ )
+ }
}
from DataFlow::PathNode source, DataFlow::PathNode sink, UnsafeDeserializationConfig conf
diff --git a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql b/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql
index 7d072091245..02840afaf65 100644
--- a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql
+++ b/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql
@@ -4,7 +4,7 @@
* may cause redirection to malicious web sites.
* @kind path-problem
* @problem.severity error
- * @security-severity 2.7
+ * @security-severity 6.1
* @precision high
* @id java/unvalidated-url-redirection
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql b/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql
index 4f60a15d8a6..a8157748d7b 100644
--- a/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql
+++ b/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql
@@ -4,7 +4,7 @@
* may cause redirection to malicious web sites.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 2.7
+ * @security-severity 6.1
* @precision medium
* @id java/unvalidated-url-redirection-local
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-611/XXE.ql b/java/ql/src/Security/CWE/CWE-611/XXE.ql
index dc277337769..bfcedb19d17 100644
--- a/java/ql/src/Security/CWE/CWE-611/XXE.ql
+++ b/java/ql/src/Security/CWE/CWE-611/XXE.ql
@@ -4,7 +4,7 @@
* references may lead to disclosure of confidential data or denial of service.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.1
* @precision high
* @id java/xxe
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-614/InsecureCookie.ql b/java/ql/src/Security/CWE/CWE-614/InsecureCookie.ql
index ef6d143ece8..d71be47bc79 100644
--- a/java/ql/src/Security/CWE/CWE-614/InsecureCookie.ql
+++ b/java/ql/src/Security/CWE/CWE-614/InsecureCookie.ql
@@ -4,7 +4,7 @@
* interception.
* @kind problem
* @problem.severity error
- * @security-severity 2.9
+ * @security-severity 5.0
* @precision high
* @id java/insecure-cookie
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-643/XPathInjection.ql b/java/ql/src/Security/CWE/CWE-643/XPathInjection.ql
index 0dd73370569..9e2d1c1a2ac 100644
--- a/java/ql/src/Security/CWE/CWE-643/XPathInjection.ql
+++ b/java/ql/src/Security/CWE/CWE-643/XPathInjection.ql
@@ -4,7 +4,7 @@
* malicious code by the user.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision high
* @id java/xml/xpath-injection
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-681/NumericCastTainted.ql b/java/ql/src/Security/CWE/CWE-681/NumericCastTainted.ql
index 0518b99e221..fcc2651ae9e 100644
--- a/java/ql/src/Security/CWE/CWE-681/NumericCastTainted.ql
+++ b/java/ql/src/Security/CWE/CWE-681/NumericCastTainted.ql
@@ -4,7 +4,7 @@
* can cause unexpected truncation.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.0
* @precision high
* @id java/tainted-numeric-cast
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-681/NumericCastTaintedLocal.ql b/java/ql/src/Security/CWE/CWE-681/NumericCastTaintedLocal.ql
index 519e4c398ee..ad02cb21bc7 100644
--- a/java/ql/src/Security/CWE/CWE-681/NumericCastTaintedLocal.ql
+++ b/java/ql/src/Security/CWE/CWE-681/NumericCastTaintedLocal.ql
@@ -4,7 +4,7 @@
* can cause unexpected truncation.
* @kind path-problem
* @problem.severity recommendation
- * @security-severity 5.9
+ * @security-severity 9.0
* @precision medium
* @id java/tainted-numeric-cast-local
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-732/ReadingFromWorldWritableFile.ql b/java/ql/src/Security/CWE/CWE-732/ReadingFromWorldWritableFile.ql
index 3797f11dfd5..7d2a309c6c0 100644
--- a/java/ql/src/Security/CWE/CWE-732/ReadingFromWorldWritableFile.ql
+++ b/java/ql/src/Security/CWE/CWE-732/ReadingFromWorldWritableFile.ql
@@ -4,7 +4,7 @@
* the file may be modified or removed by external actors.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision high
* @id java/world-writable-file-read
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql
index 5300e3864ef..13cb2a7a69d 100644
--- a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql
+++ b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql
@@ -3,7 +3,7 @@
* @description Using a hard-coded credential in a call to a sensitive Java API may compromise security.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision medium
* @id java/hardcoded-credential-api-call
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsComparison.ql b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsComparison.ql
index 8583f4bef39..d43530f7d69 100644
--- a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsComparison.ql
+++ b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsComparison.ql
@@ -3,7 +3,7 @@
* @description Comparing a parameter to a hard-coded credential may compromise security.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision low
* @id java/hardcoded-credential-comparison
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsSourceCall.ql b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsSourceCall.ql
index 724916f1511..e14188905fa 100644
--- a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsSourceCall.ql
+++ b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsSourceCall.ql
@@ -3,7 +3,7 @@
* @description Using a hard-coded credential in a sensitive call may compromise security.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision low
* @id java/hardcoded-credential-sensitive-call
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-798/HardcodedPasswordField.ql b/java/ql/src/Security/CWE/CWE-798/HardcodedPasswordField.ql
index 4464268a5ec..0a98c000300 100644
--- a/java/ql/src/Security/CWE/CWE-798/HardcodedPasswordField.ql
+++ b/java/ql/src/Security/CWE/CWE-798/HardcodedPasswordField.ql
@@ -3,7 +3,7 @@
* @description Hard-coding a password string may compromise security.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 9.8
* @precision low
* @id java/hardcoded-password-field
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-807/ConditionalBypass.ql b/java/ql/src/Security/CWE/CWE-807/ConditionalBypass.ql
index 6f1c7275bb4..0dca7acd64d 100644
--- a/java/ql/src/Security/CWE/CWE-807/ConditionalBypass.ql
+++ b/java/ql/src/Security/CWE/CWE-807/ConditionalBypass.ql
@@ -4,7 +4,7 @@
* passing through authentication systems.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision medium
* @id java/user-controlled-bypass
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-807/TaintedPermissionsCheck.ql b/java/ql/src/Security/CWE/CWE-807/TaintedPermissionsCheck.ql
index 7eb03c1ecd7..beabdead5af 100644
--- a/java/ql/src/Security/CWE/CWE-807/TaintedPermissionsCheck.ql
+++ b/java/ql/src/Security/CWE/CWE-807/TaintedPermissionsCheck.ql
@@ -4,7 +4,7 @@
* permissions being granted.
* @kind path-problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 7.8
* @precision high
* @id java/tainted-permissions-check
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql b/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql
index d3b833eaf72..0123354572d 100644
--- a/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql
+++ b/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql
@@ -3,7 +3,7 @@
* @description Non-HTTPS connections can be intercepted by third parties.
* @kind problem
* @problem.severity error
- * @security-severity 5.9
+ * @security-severity 8.1
* @precision very-high
* @id java/maven/non-https-url
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-833/LockOrderInconsistency.ql b/java/ql/src/Security/CWE/CWE-833/LockOrderInconsistency.ql
index 241965f4b09..5ad653bd6dd 100644
--- a/java/ql/src/Security/CWE/CWE-833/LockOrderInconsistency.ql
+++ b/java/ql/src/Security/CWE/CWE-833/LockOrderInconsistency.ql
@@ -3,7 +3,7 @@
* @description Acquiring multiple locks in a different order may cause deadlock.
* @kind problem
* @problem.severity recommendation
- * @security-severity 6.9
+ * @security-severity 5.0
* @precision medium
* @id java/lock-order-inconsistency
* @tags security
diff --git a/java/ql/src/Security/CWE/CWE-835/InfiniteLoop.ql b/java/ql/src/Security/CWE/CWE-835/InfiniteLoop.ql
index 4fe1c38c6d5..35f951d6d52 100644
--- a/java/ql/src/Security/CWE/CWE-835/InfiniteLoop.ql
+++ b/java/ql/src/Security/CWE/CWE-835/InfiniteLoop.ql
@@ -5,7 +5,7 @@
* looping.
* @kind problem
* @problem.severity warning
- * @security-severity 3.6
+ * @security-severity 7.5
* @precision medium
* @id java/unreachable-exit-in-loop
* @tags security
diff --git a/java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.java b/java/ql/src/Security/CWE/CWE-918/RequestForgery.java
similarity index 100%
rename from java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.java
rename to java/ql/src/Security/CWE/CWE-918/RequestForgery.java
diff --git a/java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.qhelp b/java/ql/src/Security/CWE/CWE-918/RequestForgery.qhelp
similarity index 55%
rename from java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.qhelp
rename to java/ql/src/Security/CWE/CWE-918/RequestForgery.qhelp
index 0a34747413d..f89198ee378 100644
--- a/java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.qhelp
+++ b/java/ql/src/Security/CWE/CWE-918/RequestForgery.qhelp
@@ -5,22 +5,24 @@
-Directly incorporating user input into a HTTP request without validating the input
-can facilitate Server Side Request Forgery (SSRF) attacks. In these attacks, the server
-may be tricked into making a request and interacting with an attacker-controlled server.
+
Directly incorporating user input into an HTTP request without validating the input
+can facilitate server-side request forgery (SSRF) attacks. In these attacks, the server
+may be tricked into making a request and interacting with an attacker-controlled server.
-To guard against SSRF attacks, it is advisable to avoid putting user input
-directly into the request URL. Instead, maintain a list of authorized
-URLs on the server; then choose from that list based on the user input provided.
+To guard against SSRF attacks, you should avoid putting user-provided input
+directly into a request URL. Instead, maintain a list of authorized
+URLs on the server; then choose from that list based on the input provided.
+Alternatively, ensure requests constructed from user input are limited to
+a particular host or more restrictive URL prefix.
-The following example shows an HTTP request parameter being used directly in a forming a
+
The following example shows an HTTP request parameter being used directly to form a
new request without validating the input, which facilitates SSRF attacks.
It also shows how to remedy the problem by validating the user input against a known fixed string.
diff --git a/java/ql/src/Security/CWE/CWE-918/RequestForgery.ql b/java/ql/src/Security/CWE/CWE-918/RequestForgery.ql
new file mode 100644
index 00000000000..7a1ff4ac933
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-918/RequestForgery.ql
@@ -0,0 +1,20 @@
+/**
+ * @name Server-side request forgery
+ * @description Making web requests based on unvalidated user-input
+ * may cause the server to communicate with malicious servers.
+ * @kind path-problem
+ * @problem.severity error
+ * @precision high
+ * @id java/ssrf
+ * @tags security
+ * external/cwe/cwe-918
+ */
+
+import java
+import semmle.code.java.security.RequestForgeryConfig
+import DataFlow::PathGraph
+
+from DataFlow::PathNode source, DataFlow::PathNode sink, RequestForgeryConfiguration conf
+where conf.hasFlowPath(source, sink)
+select sink.getNode(), source, sink, "Potential server-side request forgery due to $@.",
+ source.getNode(), "a user-provided value"
diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/BeanShellInjection.java b/java/ql/src/experimental/Security/CWE/CWE-094/BeanShellInjection.java
new file mode 100644
index 00000000000..ee98929312b
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-094/BeanShellInjection.java
@@ -0,0 +1,33 @@
+import bsh.Interpreter;
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.scripting.bsh.BshScriptEvaluator;
+import org.springframework.scripting.support.StaticScriptSource;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class BeanShellInjection {
+
+ @GetMapping(value = "bad1")
+ public void bad1(HttpServletRequest request) {
+ String code = request.getParameter("code");
+ BshScriptEvaluator evaluator = new BshScriptEvaluator();
+ evaluator.evaluate(new StaticScriptSource(code)); //bad
+ }
+
+ @GetMapping(value = "bad2")
+ public void bad2(HttpServletRequest request) throws Exception {
+ String code = request.getParameter("code");
+ Interpreter interpreter = new Interpreter();
+ interpreter.eval(code); //bad
+ }
+
+ @GetMapping(value = "bad3")
+ public void bad3(HttpServletRequest request) {
+ String code = request.getParameter("code");
+ StaticScriptSource staticScriptSource = new StaticScriptSource("test");
+ staticScriptSource.setScript(code);
+ BshScriptEvaluator evaluator = new BshScriptEvaluator();
+ evaluator.evaluate(staticScriptSource); //bad
+ }
+}
diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/BeanShellInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/BeanShellInjection.qhelp
new file mode 100644
index 00000000000..f86d7759552
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-094/BeanShellInjection.qhelp
@@ -0,0 +1,34 @@
+
+
+
+
+
+BeanShell is a small, free, embeddable Java source interpreter with object scripting language
+features, written in Java. BeanShell dynamically executes standard Java syntax and extends it
+with common scripting conveniences such as loose types, commands, and method closures like
+those in Perl and JavaScript. If a BeanShell expression is built using attacker-controlled data,
+and then evaluated, then it may allow the attacker to run arbitrary code.
+
+
+
+
+
+It is generally recommended to avoid using untrusted input in a BeanShell expression.
+If it is not possible, BeanShell expressions should be run in a sandbox that allows accessing only
+explicitly allowed classes.
+
+
+
+
+
+The following example uses untrusted data to build and run a BeanShell expression.
+
+
+
+
+
+
+CVE-2016-2510:BeanShell Injection.
+
+
+
diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/BeanShellInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-094/BeanShellInjection.ql
new file mode 100644
index 00000000000..b8301d4f977
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-094/BeanShellInjection.ql
@@ -0,0 +1,47 @@
+/**
+ * @name BeanShell injection
+ * @description Evaluation of a user-controlled BeanShell expression
+ * may lead to arbitrary code execution.
+ * @kind path-problem
+ * @problem.severity error
+ * @precision high
+ * @id java/beanshell-injection
+ * @tags security
+ * external/cwe/cwe-094
+ */
+
+import java
+import BeanShellInjection
+import semmle.code.java.dataflow.FlowSources
+import DataFlow::PathGraph
+
+class BeanShellInjectionConfig extends TaintTracking::Configuration {
+ BeanShellInjectionConfig() { this = "BeanShellInjectionConfig" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof BeanShellInjectionSink }
+
+ override predicate isAdditionalTaintStep(DataFlow::Node prod, DataFlow::Node succ) {
+ exists(ClassInstanceExpr cie |
+ cie.getConstructedType()
+ .hasQualifiedName("org.springframework.scripting.support", "StaticScriptSource") and
+ cie.getArgument(0) = prod.asExpr() and
+ cie = succ.asExpr()
+ )
+ or
+ exists(MethodAccess ma |
+ ma.getMethod().hasName("setScript") and
+ ma.getMethod()
+ .getDeclaringType()
+ .hasQualifiedName("org.springframework.scripting.support", "StaticScriptSource") and
+ ma.getArgument(0) = prod.asExpr() and
+ ma.getQualifier() = succ.asExpr()
+ )
+ }
+}
+
+from DataFlow::PathNode source, DataFlow::PathNode sink, BeanShellInjectionConfig conf
+where conf.hasFlowPath(source, sink)
+select sink.getNode(), source, sink, "BeanShell injection from $@.", source.getNode(),
+ "this user input"
diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/BeanShellInjection.qll b/java/ql/src/experimental/Security/CWE/CWE-094/BeanShellInjection.qll
new file mode 100644
index 00000000000..3d1cc122339
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-094/BeanShellInjection.qll
@@ -0,0 +1,28 @@
+import java
+import semmle.code.java.dataflow.FlowSources
+
+/** A call to `Interpreter.eval`. */
+class InterpreterEvalCall extends MethodAccess {
+ InterpreterEvalCall() {
+ this.getMethod().hasName("eval") and
+ this.getMethod().getDeclaringType().hasQualifiedName("bsh", "Interpreter")
+ }
+}
+
+/** A call to `BshScriptEvaluator.evaluate`. */
+class BshScriptEvaluatorEvaluateCall extends MethodAccess {
+ BshScriptEvaluatorEvaluateCall() {
+ this.getMethod().hasName("evaluate") and
+ this.getMethod()
+ .getDeclaringType()
+ .hasQualifiedName("org.springframework.scripting.bsh", "BshScriptEvaluator")
+ }
+}
+
+/** A sink for BeanShell expression injection vulnerabilities. */
+class BeanShellInjectionSink extends DataFlow::Node {
+ BeanShellInjectionSink() {
+ this.asExpr() = any(InterpreterEvalCall iec).getArgument(0) or
+ this.asExpr() = any(BshScriptEvaluatorEvaluateCall bseec).getArgument(0)
+ }
+}
diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql
index 4c0dc624d07..2aa2d487cae 100644
--- a/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql
+++ b/java/ql/src/experimental/Security/CWE/CWE-1004/SensitiveCookieNotHttpOnly.ql
@@ -74,12 +74,9 @@ class MatchesHttpOnlyConfiguration extends TaintTracking2::Configuration {
}
}
-/** A class descended from `javax.servlet.http.Cookie` or `javax/jakarta.ws.rs.core.Cookie`. */
+/** A class descended from `javax.servlet.http.Cookie`. */
class CookieClass extends RefType {
- CookieClass() {
- this.getASupertype*()
- .hasQualifiedName(["javax.servlet.http", "javax.ws.rs.core", "jakarta.ws.rs.core"], "Cookie")
- }
+ CookieClass() { this.getASupertype*().hasQualifiedName("javax.servlet.http", "Cookie") }
}
/** Holds if `expr` is any boolean-typed expression other than literal `false`. */
diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql
index 97d2f6dad33..8945f30fd45 100644
--- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql
+++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql
@@ -194,15 +194,6 @@ predicate urlOpen(DataFlow::Node node1, DataFlow::Node node2) {
)
}
-/** Constructor of `BasicRequestLine` */
-predicate basicRequestLine(DataFlow::Node node1, DataFlow::Node node2) {
- exists(ConstructorCall mcc |
- mcc.getConstructedType().hasQualifiedName("org.apache.http.message", "BasicRequestLine") and
- mcc.getArgument(1) = node1.asExpr() and // `BasicRequestLine(String method, String uri, ProtocolVersion version)
- node2.asExpr() = mcc
- )
-}
-
class BasicAuthFlowConfig extends TaintTracking::Configuration {
BasicAuthFlowConfig() { this = "InsecureBasicAuth::BasicAuthFlowConfig" }
@@ -236,7 +227,6 @@ class BasicAuthFlowConfig extends TaintTracking::Configuration {
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
apacheHttpRequest(node1, node2) or
createURI(node1, node2) or
- basicRequestLine(node1, node2) or
createURL(node1, node2) or
urlOpen(node1, node2)
}
diff --git a/java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.ql b/java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.ql
deleted file mode 100644
index c3bf787881f..00000000000
--- a/java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.ql
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * @name Server Side Request Forgery (SSRF)
- * @description Making web requests based on unvalidated user-input
- * may cause server to communicate with malicious servers.
- * @kind path-problem
- * @problem.severity error
- * @precision high
- * @id java/ssrf
- * @tags security
- * external/cwe/cwe-918
- */
-
-import java
-import semmle.code.java.dataflow.FlowSources
-import RequestForgery
-import DataFlow::PathGraph
-
-class RequestForgeryConfiguration extends TaintTracking::Configuration {
- RequestForgeryConfiguration() { this = "Server Side Request Forgery" }
-
- override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof RequestForgerySink }
-
- override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
- requestForgeryStep(pred, succ)
- }
-}
-
-from DataFlow::PathNode source, DataFlow::PathNode sink, RequestForgeryConfiguration conf
-where conf.hasFlowPath(source, sink)
-select sink.getNode(), source, sink, "Potential server side request forgery due to $@.",
- source.getNode(), "a user-provided value"
diff --git a/java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.qll b/java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.qll
deleted file mode 100644
index 3fc52ddca76..00000000000
--- a/java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.qll
+++ /dev/null
@@ -1,192 +0,0 @@
-import java
-import semmle.code.java.frameworks.Networking
-import semmle.code.java.frameworks.ApacheHttp
-import semmle.code.java.frameworks.spring.Spring
-import semmle.code.java.frameworks.JaxWS
-import semmle.code.java.frameworks.javase.Http
-import semmle.code.java.dataflow.DataFlow
-
-predicate requestForgeryStep(DataFlow::Node pred, DataFlow::Node succ) {
- // propagate to a URI when its host is assigned to
- exists(UriCreation c | c.getHostArg() = pred.asExpr() | succ.asExpr() = c)
- or
- // propagate to a URL when its host is assigned to
- exists(UrlConstructorCall c | c.getHostArg() = pred.asExpr() | succ.asExpr() = c)
- or
- // propagate to a RequestEntity when its url is assigned to
- exists(MethodAccess m |
- m.getMethod().getDeclaringType() instanceof SpringRequestEntity and
- (
- m.getMethod().hasName(["get", "post", "head", "delete", "options", "patch", "put"]) and
- m.getArgument(0) = pred.asExpr() and
- m = succ.asExpr()
- or
- m.getMethod().hasName("method") and
- m.getArgument(1) = pred.asExpr() and
- m = succ.asExpr()
- )
- )
- or
- // propagate from a `RequestEntity<>$BodyBuilder` to a `RequestEntity`
- // when the builder is tainted
- exists(MethodAccess m, RefType t |
- m.getMethod().getDeclaringType() = t and
- t.hasQualifiedName("org.springframework.http", "RequestEntity<>$BodyBuilder") and
- m.getMethod().hasName("body") and
- m.getQualifier() = pred.asExpr() and
- m = succ.asExpr()
- )
-}
-
-/** A data flow sink for request forgery vulnerabilities. */
-abstract class RequestForgerySink extends DataFlow::Node { }
-
-/**
- * An argument to an url `openConnection` or `openStream` call
- * taken as a sink for request forgery vulnerabilities.
- */
-private class UrlOpen extends RequestForgerySink {
- UrlOpen() {
- exists(MethodAccess ma |
- ma.getMethod() instanceof UrlOpenConnectionMethod or
- ma.getMethod() instanceof UrlOpenStreamMethod
- |
- this.asExpr() = ma.getQualifier()
- )
- }
-}
-
-/**
- * An argument to an Apache `setURI` call taken as a
- * sink for request forgery vulnerabilities.
- */
-private class ApacheSetUri extends RequestForgerySink {
- ApacheSetUri() {
- exists(MethodAccess ma |
- ma.getReceiverType() instanceof ApacheHttpRequest and
- ma.getMethod().hasName("setURI")
- |
- this.asExpr() = ma.getArgument(0)
- )
- }
-}
-
-/**
- * An argument to any Apache Request Instantiation call taken as a
- * sink for request forgery vulnerabilities.
- */
-private class ApacheHttpRequestInstantiation extends RequestForgerySink {
- ApacheHttpRequestInstantiation() {
- exists(ClassInstanceExpr c | c.getConstructedType() instanceof ApacheHttpRequest |
- this.asExpr() = c.getArgument(0)
- )
- }
-}
-
-/**
- * An argument to a Apache RequestBuilder method call taken as a
- * sink for request forgery vulnerabilities.
- */
-private class ApacheHttpRequestBuilderArgument extends RequestForgerySink {
- ApacheHttpRequestBuilderArgument() {
- exists(MethodAccess ma |
- ma.getReceiverType() instanceof TypeApacheHttpRequestBuilder and
- ma.getMethod().hasName(["setURI", "get", "post", "put", "optons", "head", "delete"])
- |
- this.asExpr() = ma.getArgument(0)
- )
- }
-}
-
-/**
- * An argument to any Java.net.http.request Instantiation call taken as a
- * sink for request forgery vulnerabilities.
- */
-private class HttpRequestNewBuilder extends RequestForgerySink {
- HttpRequestNewBuilder() {
- exists(MethodAccess call |
- call.getCallee().hasName("newBuilder") and
- call.getMethod().getDeclaringType().getName() = "HttpRequest"
- |
- this.asExpr() = call.getArgument(0)
- )
- }
-}
-
-/**
- * An argument to an Http Builder `uri` call taken as a
- * sink for request forgery vulnerabilities.
- */
-private class HttpBuilderUriArgument extends RequestForgerySink {
- HttpBuilderUriArgument() {
- exists(MethodAccess ma | ma.getMethod() instanceof HttpBuilderUri |
- this.asExpr() = ma.getArgument(0)
- )
- }
-}
-
-/**
- * An argument to a Spring Rest Template method call taken as a
- * sink for request forgery vulnerabilities.
- */
-private class SpringRestTemplateArgument extends RequestForgerySink {
- SpringRestTemplateArgument() {
- exists(MethodAccess ma |
- this.asExpr() = ma.getMethod().(SpringRestTemplateUrlMethods).getUrlArgument(ma)
- )
- }
-}
-
-/**
- * An argument to `javax.ws.rs.Client`s `target` method call taken as a
- * sink for request forgery vulnerabilities.
- */
-private class JaxRsClientTarget extends RequestForgerySink {
- JaxRsClientTarget() {
- exists(MethodAccess ma |
- ma.getMethod().getDeclaringType() instanceof JaxRsClient and
- ma.getMethod().hasName("target")
- |
- this.asExpr() = ma.getArgument(0)
- )
- }
-}
-
-/**
- * An argument to `org.springframework.http.RequestEntity`s constructor call
- * which is an URI taken as a sink for request forgery vulnerabilities.
- */
-private class RequestEntityUriArg extends RequestForgerySink {
- RequestEntityUriArg() {
- exists(ClassInstanceExpr e, Argument a |
- e.getConstructedType() instanceof SpringRequestEntity and
- e.getAnArgument() = a and
- a.getType() instanceof TypeUri and
- this.asExpr() = a
- )
- }
-}
-
-/**
- * A class representing all Spring Rest Template methods
- * which take an URL as an argument.
- */
-private class SpringRestTemplateUrlMethods extends Method {
- SpringRestTemplateUrlMethods() {
- this.getDeclaringType() instanceof SpringRestTemplate and
- this.hasName([
- "doExecute", "postForEntity", "postForLocation", "postForObject", "put", "exchange",
- "execute", "getForEntity", "getForObject", "patchForObject"
- ])
- }
-
- /**
- * Gets the argument which corresponds to a URL argument
- * passed as a `java.net.URL` object or as a string or the like
- */
- Argument getUrlArgument(MethodAccess ma) {
- // doExecute(URI url, HttpMethod method, RequestCallback requestCallback,
- // ResponseExtractor responseExtractor)
- result = ma.getArgument(0)
- }
-}
diff --git a/java/ql/src/semmle/code/java/StringFormat.qll b/java/ql/src/semmle/code/java/StringFormat.qll
index aa77feafeb9..cc37ee8212a 100644
--- a/java/ql/src/semmle/code/java/StringFormat.qll
+++ b/java/ql/src/semmle/code/java/StringFormat.qll
@@ -175,6 +175,19 @@ class FormattingCall extends Call {
)
}
+ /** Gets the `i`th argument to be formatted. The index `i` is one-based. */
+ Expr getArgumentToBeFormatted(int i) {
+ i >= 1 and
+ if this.hasExplicitVarargsArray()
+ then
+ result =
+ this.getArgument(1 + this.getFormatStringIndex())
+ .(ArrayCreationExpr)
+ .getInit()
+ .getInit(i - 1)
+ else result = this.getArgument(this.getFormatStringIndex() + i)
+ }
+
/** Holds if the varargs argument is given as an explicit array. */
private predicate hasExplicitVarargsArray() {
this.getNumArgument() = this.getFormatStringIndex() + 2 and
@@ -353,6 +366,11 @@ class FormatString extends string {
* is not referred by any format specifier.
*/
/*abstract*/ int getASkippedFmtSpecIndex() { none() }
+
+ /**
+ * Gets an offset (zero-based) in this format string where argument `argNo` (1-based) will be interpolated, if any.
+ */
+ int getAnArgUsageOffset(int argNo) { none() }
}
private class PrintfFormatString extends FormatString {
@@ -425,6 +443,22 @@ private class PrintfFormatString extends FormatString {
result > count(int i | fmtSpecRefersToSequentialIndex(i)) and
not result = fmtSpecRefersToSpecificIndex(_)
}
+
+ private int getFmtSpecRank(int specOffset) {
+ rank[result](int i | this.fmtSpecIsRef(i)) = specOffset
+ }
+
+ override int getAnArgUsageOffset(int argNo) {
+ argNo = fmtSpecRefersToSpecificIndex(result)
+ or
+ result = rank[argNo](int i | fmtSpecRefersToSequentialIndex(i))
+ or
+ fmtSpecRefersToPrevious(result) and
+ exists(int previousOffset |
+ getFmtSpecRank(previousOffset) = getFmtSpecRank(result) - 1 and
+ previousOffset = getAnArgUsageOffset(argNo)
+ )
+ }
}
private class LoggerFormatString extends FormatString {
@@ -449,4 +483,6 @@ private class LoggerFormatString extends FormatString {
}
override int getMaxFmtSpecIndex() { result = count(int i | fmtPlaceholder(i)) }
+
+ override int getAnArgUsageOffset(int argNo) { result = rank[argNo](int i | fmtPlaceholder(i)) }
}
diff --git a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll
index 8080bd28ab6..535c667698f 100644
--- a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll
+++ b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll
@@ -81,6 +81,9 @@ private module Frameworks {
private import semmle.code.java.frameworks.apache.Lang
private import semmle.code.java.frameworks.guava.Guava
private import semmle.code.java.frameworks.jackson.JacksonSerializability
+ private import semmle.code.java.frameworks.JaxWS
+ private import semmle.code.java.frameworks.spring.SpringHttp
+ private import semmle.code.java.frameworks.spring.SpringWebClient
private import semmle.code.java.security.ResponseSplitting
private import semmle.code.java.security.InformationLeak
private import semmle.code.java.security.XSS
@@ -208,6 +211,8 @@ private predicate sinkModelCsv(string row) {
// Open URL
"java.net;URL;false;openConnection;;;Argument[-1];open-url",
"java.net;URL;false;openStream;;;Argument[-1];open-url",
+ "java.net.http;HttpRequest;false;newBuilder;;;Argument[0];open-url",
+ "java.net.http;HttpRequest$Builder;false;uri;;;Argument[0];open-url",
// Create file
"java.io;FileOutputStream;false;FileOutputStream;;;Argument[0];create-file",
"java.io;RandomAccessFile;false;RandomAccessFile;;;Argument[0];create-file",
@@ -247,6 +252,8 @@ private predicate summaryModelCsv(string row) {
"javax.xml.transform.stream;StreamSource;false;getInputStream;;;Argument[-1];ReturnValue;taint",
"java.nio;ByteBuffer;false;get;;;Argument[-1];ReturnValue;taint",
"java.net;URI;false;toURL;;;Argument[-1];ReturnValue;taint",
+ "java.net;URI;false;toString;;;Argument[-1];ReturnValue;taint",
+ "java.net;URI;false;toAsciiString;;;Argument[-1];ReturnValue;taint",
"java.io;File;false;toURI;;;Argument[-1];ReturnValue;taint",
"java.io;File;false;toPath;;;Argument[-1];ReturnValue;taint",
"java.nio.file;Path;false;toFile;;;Argument[-1];ReturnValue;taint",
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll
index 4e1cd281488..a55e65a81f6 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll
@@ -168,7 +168,13 @@ module Consistency {
msg = "ArgumentNode is missing PostUpdateNode."
}
- query predicate postWithInFlow(PostUpdateNode n, string msg) {
+ // This predicate helps the compiler forget that in some languages
+ // it is impossible for a `PostUpdateNode` to be the target of
+ // `simpleLocalFlowStep`.
+ private predicate isPostUpdateNode(Node n) { n instanceof PostUpdateNode or none() }
+
+ query predicate postWithInFlow(Node n, string msg) {
+ isPostUpdateNode(n) and
simpleLocalFlowStep(_, n) and
msg = "PostUpdateNode should not be the target of local flow."
}
diff --git a/java/ql/src/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll b/java/ql/src/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll
index d28dd2206ac..974982a9c29 100644
--- a/java/ql/src/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll
+++ b/java/ql/src/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll
@@ -70,9 +70,22 @@ predicate summaryElement(DataFlowCallable c, string input, string output, string
)
}
+private FieldContent parseField(string c) {
+ External::specSplit(_, c, _) and
+ exists(string fieldRegex, string package, string className, string fieldName |
+ fieldRegex = "^Field\\[(.*)\\.([^.]+)\\.([^.]+)\\]$" and
+ package = c.regexpCapture(fieldRegex, 1) and
+ className = c.regexpCapture(fieldRegex, 2) and
+ fieldName = c.regexpCapture(fieldRegex, 3) and
+ result.getField().hasQualifiedName(package, className, fieldName)
+ )
+}
+
/** Gets the summary component for specification component `c`, if any. */
bindingset[c]
SummaryComponent interpretComponentSpecific(string c) {
+ result = SummaryComponent::content(parseField(c))
+ or
c = "ArrayElement" and result = SummaryComponent::content(any(ArrayContent c0))
or
c = "Element" and result = SummaryComponent::content(any(CollectionContent c0))
diff --git a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll
index 80cb589e6f2..952efe9f7dc 100644
--- a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll
+++ b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll
@@ -92,6 +92,39 @@ private class ApacheHttpXssSink extends SinkModelCsv {
}
}
+private class ApacheHttpOpenUrlSink extends SinkModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "org.apache.http;HttpRequest;true;setURI;;;Argument[0];open-url",
+ "org.apache.http.message;BasicHttpRequest;false;BasicHttpRequest;(RequestLine);;Argument[0];open-url",
+ "org.apache.http.message;BasicHttpRequest;false;BasicHttpRequest;(String,String);;Argument[1];open-url",
+ "org.apache.http.message;BasicHttpRequest;false;BasicHttpRequest;(String,String,ProtocolVersion);;Argument[1];open-url",
+ "org.apache.http.message;BasicHttpEntityEnclosingRequest;false;BasicHttpEntityEnclosingRequest;(RequestLine);;Argument[0];open-url",
+ "org.apache.http.message;BasicHttpEntityEnclosingRequest;false;BasicHttpEntityEnclosingRequest;(String,String);;Argument[1];open-url",
+ "org.apache.http.message;BasicHttpEntityEnclosingRequest;false;BasicHttpEntityEnclosingRequest;(String,String,ProtocolVersion);;Argument[1];open-url",
+ "org.apache.http.client.methods;HttpGet;false;HttpGet;;;Argument[0];open-url",
+ "org.apache.http.client.methods;HttpHead;false;HttpHead;;;Argument[0];open-url",
+ "org.apache.http.client.methods;HttpPut;false;HttpPut;;;Argument[0];open-url",
+ "org.apache.http.client.methods;HttpPost;false;HttpPost;;;Argument[0];open-url",
+ "org.apache.http.client.methods;HttpDelete;false;HttpDelete;;;Argument[0];open-url",
+ "org.apache.http.client.methods;HttpOptions;false;HttpOptions;;;Argument[0];open-url",
+ "org.apache.http.client.methods;HttpTrace;false;HttpTrace;;;Argument[0];open-url",
+ "org.apache.http.client.methods;HttpPatch;false;HttpPatch;;;Argument[0];open-url",
+ "org.apache.http.client.methods;HttpRequestBase;true;setURI;;;Argument[0];open-url",
+ "org.apache.http.client.methods;RequestBuilder;false;setUri;;;Argument[0];open-url",
+ "org.apache.http.client.methods;RequestBuilder;false;get;;;Argument[0];open-url",
+ "org.apache.http.client.methods;RequestBuilder;false;post;;;Argument[0];open-url",
+ "org.apache.http.client.methods;RequestBuilder;false;put;;;Argument[0];open-url",
+ "org.apache.http.client.methods;RequestBuilder;false;options;;;Argument[0];open-url",
+ "org.apache.http.client.methods;RequestBuilder;false;head;;;Argument[0];open-url",
+ "org.apache.http.client.methods;RequestBuilder;false;delete;;;Argument[0];open-url",
+ "org.apache.http.client.methods;RequestBuilder;false;trace;;;Argument[0];open-url",
+ "org.apache.http.client.methods;RequestBuilder;false;patch;;;Argument[0];open-url"
+ ]
+ }
+}
+
private class ApacheHttpFlowStep extends SummaryModelCsv {
override predicate row(string row) {
row =
@@ -228,7 +261,10 @@ private class ApacheHttpFlowStep extends SummaryModelCsv {
"org.apache.hc.core5.util;CharArrayBuffer;true;toString;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;substring;(int,int);;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;subSequence;(int,int);;Argument[-1];ReturnValue;taint",
- "org.apache.hc.core5.util;CharArrayBuffer;true;substringTrimmed;(int,int);;Argument[-1];ReturnValue;taint"
+ "org.apache.hc.core5.util;CharArrayBuffer;true;substringTrimmed;(int,int);;Argument[-1];ReturnValue;taint",
+ "org.apache.http.message;BasicRequestLine;false;BasicRequestLine;;;Argument[1];Argument[-1];taint",
+ "org.apache.http;RequestLine;true;getUri;;;Argument[-1];ReturnValue;taint",
+ "org.apache.http;RequestLine;true;toString;;;Argument[-1];ReturnValue;taint"
]
}
}
diff --git a/java/ql/src/semmle/code/java/frameworks/Castor.qll b/java/ql/src/semmle/code/java/frameworks/Castor.qll
new file mode 100644
index 00000000000..f1e1b825725
--- /dev/null
+++ b/java/ql/src/semmle/code/java/frameworks/Castor.qll
@@ -0,0 +1,20 @@
+/**
+ * Provides classes and predicates for working with the Castor framework.
+ */
+
+import java
+
+/**
+ * The class `org.exolab.castor.xml.Unmarshaller`.
+ */
+class CastorUnmarshaller extends RefType {
+ CastorUnmarshaller() { this.hasQualifiedName("org.exolab.castor.xml", "Unmarshaller") }
+}
+
+/** A method with the name `unmarshal` declared in `org.exolab.castor.xml.Unmarshaller`. */
+class CastorUnmarshalMethod extends Method {
+ CastorUnmarshalMethod() {
+ this.getDeclaringType() instanceof CastorUnmarshaller and
+ this.getName() = "unmarshal"
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/HessianBurlap.qll b/java/ql/src/semmle/code/java/frameworks/HessianBurlap.qll
new file mode 100644
index 00000000000..95803d192a7
--- /dev/null
+++ b/java/ql/src/semmle/code/java/frameworks/HessianBurlap.qll
@@ -0,0 +1,49 @@
+/**
+ * Provides classes and predicates for working with the HessianBurlap framework.
+ */
+
+import java
+
+/**
+ * The classes `[com.alibaba.]com.caucho.hessian.io.AbstractHessianInput` or `[com.alibaba.]com.caucho.hessian.io.Hessian2StreamingInput`.
+ */
+class UnsafeHessianInput extends RefType {
+ UnsafeHessianInput() {
+ this.hasQualifiedName(["com.caucho.hessian.io", "com.alibaba.com.caucho.hessian.io"],
+ ["AbstractHessianInput", "Hessian2StreamingInput"])
+ }
+}
+
+/**
+ * A AbstractHessianInput or Hessian2StreamingInput subclass readObject method.
+ * This is either `AbstractHessianInput.readObject` or `Hessian2StreamingInput.readObject`.
+ */
+class UnsafeHessianInputReadObjectMethod extends Method {
+ UnsafeHessianInputReadObjectMethod() {
+ this.getDeclaringType().getASupertype*() instanceof UnsafeHessianInput and
+ this.getName() = "readObject"
+ }
+}
+
+/**
+ * The class `com.caucho.burlap.io.BurlapInput`.
+ */
+class BurlapInput extends RefType {
+ BurlapInput() { this.hasQualifiedName("com.caucho.burlap.io", "BurlapInput") }
+}
+
+/** A method with the name `readObject` declared in `com.caucho.burlap.io.BurlapInput`. */
+class BurlapInputReadObjectMethod extends Method {
+ BurlapInputReadObjectMethod() {
+ this.getDeclaringType() instanceof BurlapInput and
+ this.getName() = "readObject"
+ }
+}
+
+/** A method with the name `init` declared in `com.caucho.burlap.io.BurlapInput`. */
+class BurlapInputInitMethod extends Method {
+ BurlapInputInitMethod() {
+ this.getDeclaringType() instanceof BurlapInput and
+ this.getName() = "init"
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/JYaml.qll b/java/ql/src/semmle/code/java/frameworks/JYaml.qll
new file mode 100644
index 00000000000..9d77b86f6c1
--- /dev/null
+++ b/java/ql/src/semmle/code/java/frameworks/JYaml.qll
@@ -0,0 +1,22 @@
+/**
+ * Provides classes and predicates for working with the JYaml framework.
+ */
+
+import java
+
+/**
+ * The class `org.ho.yaml.Yaml` or `org.ho.yaml.YamlConfig`.
+ */
+class JYamlLoader extends RefType {
+ JYamlLoader() { this.hasQualifiedName("org.ho.yaml", ["Yaml", "YamlConfig"]) }
+}
+
+/**
+ * A JYaml unsafe load method, declared on either `Yaml` or `YamlConfig`.
+ */
+class JYamlLoaderUnsafeLoadMethod extends Method {
+ JYamlLoaderUnsafeLoadMethod() {
+ this.getDeclaringType() instanceof JYamlLoader and
+ this.getName() in ["load", "loadType", "loadStream", "loadStreamOfType"]
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll b/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll
index 833db9a9e44..0f5da6c39ea 100644
--- a/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll
@@ -137,6 +137,13 @@ class InterceptorsAnnotation extends Annotation {
* Annotations in the package `javax.jws`.
*/
+/**
+ * A `@javax.jws.WebMethod` annotation.
+ */
+class WebMethodAnnotation extends Annotation {
+ WebMethodAnnotation() { this.getType().hasQualifiedName("javax.jws", "WebMethod") }
+}
+
/**
* A `@javax.jws.WebService` annotation.
*/
diff --git a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
index 50471d68fbf..cd773721dfb 100644
--- a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
@@ -1,4 +1,22 @@
+/**
+ * Definitions relating to JAX-WS (Java/Jakarta API for XML Web Services) and JAX-RS
+ * (Java/Jakarta API for RESTful Web Services).
+ */
+
import java
+private import semmle.code.java.dataflow.ExternalFlow
+private import semmle.code.java.security.XSS
+
+/**
+ * Gets a name for the root package of JAX-RS.
+ */
+string getAJaxRsPackage() { result in ["javax.ws.rs", "jakarta.ws.rs"] }
+
+/**
+ * Gets a name for package `subpackage` within the JAX-RS hierarchy.
+ */
+bindingset[subpackage]
+string getAJaxRsPackage(string subpackage) { result = getAJaxRsPackage() + "." + subpackage }
/**
* A JAX WS endpoint is constructed by the container, and its methods
@@ -13,6 +31,7 @@ class JaxWsEndpoint extends Class {
)
}
+ /** Gets a method annotated with `@WebMethod` or `@WebEndpoint`. */
Callable getARemoteMethod() {
result = this.getACallable() and
exists(AnnotationType a | a = result.getAnAnnotation().getType() |
@@ -28,7 +47,7 @@ class JaxWsEndpoint extends Class {
private predicate hasPathAnnotation(Annotatable annotatable) {
exists(AnnotationType a |
a = annotatable.getAnAnnotation().getType() and
- a.getPackage().getName() = "javax.ws.rs"
+ a.getPackage().getName() = getAJaxRsPackage()
|
a.hasName("Path")
)
@@ -41,7 +60,7 @@ class JaxRsResourceMethod extends Method {
JaxRsResourceMethod() {
exists(AnnotationType a |
a = this.getAnAnnotation().getType() and
- a.getPackage().getName() = "javax.ws.rs"
+ a.getPackage().getName() = getAJaxRsPackage()
|
a.hasName("GET") or
a.hasName("POST") or
@@ -50,6 +69,27 @@ class JaxRsResourceMethod extends Method {
a.hasName("OPTIONS") or
a.hasName("HEAD")
)
+ or
+ // A JaxRS resource method can also inherit these annotations from a supertype, but only if
+ // there are no JaxRS annotations on the method itself
+ this.getAnOverride() instanceof JaxRsResourceMethod and
+ not exists(this.getAnAnnotation().(JaxRSAnnotation))
+ }
+
+ /** Gets an `@Produces` annotation that applies to this method */
+ JaxRSProducesAnnotation getProducesAnnotation() {
+ result = this.getAnAnnotation()
+ or
+ // No direct annotations
+ not this.getAnAnnotation() instanceof JaxRSProducesAnnotation and
+ (
+ // Annotations on a method we've overridden
+ result = this.getAnOverride().getAnAnnotation()
+ or
+ // No annotations on this method, or a method we've overridden, so look to the class
+ not this.getAnOverride().getAnAnnotation() instanceof JaxRSProducesAnnotation and
+ result = this.getDeclaringType().getAnAnnotation()
+ )
}
}
@@ -81,7 +121,7 @@ class JaxRsResourceClass extends Class {
* annotations leading to this resource method.
*/
JaxRsResourceMethod getAResourceMethod() {
- isPublic() and
+ this.isPublic() and
result = this.getACallable()
}
@@ -90,7 +130,7 @@ class JaxRsResourceClass extends Class {
* but is not a resource method e.g. it is not annotated with `@GET` etc.
*/
Callable getASubResourceLocator() {
- result = getAMethod() and
+ result = this.getAMethod() and
not result instanceof JaxRsResourceMethod and
hasPathAnnotation(result)
}
@@ -109,10 +149,10 @@ class JaxRsResourceClass extends Class {
* (existence of particular parameters).
*/
Constructor getAnInjectableConstructor() {
- result = getAConstructor() and
+ result = this.getAConstructor() and
// JaxRs Spec v2.0 - 3.12
// Only root resources are constructed by the JaxRS container.
- isRootResource() and
+ this.isRootResource() and
// JaxRS can only construct the class using constructors that are public, and where the
// container can provide all of the parameters. This includes the no-arg constructor.
result.isPublic() and
@@ -125,29 +165,41 @@ class JaxRsResourceClass extends Class {
* Gets a Callable that may be executed by the JaxRs container, injecting parameters as required.
*/
Callable getAnInjectableCallable() {
- result = getAResourceMethod() or
- result = getAnInjectableConstructor() or
- result = getASubResourceLocator()
+ result = this.getAResourceMethod() or
+ result = this.getAnInjectableConstructor() or
+ result = this.getASubResourceLocator()
}
/**
* Gets a Field that may be injected with a value by the JaxRs container.
*/
Field getAnInjectableField() {
- result = getAField() and
+ result = this.getAField() and
result.getAnAnnotation() instanceof JaxRsInjectionAnnotation
}
}
+/**
+ * An annotation from the `javax.ws.rs` or `jakarta.ws.rs` package hierarchy.
+ */
+class JaxRSAnnotation extends Annotation {
+ JaxRSAnnotation() {
+ exists(AnnotationType a |
+ a = this.getType() and
+ a.getPackage().getName().regexpMatch(["javax\\.ws\\.rs(\\..*)?", "jakarta\\.ws\\.rs(\\..*)?"])
+ )
+ }
+}
+
/**
* An annotation that is used by JaxRS containers to determine a value to inject into the annotated
* element.
*/
-class JaxRsInjectionAnnotation extends Annotation {
+class JaxRsInjectionAnnotation extends JaxRSAnnotation {
JaxRsInjectionAnnotation() {
exists(AnnotationType a |
- a = getType() and
- a.getPackage().getName() = "javax.ws.rs"
+ a = this.getType() and
+ a.getPackage().getName() = getAJaxRsPackage()
|
a.hasName("BeanParam") or
a.hasName("CookieParam") or
@@ -158,23 +210,31 @@ class JaxRsInjectionAnnotation extends Annotation {
a.hasName("QueryParam")
)
or
- getType().hasQualifiedName("javax.ws.rs.core", "Context")
+ this.getType().hasQualifiedName(getAJaxRsPackage("core"), "Context")
}
}
+/**
+ * The class `javax.ws.rs.core.Response`.
+ */
class JaxRsResponse extends Class {
- JaxRsResponse() { this.hasQualifiedName("javax.ws.rs.core", "Response") }
+ JaxRsResponse() { this.hasQualifiedName(getAJaxRsPackage("core"), "Response") }
}
+/**
+ * The class `javax.ws.rs.core.Response$ResponseBuilder`.
+ */
class JaxRsResponseBuilder extends Class {
- JaxRsResponseBuilder() { this.hasQualifiedName("javax.ws.rs.core", "ResponseBuilder") }
+ JaxRsResponseBuilder() {
+ this.hasQualifiedName(getAJaxRsPackage("core"), "Response$ResponseBuilder")
+ }
}
/**
* The class `javax.ws.rs.client.Client`.
*/
class JaxRsClient extends RefType {
- JaxRsClient() { this.hasQualifiedName("javax.ws.rs.client", "Client") }
+ JaxRsClient() { this.hasQualifiedName(getAJaxRsPackage("client"), "Client") }
}
/**
@@ -184,13 +244,12 @@ class JaxRsClient extends RefType {
class JaxRsBeanParamConstructor extends Constructor {
JaxRsBeanParamConstructor() {
exists(JaxRsResourceClass resourceClass, Callable c, Parameter p |
- c = resourceClass.getAnInjectableCallable()
- |
+ c = resourceClass.getAnInjectableCallable() and
p = c.getAParameter() and
- p.getAnAnnotation().getType().hasQualifiedName("javax.ws.rs", "BeanParam") and
+ p.getAnAnnotation().getType().hasQualifiedName(getAJaxRsPackage(), "BeanParam") and
this.getDeclaringType().getSourceDeclaration() = p.getType().(RefType).getSourceDeclaration()
) and
- forall(Parameter p | p = getAParameter() |
+ forall(Parameter p | p = this.getAParameter() |
p.getAnAnnotation() instanceof JaxRsInjectionAnnotation
)
}
@@ -200,7 +259,7 @@ class JaxRsBeanParamConstructor extends Constructor {
* The class `javax.ws.rs.ext.MessageBodyReader`.
*/
class MessageBodyReader extends GenericInterface {
- MessageBodyReader() { this.hasQualifiedName("javax.ws.rs.ext", "MessageBodyReader") }
+ MessageBodyReader() { this.hasQualifiedName(getAJaxRsPackage("ext"), "MessageBodyReader") }
}
/**
@@ -208,7 +267,7 @@ class MessageBodyReader extends GenericInterface {
*/
class MessageBodyReaderReadFrom extends Method {
MessageBodyReaderReadFrom() {
- this.getDeclaringType() instanceof MessageBodyReader and
+ this.getDeclaringType().getSourceDeclaration() instanceof MessageBodyReader and
this.hasName("readFrom")
}
}
@@ -223,3 +282,517 @@ class MessageBodyReaderRead extends Method {
)
}
}
+
+/** An `@Produces` annotation that describes which content types can be produced by this resource. */
+class JaxRSProducesAnnotation extends JaxRSAnnotation {
+ JaxRSProducesAnnotation() { this.getType().hasQualifiedName(getAJaxRsPackage(), "Produces") }
+
+ /**
+ * Gets a declared content type that can be produced by this resource.
+ */
+ string getADeclaredContentType() {
+ result = this.getAValue().(CompileTimeConstantExpr).getStringValue()
+ or
+ exists(Field jaxMediaType |
+ // Accesses to static fields on `MediaType` class do not have constant strings in the database
+ // so convert the field name to a content type string
+ jaxMediaType.getDeclaringType().hasQualifiedName(getAJaxRsPackage("core"), "MediaType") and
+ jaxMediaType.getAnAccess() = this.getAValue() and
+ // e.g. MediaType.TEXT_PLAIN => text/plain
+ result = jaxMediaType.getName().toLowerCase().replaceAll("_", "/")
+ )
+ }
+}
+
+/** An `@Consumes` annotation that describes content types can be consumed by this resource. */
+class JaxRSConsumesAnnotation extends JaxRSAnnotation {
+ JaxRSConsumesAnnotation() { this.getType().hasQualifiedName(getAJaxRsPackage(), "Consumes") }
+}
+
+/** A default sink representing methods susceptible to XSS attacks. */
+private class JaxRSXssSink extends XssSink {
+ JaxRSXssSink() {
+ exists(JaxRsResourceMethod resourceMethod, ReturnStmt rs |
+ resourceMethod = any(JaxRsResourceClass resourceClass).getAResourceMethod() and
+ rs.getEnclosingCallable() = resourceMethod and
+ this.asExpr() = rs.getResult()
+ |
+ not exists(resourceMethod.getProducesAnnotation())
+ or
+ resourceMethod.getProducesAnnotation().getADeclaredContentType() = "text/plain"
+ )
+ }
+}
+
+/** A URL redirection sink from JAX-RS */
+private class JaxRsUrlRedirectSink extends SinkModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ //`namespace; type; subtypes; name; signature; ext; input; kind`
+ "javax.ws.rs.core;Response;true;seeOther;;;Argument[0];url-redirect",
+ "javax.ws.rs.core;Response;true;temporaryRedirect;;;Argument[0];url-redirect",
+ "jakarta.ws.rs.core;Response;true;seeOther;;;Argument[0];url-redirect",
+ "jakarta.ws.rs.core;Response;true;temporaryRedirect;;;Argument[0];url-redirect"
+ ]
+ }
+}
+
+/**
+ * Model Response:
+ *
+ * - the returned ResponseBuilder gains taint from a tainted entity or existing Response
+ */
+private class ResponseModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;Response;false;accepted;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;Response;false;fromResponse;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;Response;false;ok;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;Response;false;accepted;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;Response;false;fromResponse;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;Response;false;ok;;;Argument[0];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model ResponseBuilder:
+ *
+ * - becomes tainted by a tainted entity, but not by metadata, headers etc
+ * - build() method returns taint
+ * - almost all methods are fluent, and so preserve value
+ */
+private class ResponseBuilderModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;Response$ResponseBuilder;true;build;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;entity;;;Argument[0];Argument[-1];taint",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;allow;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;cacheControl;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;clone;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;contentLocation;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;cookie;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;encoding;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;entity;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;expires;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;header;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;language;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;lastModified;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;link;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;links;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;location;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;replaceAll;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;status;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;tag;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;type;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;variant;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;variants;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;build;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;entity;;;Argument[0];Argument[-1];taint",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;allow;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;cacheControl;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;clone;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;contentLocation;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;cookie;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;encoding;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;entity;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;expires;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;header;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;language;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;lastModified;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;link;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;links;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;location;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;replaceAll;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;status;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;tag;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;type;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;variant;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;variants;;;Argument[-1];ReturnValue;value"
+ ]
+ }
+}
+
+/**
+ * Model HttpHeaders: methods that Date have to be syntax-checked, but those returning MediaType
+ * or Locale are assumed potentially dangerous, as these types do not generally check that the
+ * input data is recognised, only that it conforms to the expected syntax.
+ */
+private class HttpHeadersModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;HttpHeaders;true;getAcceptableLanguages;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getAcceptableMediaTypes;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getCookies;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getHeaderString;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getLanguage;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getMediaType;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getRequestHeader;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getRequestHeaders;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getAcceptableLanguages;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getAcceptableMediaTypes;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getCookies;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getHeaderString;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getLanguage;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getMediaType;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getRequestHeader;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getRequestHeaders;;;Argument[-1];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model MultivaluedMap, which extends Map> and provides a few extra helper methods.
+ */
+private class MultivaluedMapModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;MultivaluedMap;true;add;;;Argument[0];MapKey of Argument[-1];value",
+ "javax.ws.rs.core;MultivaluedMap;true;add;;;Argument[1];Element of MapValue of Argument[-1];value",
+ "javax.ws.rs.core;MultivaluedMap;true;addAll;;;Argument[0];MapKey of Argument[-1];value",
+ "javax.ws.rs.core;MultivaluedMap;true;addAll;(Object,List);;Element of Argument[1];Element of MapValue of Argument[-1];value",
+ "javax.ws.rs.core;MultivaluedMap;true;addAll;(Object,Object[]);;ArrayElement of Argument[1];Element of MapValue of Argument[-1];value",
+ "javax.ws.rs.core;MultivaluedMap;true;addFirst;;;Argument[0];MapKey of Argument[-1];value",
+ "javax.ws.rs.core;MultivaluedMap;true;addFirst;;;Argument[1];Element of MapValue of Argument[-1];value",
+ "javax.ws.rs.core;MultivaluedMap;true;getFirst;;;Element of MapValue of Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;MultivaluedMap;true;putSingle;;;Argument[0];MapKey of Argument[-1];value",
+ "javax.ws.rs.core;MultivaluedMap;true;putSingle;;;Argument[1];Element of MapValue of Argument[-1];value",
+ "jakarta.ws.rs.core;MultivaluedMap;true;add;;;Argument[0];MapKey of Argument[-1];value",
+ "jakarta.ws.rs.core;MultivaluedMap;true;add;;;Argument[1];Element of MapValue of Argument[-1];value",
+ "jakarta.ws.rs.core;MultivaluedMap;true;addAll;;;Argument[0];MapKey of Argument[-1];value",
+ "jakarta.ws.rs.core;MultivaluedMap;true;addAll;(Object,List);;Element of Argument[1];Element of MapValue of Argument[-1];value",
+ "jakarta.ws.rs.core;MultivaluedMap;true;addAll;(Object,Object[]);;ArrayElement of Argument[1];Element of MapValue of Argument[-1];value",
+ "jakarta.ws.rs.core;MultivaluedMap;true;addFirst;;;Argument[0];MapKey of Argument[-1];value",
+ "jakarta.ws.rs.core;MultivaluedMap;true;addFirst;;;Argument[1];Element of MapValue of Argument[-1];value",
+ "jakarta.ws.rs.core;MultivaluedMap;true;getFirst;;;Element of MapValue of Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;MultivaluedMap;true;putSingle;;;Argument[0];MapKey of Argument[-1];value",
+ "jakarta.ws.rs.core;MultivaluedMap;true;putSingle;;;Argument[1];Element of MapValue of Argument[-1];value"
+ ]
+ }
+}
+
+/**
+ * Model AbstractMultivaluedMap, which implements MultivaluedMap.
+ */
+private class AbstractMultivaluedMapModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;AbstractMultivaluedMap;false;AbstractMultivaluedMap;;;MapKey of Argument[0];MapKey of Argument[-1];value",
+ "javax.ws.rs.core;AbstractMultivaluedMap;false;AbstractMultivaluedMap;;;MapValue of Argument[0];MapValue of Argument[-1];value",
+ "jakarta.ws.rs.core;AbstractMultivaluedMap;false;AbstractMultivaluedMap;;;MapKey of Argument[0];MapKey of Argument[-1];value",
+ "jakarta.ws.rs.core;AbstractMultivaluedMap;false;AbstractMultivaluedMap;;;MapValue of Argument[0];MapValue of Argument[-1];value"
+ ]
+ }
+}
+
+/**
+ * Model MultivaluedHashMap, which extends AbstractMultivaluedMap.
+ */
+private class MultivaluedHashMapModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;MultivaluedHashMap;false;MultivaluedHashMap;(Map);;MapKey of Argument[0];MapKey of Argument[-1];value",
+ "javax.ws.rs.core;MultivaluedHashMap;false;MultivaluedHashMap;(Map);;MapValue of Argument[0];Element of MapValue of Argument[-1];value",
+ "javax.ws.rs.core;MultivaluedHashMap;false;MultivaluedHashMap;(MultivaluedMap);;MapKey of Argument[0];MapKey of Argument[-1];value",
+ "javax.ws.rs.core;MultivaluedHashMap;false;MultivaluedHashMap;(MultivaluedMap);;MapValue of Argument[0];MapValue of Argument[-1];value",
+ "jakarta.ws.rs.core;MultivaluedHashMap;false;MultivaluedHashMap;(Map);;MapKey of Argument[0];MapKey of Argument[-1];value",
+ "jakarta.ws.rs.core;MultivaluedHashMap;false;MultivaluedHashMap;(Map);;MapValue of Argument[0];Element of MapValue of Argument[-1];value",
+ "jakarta.ws.rs.core;MultivaluedHashMap;false;MultivaluedHashMap;(MultivaluedMap);;MapKey of Argument[0];MapKey of Argument[-1];value",
+ "jakarta.ws.rs.core;MultivaluedHashMap;false;MultivaluedHashMap;(MultivaluedMap);;MapValue of Argument[0];MapValue of Argument[-1];value"
+ ]
+ }
+}
+
+/**
+ * Model PathSegment, which wraps a path and its associated matrix parameters.
+ */
+private class PathSegmentModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;PathSegment;true;getMatrixParameters;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;PathSegment;true;getPath;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;PathSegment;true;getMatrixParameters;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;PathSegment;true;getPath;;;Argument[-1];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model UriInfo, which provides URI element accessors.
+ */
+private class UriInfoModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;UriInfo;true;getPathParameters;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriInfo;true;getPathSegments;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriInfo;true;getQueryParameters;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriInfo;true;getRequestUri;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriInfo;true;getRequestUriBuilder;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriInfo;true;getPathParameters;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriInfo;true;getPathSegments;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriInfo;true;getQueryParameters;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriInfo;true;getRequestUri;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriInfo;true;getRequestUriBuilder;;;Argument[-1];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model Cookie, a simple tuple type.
+ */
+private class CookieModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;Cookie;true;getDomain;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Cookie;true;getName;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Cookie;true;getPath;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Cookie;true;getValue;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Cookie;true;getVersion;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Cookie;true;toString;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Cookie;false;Cookie;;;Argument[0..4];Argument[-1];taint",
+ "javax.ws.rs.core;Cookie;false;valueOf;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;true;getDomain;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;true;getName;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;true;getPath;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;true;getValue;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;true;getVersion;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;true;toString;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;false;Cookie;;;Argument[0..4];Argument[-1];taint",
+ "jakarta.ws.rs.core;Cookie;false;valueOf;;;Argument[0];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model NewCookie, a simple tuple type.
+ */
+private class NewCookieModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;NewCookie;true;getComment;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;NewCookie;true;getExpiry;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;NewCookie;true;getMaxAge;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;NewCookie;true;toCookie;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;NewCookie;false;NewCookie;;;Argument[0..9];Argument[-1];taint",
+ "javax.ws.rs.core;NewCookie;false;valueOf;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;NewCookie;true;getComment;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;NewCookie;true;getExpiry;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;NewCookie;true;getMaxAge;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;NewCookie;true;toCookie;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;NewCookie;false;NewCookie;;;Argument[0..9];Argument[-1];taint",
+ "jakarta.ws.rs.core;NewCookie;false;valueOf;;;Argument[0];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model Form, a simple container type.
+ */
+private class FormModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;Form;false;Form;;;MapKey of Argument[0];Argument[-1];taint",
+ "javax.ws.rs.core;Form;false;Form;;;MapValue of Argument[0];Argument[-1];taint",
+ "javax.ws.rs.core;Form;false;Form;;;Argument[0..1];Argument[-1];taint",
+ "javax.ws.rs.core;Form;true;asMap;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Form;true;param;;;Argument[0..1];Argument[-1];taint",
+ "javax.ws.rs.core;Form;true;param;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Form;false;Form;;;MapKey of Argument[0];Argument[-1];taint",
+ "jakarta.ws.rs.core;Form;false;Form;;;MapValue of Argument[0];Argument[-1];taint",
+ "jakarta.ws.rs.core;Form;false;Form;;;Argument[0..1];Argument[-1];taint",
+ "jakarta.ws.rs.core;Form;true;asMap;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Form;true;param;;;Argument[0..1];Argument[-1];taint",
+ "jakarta.ws.rs.core;Form;true;param;;;Argument[-1];ReturnValue;value"
+ ]
+ }
+}
+
+/**
+ * Model GenericEntity, a wrapper for HTTP entities (e.g., documents).
+ */
+private class GenericEntityModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;GenericEntity;false;GenericEntity;;;Argument[0];Argument[-1];taint",
+ "javax.ws.rs.core;GenericEntity;true;getEntity;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;GenericEntity;false;GenericEntity;;;Argument[0];Argument[-1];taint",
+ "jakarta.ws.rs.core;GenericEntity;true;getEntity;;;Argument[-1];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model MediaType, which provides accessors for elements of Content-Type and similar
+ * media type specifications.
+ */
+private class MediaTypeModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;MediaType;false;MediaType;;;Argument[0..2];Argument[-1];taint",
+ "javax.ws.rs.core;MediaType;true;getParameters;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;MediaType;true;getSubtype;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;MediaType;true;getType;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;MediaType;false;valueOf;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;MediaType;true;withCharset;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;MediaType;false;MediaType;;;Argument[0..2];Argument[-1];taint",
+ "jakarta.ws.rs.core;MediaType;true;getParameters;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;MediaType;true;getSubtype;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;MediaType;true;getType;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;MediaType;false;valueOf;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;MediaType;true;withCharset;;;Argument[-1];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model UriBuilder, which provides a fluent interface to build a URI from components.
+ */
+private class UriBuilderModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;UriBuilder;true;build;;;ArrayElement of Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;build;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromEncoded;;;ArrayElement of Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromEncoded;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromEncodedMap;;;MapKey of Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromEncodedMap;;;MapValue of Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromEncodedMap;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromMap;;;MapKey of Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromMap;;;MapValue of Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromMap;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;clone;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;fragment;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;fragment;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;false;fromLink;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;false;fromPath;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;false;fromUri;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;host;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;host;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;matrixParam;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;matrixParam;;;ArrayElement of Argument[1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;matrixParam;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;path;;;Argument[0..1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;path;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;queryParam;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;queryParam;;;ArrayElement of Argument[1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;queryParam;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;replaceMatrix;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;replaceMatrix;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;replaceMatrixParam;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;replaceMatrixParam;;;ArrayElement of Argument[1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;replaceMatrixParam;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;replacePath;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;replacePath;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;replaceQuery;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;replaceQuery;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;replaceQueryParam;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;replaceQueryParam;;;ArrayElement of Argument[1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;replaceQueryParam;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplate;;;Argument[0..2];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplate;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplateFromEncoded;;;Argument[0..1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplateFromEncoded;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplates;;;MapKey of Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplates;;;MapValue of Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplates;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplatesFromEncoded;;;MapKey of Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplatesFromEncoded;;;MapValue of Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplatesFromEncoded;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;scheme;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;scheme;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;schemeSpecificPart;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;schemeSpecificPart;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;segment;;;ArrayElement of Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;segment;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;toTemplate;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;uri;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;uri;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;userInfo;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;userInfo;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;build;;;ArrayElement of Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;build;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromEncoded;;;ArrayElement of Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromEncoded;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromEncodedMap;;;MapKey of Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromEncodedMap;;;MapValue of Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromEncodedMap;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromMap;;;MapKey of Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromMap;;;MapValue of Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromMap;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;clone;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;fragment;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;fragment;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;false;fromLink;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;false;fromPath;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;false;fromUri;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;host;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;host;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;matrixParam;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;matrixParam;;;ArrayElement of Argument[1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;matrixParam;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;path;;;Argument[0..1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;path;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;queryParam;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;queryParam;;;ArrayElement of Argument[1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;queryParam;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceMatrix;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceMatrix;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceMatrixParam;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceMatrixParam;;;ArrayElement of Argument[1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceMatrixParam;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;replacePath;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;replacePath;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceQuery;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceQuery;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceQueryParam;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceQueryParam;;;ArrayElement of Argument[1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceQueryParam;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplate;;;Argument[0..2];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplate;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplateFromEncoded;;;Argument[0..1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplateFromEncoded;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplates;;;MapKey of Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplates;;;MapValue of Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplates;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplatesFromEncoded;;;MapKey of Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplatesFromEncoded;;;MapValue of Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplatesFromEncoded;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;scheme;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;scheme;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;schemeSpecificPart;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;schemeSpecificPart;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;segment;;;ArrayElement of Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;segment;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;toTemplate;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;uri;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;uri;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;userInfo;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;userInfo;;;Argument[-1];ReturnValue;value"
+ ]
+ }
+}
+
+private class JaxRsUrlOpenSink extends SinkModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.client;Client;true;target;;;Argument[0];open-url",
+ "jakarta.ws.rs.client;Client;true;target;;;Argument[0];open-url"
+ ]
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/JsonIo.qll b/java/ql/src/semmle/code/java/frameworks/JsonIo.qll
new file mode 100644
index 00000000000..ab4c1b115d9
--- /dev/null
+++ b/java/ql/src/semmle/code/java/frameworks/JsonIo.qll
@@ -0,0 +1,67 @@
+/**
+ * Provides classes and predicates for working with the Json-io framework.
+ */
+
+import java
+import semmle.code.java.Maps
+import semmle.code.java.dataflow.DataFlow
+import semmle.code.java.dataflow.DataFlow2
+
+/**
+ * The class `com.cedarsoftware.util.io.JsonReader`.
+ */
+class JsonIoJsonReader extends RefType {
+ JsonIoJsonReader() { this.hasQualifiedName("com.cedarsoftware.util.io", "JsonReader") }
+}
+
+/** A method with the name `jsonToJava` declared in `com.cedarsoftware.util.io.JsonReader`. */
+class JsonIoJsonToJavaMethod extends Method {
+ JsonIoJsonToJavaMethod() {
+ this.getDeclaringType() instanceof JsonIoJsonReader and
+ this.getName() = "jsonToJava"
+ }
+}
+
+/** A method with the name `readObject` declared in `com.cedarsoftware.util.io.JsonReader`. */
+class JsonIoReadObjectMethod extends Method {
+ JsonIoReadObjectMethod() {
+ this.getDeclaringType() instanceof JsonIoJsonReader and
+ this.getName() = "readObject"
+ }
+}
+
+/**
+ * A call to `Map.put` method, set the value of the `USE_MAPS` key to `true`.
+ */
+class JsonIoUseMapsSetter extends MethodAccess {
+ JsonIoUseMapsSetter() {
+ this.getMethod().getDeclaringType().getASourceSupertype*() instanceof MapType and
+ this.getMethod().hasName("put") and
+ this.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "USE_MAPS" and
+ this.getArgument(1).(CompileTimeConstantExpr).getBooleanValue() = true
+ }
+}
+
+/** A data flow configuration tracing flow from JsonIo safe settings. */
+class SafeJsonIoConfig extends DataFlow2::Configuration {
+ SafeJsonIoConfig() { this = "UnsafeDeserialization::SafeJsonIoConfig" }
+
+ override predicate isSource(DataFlow::Node src) {
+ exists(MethodAccess ma |
+ ma instanceof JsonIoUseMapsSetter and
+ src.asExpr() = ma.getQualifier()
+ )
+ }
+
+ override predicate isSink(DataFlow::Node sink) {
+ exists(MethodAccess ma |
+ ma.getMethod() instanceof JsonIoJsonToJavaMethod and
+ sink.asExpr() = ma.getArgument(1)
+ )
+ or
+ exists(ClassInstanceExpr cie |
+ cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader and
+ sink.asExpr() = cie.getArgument(1)
+ )
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/YamlBeans.qll b/java/ql/src/semmle/code/java/frameworks/YamlBeans.qll
new file mode 100644
index 00000000000..b5db59926be
--- /dev/null
+++ b/java/ql/src/semmle/code/java/frameworks/YamlBeans.qll
@@ -0,0 +1,20 @@
+/**
+ * Provides classes and predicates for working with the YamlBeans framework.
+ */
+
+import java
+
+/**
+ * The class `com.esotericsoftware.yamlbeans.YamlReader`.
+ */
+class YamlBeansReader extends RefType {
+ YamlBeansReader() { this.hasQualifiedName("com.esotericsoftware.yamlbeans", "YamlReader") }
+}
+
+/** A method with the name `read` declared in `com.esotericsoftware.yamlbeans.YamlReader`. */
+class YamlBeansReaderReadMethod extends Method {
+ YamlBeansReaderReadMethod() {
+ this.getDeclaringType() instanceof YamlBeansReader and
+ this.getName() = "read"
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll
index 38469bf6b76..bf47d627686 100644
--- a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll
+++ b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll
@@ -789,3 +789,72 @@ private class ApacheToStringBuilderModel extends SummaryModelCsv {
]
}
}
+
+/**
+ * Value-propagating models for `Pair`, `ImmutablePair` and `MutablePair`.
+ */
+private class ApachePairModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "org.apache.commons.lang3.tuple;Pair;false;getKey;;;Field[org.apache.commons.lang3.tuple.ImmutablePair.left] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;Pair;false;getValue;;;Field[org.apache.commons.lang3.tuple.ImmutablePair.right] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;Pair;false;getKey;;;Field[org.apache.commons.lang3.tuple.MutablePair.left] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;Pair;false;getValue;;;Field[org.apache.commons.lang3.tuple.MutablePair.right] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;Pair;false;of;(java.lang.Object,java.lang.Object);;Argument[0];Field[org.apache.commons.lang3.tuple.ImmutablePair.left] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;Pair;false;of;(java.lang.Object,java.lang.Object);;Argument[1];Field[org.apache.commons.lang3.tuple.ImmutablePair.right] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;ImmutablePair;false;ImmutablePair;(java.lang.Object,java.lang.Object);;Argument[0];Field[org.apache.commons.lang3.tuple.ImmutablePair.left] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;ImmutablePair;false;ImmutablePair;(java.lang.Object,java.lang.Object);;Argument[1];Field[org.apache.commons.lang3.tuple.ImmutablePair.right] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;ImmutablePair;false;getLeft;;;Field[org.apache.commons.lang3.tuple.ImmutablePair.left] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;ImmutablePair;false;getRight;;;Field[org.apache.commons.lang3.tuple.ImmutablePair.right] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;ImmutablePair;false;left;;;Argument[0];Field[org.apache.commons.lang3.tuple.ImmutablePair.left] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;ImmutablePair;false;right;;;Argument[0];Field[org.apache.commons.lang3.tuple.ImmutablePair.right] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;ImmutablePair;false;of;(java.lang.Object,java.lang.Object);;Argument[0];Field[org.apache.commons.lang3.tuple.ImmutablePair.left] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;ImmutablePair;false;of;(java.lang.Object,java.lang.Object);;Argument[1];Field[org.apache.commons.lang3.tuple.ImmutablePair.right] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;MutablePair;false;MutablePair;(java.lang.Object,java.lang.Object);;Argument[0];Field[org.apache.commons.lang3.tuple.MutablePair.left] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;MutablePair;false;MutablePair;(java.lang.Object,java.lang.Object);;Argument[1];Field[org.apache.commons.lang3.tuple.MutablePair.right] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;MutablePair;false;getLeft;;;Field[org.apache.commons.lang3.tuple.MutablePair.left] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;MutablePair;false;getRight;;;Field[org.apache.commons.lang3.tuple.MutablePair.right] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;MutablePair;false;setLeft;;;Argument[0];Field[org.apache.commons.lang3.tuple.MutablePair.left] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;MutablePair;false;setRight;;;Argument[0];Field[org.apache.commons.lang3.tuple.MutablePair.right] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;MutablePair;false;setValue;;;Argument[0];Field[org.apache.commons.lang3.tuple.MutablePair.right] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;MutablePair;false;of;(java.lang.Object,java.lang.Object);;Argument[0];Field[org.apache.commons.lang3.tuple.MutablePair.left] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;MutablePair;false;of;(java.lang.Object,java.lang.Object);;Argument[1];Field[org.apache.commons.lang3.tuple.MutablePair.right] of ReturnValue;value"
+ ]
+ }
+}
+
+/**
+ * Value-propagating models for `Triple`, `ImmutableTriple` and `MutableTriple`.
+ */
+private class ApacheTripleModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "org.apache.commons.lang3.tuple;Triple;false;of;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[0];Field[org.apache.commons.lang3.tuple.ImmutableTriple.left] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;Triple;false;of;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[1];Field[org.apache.commons.lang3.tuple.ImmutableTriple.middle] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;Triple;false;of;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[2];Field[org.apache.commons.lang3.tuple.ImmutableTriple.right] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;ImmutableTriple;false;ImmutableTriple;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[0];Field[org.apache.commons.lang3.tuple.ImmutableTriple.left] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;ImmutableTriple;false;ImmutableTriple;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[1];Field[org.apache.commons.lang3.tuple.ImmutableTriple.middle] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;ImmutableTriple;false;ImmutableTriple;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[2];Field[org.apache.commons.lang3.tuple.ImmutableTriple.right] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;ImmutableTriple;false;getLeft;;;Field[org.apache.commons.lang3.tuple.ImmutableTriple.left] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;ImmutableTriple;false;getMiddle;;;Field[org.apache.commons.lang3.tuple.ImmutableTriple.middle] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;ImmutableTriple;false;getRight;;;Field[org.apache.commons.lang3.tuple.ImmutableTriple.right] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;ImmutableTriple;false;of;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[0];Field[org.apache.commons.lang3.tuple.ImmutableTriple.left] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;ImmutableTriple;false;of;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[1];Field[org.apache.commons.lang3.tuple.ImmutableTriple.middle] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;ImmutableTriple;false;of;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[2];Field[org.apache.commons.lang3.tuple.ImmutableTriple.right] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;MutableTriple;false;MutableTriple;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[0];Field[org.apache.commons.lang3.tuple.MutableTriple.left] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;MutableTriple;false;MutableTriple;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[1];Field[org.apache.commons.lang3.tuple.MutableTriple.middle] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;MutableTriple;false;MutableTriple;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[2];Field[org.apache.commons.lang3.tuple.MutableTriple.right] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;MutableTriple;false;getLeft;;;Field[org.apache.commons.lang3.tuple.MutableTriple.left] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;MutableTriple;false;getMiddle;;;Field[org.apache.commons.lang3.tuple.MutableTriple.middle] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;MutableTriple;false;getRight;;;Field[org.apache.commons.lang3.tuple.MutableTriple.right] of Argument[-1];ReturnValue;value",
+ "org.apache.commons.lang3.tuple;MutableTriple;false;setLeft;;;Argument[0];Field[org.apache.commons.lang3.tuple.MutableTriple.left] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;MutableTriple;false;setMiddle;;;Argument[0];Field[org.apache.commons.lang3.tuple.MutableTriple.middle] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;MutableTriple;false;setRight;;;Argument[0];Field[org.apache.commons.lang3.tuple.MutableTriple.right] of Argument[-1];value",
+ "org.apache.commons.lang3.tuple;MutableTriple;false;of;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[0];Field[org.apache.commons.lang3.tuple.MutableTriple.left] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;MutableTriple;false;of;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[1];Field[org.apache.commons.lang3.tuple.MutableTriple.middle] of ReturnValue;value",
+ "org.apache.commons.lang3.tuple;MutableTriple;false;of;(java.lang.Object,java.lang.Object,java.lang.Object);;Argument[2];Field[org.apache.commons.lang3.tuple.MutableTriple.right] of ReturnValue;value"
+ ]
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/guava/Base.qll b/java/ql/src/semmle/code/java/frameworks/guava/Base.qll
index cb34d3da7ed..2e5e37a9bfb 100644
--- a/java/ql/src/semmle/code/java/frameworks/guava/Base.qll
+++ b/java/ql/src/semmle/code/java/frameworks/guava/Base.qll
@@ -7,7 +7,7 @@ private class GuavaBaseCsv extends SummaryModelCsv {
override predicate row(string row) {
row =
[
- //"package;type;overrides;name;signature;ext;inputspec;outputspec;kind",
+ //`namespace; type; subtypes; name; signature; ext; input; output; kind`
"com.google.common.base;Strings;false;emptyToNull;(String);;Argument[0];ReturnValue;value",
"com.google.common.base;Strings;false;nullToEmpty;(String);;Argument[0];ReturnValue;value",
"com.google.common.base;Strings;false;padStart;(String,int,char);;Argument[0];ReturnValue;taint",
diff --git a/java/ql/src/semmle/code/java/frameworks/guava/IO.qll b/java/ql/src/semmle/code/java/frameworks/guava/IO.qll
index 305b4fbcfb7..60720a941ca 100644
--- a/java/ql/src/semmle/code/java/frameworks/guava/IO.qll
+++ b/java/ql/src/semmle/code/java/frameworks/guava/IO.qll
@@ -7,7 +7,7 @@ private class GuavaIoCsv extends SummaryModelCsv {
override predicate row(string row) {
row =
[
- //"package;type;overrides;name;signature;ext;inputspec;outputspec;kind",
+ //`namespace; type; subtypes; name; signature; ext; input; output; kind`
"com.google.common.io;BaseEncoding;true;decode;(CharSequence);;Argument[0];ReturnValue;taint",
"com.google.common.io;BaseEncoding;true;decodingStream;(Reader);;Argument[0];ReturnValue;taint",
"com.google.common.io;BaseEncoding;true;decodingSource;(CharSource);;Argument[0];ReturnValue;taint",
@@ -89,7 +89,7 @@ private class GuavaIoSinkCsv extends SinkModelCsv {
override predicate row(string row) {
row =
[
- //"package;type;overrides;name;signature;ext;inputspec;kind",
+ //`namespace; type; subtypes; name; signature; ext; input; kind`
"com.google.common.io;Resources;false;asByteSource;(URL);;Argument[0];url-open-stream",
"com.google.common.io;Resources;false;asCharSource;(URL,Charset);;Argument[0];url-open-stream",
"com.google.common.io;Resources;false;copy;(URL,OutputStream);;Argument[0];url-open-stream",
diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll
index 59016df25f8..63c58e4f2b5 100644
--- a/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll
+++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll
@@ -4,6 +4,7 @@
*/
import java
+private import semmle.code.java.dataflow.ExternalFlow
/** The class `org.springframework.http.HttpEntity` or an instantiation of it. */
class SpringHttpEntity extends Class {
@@ -38,3 +39,25 @@ class SpringResponseEntityBodyBuilder extends Interface {
class SpringHttpHeaders extends Class {
SpringHttpHeaders() { this.hasQualifiedName("org.springframework.http", "HttpHeaders") }
}
+
+private class UrlOpenSink extends SinkModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "org.springframework.http;RequestEntity;false;get;;;Argument[0];open-url",
+ "org.springframework.http;RequestEntity;false;post;;;Argument[0];open-url",
+ "org.springframework.http;RequestEntity;false;head;;;Argument[0];open-url",
+ "org.springframework.http;RequestEntity;false;delete;;;Argument[0];open-url",
+ "org.springframework.http;RequestEntity;false;options;;;Argument[0];open-url",
+ "org.springframework.http;RequestEntity;false;patch;;;Argument[0];open-url",
+ "org.springframework.http;RequestEntity;false;put;;;Argument[0];open-url",
+ "org.springframework.http;RequestEntity;false;method;;;Argument[1];open-url",
+ "org.springframework.http;RequestEntity;false;RequestEntity;(HttpMethod,URI);;Argument[1];open-url",
+ "org.springframework.http;RequestEntity;false;RequestEntity;(MultiValueMap,HttpMethod,URI);;Argument[2];open-url",
+ "org.springframework.http;RequestEntity;false;RequestEntity;(Object,HttpMethod,URI);;Argument[2];open-url",
+ "org.springframework.http;RequestEntity;false;RequestEntity;(Object,HttpMethod,URI,Type);;Argument[2];open-url",
+ "org.springframework.http;RequestEntity;false;RequestEntity;(Object,MultiValueMap,HttpMethod,URI);;Argument[3];open-url",
+ "org.springframework.http;RequestEntity;false;RequestEntity;(Object,MultiValueMap,HttpMethod,URI,Type);;Argument[3];open-url"
+ ]
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll
index 3a8d4bb084a..cb5391257d8 100644
--- a/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll
+++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll
@@ -4,6 +4,7 @@
import java
import SpringHttp
+private import semmle.code.java.dataflow.ExternalFlow
/** The class `org.springframework.web.client.RestTemplate`. */
class SpringRestTemplate extends Class {
@@ -27,3 +28,24 @@ class SpringWebClient extends Interface {
this.hasQualifiedName("org.springframework.web.reactive.function.client", "WebClient")
}
}
+
+private class UrlOpenSink extends SinkModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "org.springframework.web.client;RestTemplate;false;delete;;;Argument[0];open-url",
+ "org.springframework.web.client;RestTemplate;false;doExecute;;;Argument[0];open-url",
+ "org.springframework.web.client;RestTemplate;false;exchange;;;Argument[0];open-url",
+ "org.springframework.web.client;RestTemplate;false;execute;;;Argument[0];open-url",
+ "org.springframework.web.client;RestTemplate;false;getForEntity;;;Argument[0];open-url",
+ "org.springframework.web.client;RestTemplate;false;getForObject;;;Argument[0];open-url",
+ "org.springframework.web.client;RestTemplate;false;headForHeaders;;;Argument[0];open-url",
+ "org.springframework.web.client;RestTemplate;false;optionsForAllow;;;Argument[0];open-url",
+ "org.springframework.web.client;RestTemplate;false;patchForObject;;;Argument[0];open-url",
+ "org.springframework.web.client;RestTemplate;false;postForEntity;;;Argument[0];open-url",
+ "org.springframework.web.client;RestTemplate;false;postForLocation;;;Argument[0];open-url",
+ "org.springframework.web.client;RestTemplate;false;postForObject;;;Argument[0];open-url",
+ "org.springframework.web.client;RestTemplate;false;put;;;Argument[0];open-url"
+ ]
+ }
+}
diff --git a/java/ql/src/semmle/code/java/security/RequestForgery.qll b/java/ql/src/semmle/code/java/security/RequestForgery.qll
new file mode 100644
index 00000000000..4ac9e6232ef
--- /dev/null
+++ b/java/ql/src/semmle/code/java/security/RequestForgery.qll
@@ -0,0 +1,213 @@
+/** Provides classes to reason about server-side request forgery (SSRF) attacks. */
+
+import java
+import semmle.code.java.frameworks.Networking
+import semmle.code.java.frameworks.ApacheHttp
+import semmle.code.java.frameworks.spring.Spring
+import semmle.code.java.frameworks.JaxWS
+import semmle.code.java.frameworks.javase.Http
+import semmle.code.java.dataflow.DataFlow
+import semmle.code.java.dataflow.TaintTracking
+private import semmle.code.java.StringFormat
+private import semmle.code.java.dataflow.ExternalFlow
+
+/**
+ * A unit class for adding additional taint steps that are specific to server-side request forgery (SSRF) attacks.
+ *
+ * Extend this class to add additional taint steps to the SSRF query.
+ */
+class RequestForgeryAdditionalTaintStep extends Unit {
+ /**
+ * Holds if the step from `pred` to `succ` should be considered a taint
+ * step for server-side request forgery.
+ */
+ abstract predicate propagatesTaint(DataFlow::Node pred, DataFlow::Node succ);
+}
+
+private class DefaultRequestForgeryAdditionalTaintStep extends RequestForgeryAdditionalTaintStep {
+ override predicate propagatesTaint(DataFlow::Node pred, DataFlow::Node succ) {
+ // propagate to a URI when its host is assigned to
+ exists(UriCreation c | c.getHostArg() = pred.asExpr() | succ.asExpr() = c)
+ or
+ // propagate to a URL when its host is assigned to
+ exists(UrlConstructorCall c | c.getHostArg() = pred.asExpr() | succ.asExpr() = c)
+ }
+}
+
+/** A data flow sink for server-side request forgery (SSRF) vulnerabilities. */
+abstract class RequestForgerySink extends DataFlow::Node { }
+
+private class UrlOpenSinkAsRequestForgerySink extends RequestForgerySink {
+ UrlOpenSinkAsRequestForgerySink() { sinkNode(this, "open-url") }
+}
+
+/** A sanitizer for request forgery vulnerabilities. */
+abstract class RequestForgerySanitizer extends DataFlow::Node { }
+
+private class PrimitiveSanitizer extends RequestForgerySanitizer {
+ PrimitiveSanitizer() {
+ this.getType() instanceof PrimitiveType or
+ this.getType() instanceof BoxedType or
+ this.getType() instanceof NumberType
+ }
+}
+
+private class HostnameSanitizingConstantPrefix extends CompileTimeConstantExpr {
+ int offset;
+
+ HostnameSanitizingConstantPrefix() {
+ // Matches strings that look like when prepended to untrusted input, they will restrict
+ // the host or entity addressed: for example, anything containing `?` or `#`, or a slash that
+ // doesn't appear to be a protocol specifier (e.g. `http://` is not sanitizing), or specifically
+ // the string "/".
+ exists(
+ this.getStringValue()
+ .regexpFind(".*([?#]|[^?#:/\\\\][/\\\\]).*|[/\\\\][^/\\\\].*|^/$", 0, offset)
+ )
+ }
+
+ /**
+ * Gets the offset in this constant string where a sanitizing substring begins.
+ */
+ int getOffset() { result = offset }
+}
+
+private Expr getAHostnameSanitizingPrefix() {
+ result instanceof HostnameSanitizingConstantPrefix
+ or
+ result.(AddExpr).getAnOperand() = getAHostnameSanitizingPrefix()
+}
+
+private class StringBuilderAppend extends MethodAccess {
+ StringBuilderAppend() {
+ this.getMethod().getDeclaringType() instanceof StringBuildingType and
+ this.getMethod().hasName("append")
+ }
+}
+
+private class StringBuilderConstructorOrAppend extends Call {
+ StringBuilderConstructorOrAppend() {
+ this instanceof StringBuilderAppend or
+ this.(ClassInstanceExpr).getConstructedType() instanceof StringBuildingType
+ }
+}
+
+private Expr getQualifier(Expr e) { result = e.(MethodAccess).getQualifier() }
+
+/**
+ * An extension of `StringBuilderVar` that also accounts for strings appended in StringBuilder/Buffer's constructor
+ * and in `append` calls chained onto the constructor call.
+ *
+ * The original `StringBuilderVar` doesn't care about these because it is designed to model taint, and
+ * in taint rules terms these are not needed, as the connection between construction, appends and the
+ * eventual `toString` is more obvious.
+ */
+private class StringBuilderVarExt extends StringBuilderVar {
+ /**
+ * Returns a first assignment after this StringBuilderVar is first assigned.
+ *
+ * For example, for `StringBuilder sbv = new StringBuilder("1").append("2"); sbv.append("3").append("4");`
+ * this returns the append of `"3"`.
+ */
+ private StringBuilderAppend getAFirstAppendAfterAssignment() {
+ result = this.getAnAppend() and not result = this.getNextAppend(_)
+ }
+
+ /**
+ * Gets the next `append` after `prev`, where `prev` is, perhaps after some more `append` or other
+ * chained calls, assigned to this `StringBuilderVar`.
+ */
+ private StringBuilderAppend getNextAssignmentChainedAppend(StringBuilderConstructorOrAppend prev) {
+ getQualifier*(result) = this.getAnAssignedValue() and
+ result.getQualifier() = prev
+ }
+
+ /**
+ * Get a constructor call or `append` call that contributes a string to this string builder.
+ */
+ StringBuilderConstructorOrAppend getAConstructorOrAppend() {
+ exists(this.getNextAssignmentChainedAppend(result)) or
+ result = this.getAnAssignedValue() or
+ result = this.getAnAppend()
+ }
+
+ /**
+ * Like `StringBuilderVar.getNextAppend`, except including appends and constructors directly
+ * assigned to this `StringBuilderVar`.
+ */
+ private StringBuilderAppend getNextAppendIncludingAssignmentChains(
+ StringBuilderConstructorOrAppend prev
+ ) {
+ result = getNextAssignmentChainedAppend(prev)
+ or
+ prev = this.getAnAssignedValue() and
+ result = this.getAFirstAppendAfterAssignment()
+ or
+ result = this.getNextAppend(prev)
+ }
+
+ /**
+ * Implements `StringBuilderVarExt.getNextAppendIncludingAssignmentChains+(prev)`.
+ */
+ StringBuilderAppend getSubsequentAppendIncludingAssignmentChains(
+ StringBuilderConstructorOrAppend prev
+ ) {
+ result = this.getNextAppendIncludingAssignmentChains(prev) or
+ result =
+ this.getSubsequentAppendIncludingAssignmentChains(this.getNextAppendIncludingAssignmentChains(prev))
+ }
+}
+
+/**
+ * An expression that is sanitized because it is concatenated onto a string that looks like
+ * a hostname or a URL separator, preventing the appended string from arbitrarily controlling
+ * the addressed server.
+ */
+private class HostnameSanitizedExpr extends Expr {
+ HostnameSanitizedExpr() {
+ // Sanitize expressions that come after a sanitizing prefix in a tree of string additions:
+ this =
+ any(AddExpr add | add.getLeftOperand() = getAHostnameSanitizingPrefix()).getRightOperand()
+ or
+ // Sanitize expressions that come after a sanitizing prefix in a sequence of StringBuilder operations:
+ exists(
+ StringBuilderConstructorOrAppend appendSanitizingConstant,
+ StringBuilderAppend subsequentAppend, StringBuilderVarExt v
+ |
+ appendSanitizingConstant = v.getAConstructorOrAppend() and
+ appendSanitizingConstant.getArgument(0) = getAHostnameSanitizingPrefix() and
+ v.getSubsequentAppendIncludingAssignmentChains(appendSanitizingConstant) = subsequentAppend and
+ this = subsequentAppend.getArgument(0)
+ )
+ or
+ // Sanitize expressions that come after a sanitizing prefix in the args to a format call:
+ exists(
+ FormattingCall formatCall, FormatString formatString, HostnameSanitizingConstantPrefix prefix,
+ int sanitizedFromOffset, int laterOffset, int sanitizedArg
+ |
+ formatString = unique(FormatString fs | fs = formatCall.getAFormatString()) and
+ (
+ // A sanitizing argument comes before this:
+ exists(int argIdx |
+ formatCall.getArgumentToBeFormatted(argIdx) = prefix and
+ sanitizedFromOffset = formatString.getAnArgUsageOffset(argIdx)
+ )
+ or
+ // The format string itself sanitizes subsequent arguments:
+ formatString = prefix.getStringValue() and
+ sanitizedFromOffset = prefix.getOffset()
+ ) and
+ laterOffset > sanitizedFromOffset and
+ laterOffset = formatString.getAnArgUsageOffset(sanitizedArg) and
+ this = formatCall.getArgumentToBeFormatted(sanitizedArg)
+ )
+ }
+}
+
+/**
+ * A value that is the result of prepending a string that prevents any value from controlling the
+ * host of a URL.
+ */
+private class HostnameSantizer extends RequestForgerySanitizer {
+ HostnameSantizer() { this.asExpr() instanceof HostnameSanitizedExpr }
+}
diff --git a/java/ql/src/semmle/code/java/security/RequestForgeryConfig.qll b/java/ql/src/semmle/code/java/security/RequestForgeryConfig.qll
new file mode 100644
index 00000000000..c93d3089dc9
--- /dev/null
+++ b/java/ql/src/semmle/code/java/security/RequestForgeryConfig.qll
@@ -0,0 +1,31 @@
+/**
+ * Provides a taint-tracking configuration characterising request-forgery risks.
+ *
+ * Only import this directly from .ql files, to avoid the possibility of polluting the Configuration hierarchy accidentally.
+ */
+
+import semmle.code.java.dataflow.FlowSources
+import semmle.code.java.security.RequestForgery
+
+/**
+ * A taint-tracking configuration characterising request-forgery risks.
+ */
+class RequestForgeryConfiguration extends TaintTracking::Configuration {
+ RequestForgeryConfiguration() { this = "Server-Side Request Forgery" }
+
+ override predicate isSource(DataFlow::Node source) {
+ source instanceof RemoteFlowSource and
+ // Exclude results of remote HTTP requests: fetching something else based on that result
+ // is no worse than following a redirect returned by the remote server, and typically
+ // we're requesting a resource via https which we trust to only send us to safe URLs.
+ not source.asExpr().(MethodAccess).getCallee() instanceof URLConnectionGetInputStreamMethod
+ }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof RequestForgerySink }
+
+ override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
+ any(RequestForgeryAdditionalTaintStep r).propagatesTaint(pred, succ)
+ }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof RequestForgerySanitizer }
+}
diff --git a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
index a1561c0e6cd..d035837ad6a 100644
--- a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
+++ b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
@@ -2,6 +2,11 @@ import semmle.code.java.frameworks.Kryo
import semmle.code.java.frameworks.XStream
import semmle.code.java.frameworks.SnakeYaml
import semmle.code.java.frameworks.FastJson
+import semmle.code.java.frameworks.JYaml
+import semmle.code.java.frameworks.JsonIo
+import semmle.code.java.frameworks.YamlBeans
+import semmle.code.java.frameworks.HessianBurlap
+import semmle.code.java.frameworks.Castor
import semmle.code.java.frameworks.apache.Lang
class ObjectInputStreamReadObjectMethod extends Method {
@@ -140,6 +145,23 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
ma.getMethod() instanceof FastJsonParseMethod and
not fastJsonLooksSafe() and
sink = ma.getArgument(0)
+ or
+ ma.getMethod() instanceof JYamlLoaderUnsafeLoadMethod and
+ sink = ma.getArgument(0)
+ or
+ ma.getMethod() instanceof JsonIoJsonToJavaMethod and
+ sink = ma.getArgument(0)
+ or
+ ma.getMethod() instanceof JsonIoReadObjectMethod and
+ sink = ma.getQualifier()
+ or
+ ma.getMethod() instanceof YamlBeansReaderReadMethod and sink = ma.getQualifier()
+ or
+ ma.getMethod() instanceof UnsafeHessianInputReadObjectMethod and sink = ma.getQualifier()
+ or
+ ma.getMethod() instanceof CastorUnmarshalMethod and sink = ma.getAnArgument()
+ or
+ ma.getMethod() instanceof BurlapInputReadObjectMethod and sink = ma.getQualifier()
)
}
diff --git a/java/ql/src/semmle/code/java/security/UrlRedirect.qll b/java/ql/src/semmle/code/java/security/UrlRedirect.qll
index d2be51d2fae..254ea873fcc 100644
--- a/java/ql/src/semmle/code/java/security/UrlRedirect.qll
+++ b/java/ql/src/semmle/code/java/security/UrlRedirect.qll
@@ -2,12 +2,19 @@
import java
import semmle.code.java.dataflow.DataFlow
+import semmle.code.java.dataflow.ExternalFlow
import semmle.code.java.frameworks.Servlets
import semmle.code.java.frameworks.ApacheHttp
+private import semmle.code.java.frameworks.JaxWS
-/** A URL redirection sink */
+/** A URL redirection sink. */
abstract class UrlRedirectSink extends DataFlow::Node { }
+/** A default sink represeting methods susceptible to URL redirection attacks. */
+private class DefaultUrlRedirectSink extends UrlRedirectSink {
+ DefaultUrlRedirectSink() { sinkNode(this, "url-redirect") }
+}
+
/** A Servlet URL redirection sink. */
private class ServletUrlRedirectSink extends UrlRedirectSink {
ServletUrlRedirectSink() {
diff --git a/java/ql/test/TestUtilities/InlineExpectationsTest.qll b/java/ql/test/TestUtilities/InlineExpectationsTest.qll
index e086b810478..d351bac89a8 100644
--- a/java/ql/test/TestUtilities/InlineExpectationsTest.qll
+++ b/java/ql/test/TestUtilities/InlineExpectationsTest.qll
@@ -181,14 +181,14 @@ private int getEndOfColumnPosition(int start, string content) {
min(string name, int cand |
exists(TNamedColumn(name)) and
cand = content.indexOf(name + ":") and
- cand > start
+ cand >= start
|
cand
)
or
not exists(string name |
exists(TNamedColumn(name)) and
- content.indexOf(name + ":") > start
+ content.indexOf(name + ":") >= start
) and
result = content.length()
}
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.expected
new file mode 100644
index 00000000000..9f792d49990
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.expected
@@ -0,0 +1,15 @@
+edges
+| BeanShellInjection.java:13:17:13:44 | getParameter(...) : String | BeanShellInjection.java:15:22:15:49 | new StaticScriptSource(...) |
+| BeanShellInjection.java:20:17:20:44 | getParameter(...) : String | BeanShellInjection.java:22:20:22:23 | code |
+| BeanShellInjection.java:27:17:27:44 | getParameter(...) : String | BeanShellInjection.java:31:22:31:39 | staticScriptSource |
+nodes
+| BeanShellInjection.java:13:17:13:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| BeanShellInjection.java:15:22:15:49 | new StaticScriptSource(...) | semmle.label | new StaticScriptSource(...) |
+| BeanShellInjection.java:20:17:20:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| BeanShellInjection.java:22:20:22:23 | code | semmle.label | code |
+| BeanShellInjection.java:27:17:27:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| BeanShellInjection.java:31:22:31:39 | staticScriptSource | semmle.label | staticScriptSource |
+#select
+| BeanShellInjection.java:15:22:15:49 | new StaticScriptSource(...) | BeanShellInjection.java:13:17:13:44 | getParameter(...) : String | BeanShellInjection.java:15:22:15:49 | new StaticScriptSource(...) | BeanShell injection from $@. | BeanShellInjection.java:13:17:13:44 | getParameter(...) | this user input |
+| BeanShellInjection.java:22:20:22:23 | code | BeanShellInjection.java:20:17:20:44 | getParameter(...) : String | BeanShellInjection.java:22:20:22:23 | code | BeanShell injection from $@. | BeanShellInjection.java:20:17:20:44 | getParameter(...) | this user input |
+| BeanShellInjection.java:31:22:31:39 | staticScriptSource | BeanShellInjection.java:27:17:27:44 | getParameter(...) : String | BeanShellInjection.java:31:22:31:39 | staticScriptSource | BeanShell injection from $@. | BeanShellInjection.java:27:17:27:44 | getParameter(...) | this user input |
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.java b/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.java
new file mode 100644
index 00000000000..ee98929312b
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.java
@@ -0,0 +1,33 @@
+import bsh.Interpreter;
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.scripting.bsh.BshScriptEvaluator;
+import org.springframework.scripting.support.StaticScriptSource;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class BeanShellInjection {
+
+ @GetMapping(value = "bad1")
+ public void bad1(HttpServletRequest request) {
+ String code = request.getParameter("code");
+ BshScriptEvaluator evaluator = new BshScriptEvaluator();
+ evaluator.evaluate(new StaticScriptSource(code)); //bad
+ }
+
+ @GetMapping(value = "bad2")
+ public void bad2(HttpServletRequest request) throws Exception {
+ String code = request.getParameter("code");
+ Interpreter interpreter = new Interpreter();
+ interpreter.eval(code); //bad
+ }
+
+ @GetMapping(value = "bad3")
+ public void bad3(HttpServletRequest request) {
+ String code = request.getParameter("code");
+ StaticScriptSource staticScriptSource = new StaticScriptSource("test");
+ staticScriptSource.setScript(code);
+ BshScriptEvaluator evaluator = new BshScriptEvaluator();
+ evaluator.evaluate(staticScriptSource); //bad
+ }
+}
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.qlref
new file mode 100644
index 00000000000..a54b26a62fd
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.qlref
@@ -0,0 +1 @@
+experimental/Security/CWE/CWE-094/BeanShellInjection.ql
\ No newline at end of file
diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/options b/java/ql/test/experimental/query-tests/security/CWE-094/options
index 75905d00a27..1fc637be50f 100644
--- a/java/ql/test/experimental/query-tests/security/CWE-094/options
+++ b/java/ql/test/experimental/query-tests/security/CWE-094/options
@@ -1 +1 @@
-//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2:${testdir}/../../../stubs/groovy-all-3.0.7:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jython-2.7.2:${testdir}/../../../../experimental/stubs/rhino-1.7.13
\ No newline at end of file
+//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2:${testdir}/../../../stubs/groovy-all-3.0.7:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jython-2.7.2:${testdir}/../../../../experimental/stubs/rhino-1.7.13:${testdir}/../../../../stubs/bsh-2.0b5
\ No newline at end of file
diff --git a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected
index 6c23f5d44e9..946932400c8 100644
--- a/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected
+++ b/java/ql/test/experimental/query-tests/security/CWE-1004/SensitiveCookieNotHttpOnly.expected
@@ -5,8 +5,12 @@ edges
| SensitiveCookieNotHttpOnly.java:25:39:25:52 | tokenCookieStr : String | SensitiveCookieNotHttpOnly.java:25:28:25:64 | new Cookie(...) : Cookie |
| SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... |
| SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... |
-| SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) |
-| SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr |
+| SensitiveCookieNotHttpOnly.java:52:42:52:113 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) |
+| SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:52:42:52:113 | new NewCookie(...) : NewCookie |
+| SensitiveCookieNotHttpOnly.java:63:37:63:115 | new NewCookie(...) : NewCookie | SensitiveCookieNotHttpOnly.java:64:25:64:39 | accessKeyCookie : NewCookie |
+| SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" : String | SensitiveCookieNotHttpOnly.java:63:37:63:115 | new NewCookie(...) : NewCookie |
+| SensitiveCookieNotHttpOnly.java:64:25:64:39 | accessKeyCookie : NewCookie | SensitiveCookieNotHttpOnly.java:64:25:64:50 | toString(...) : String |
+| SensitiveCookieNotHttpOnly.java:64:25:64:50 | toString(...) : String | SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr |
| SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString |
| SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString |
| SensitiveCookieNotHttpOnly.java:70:28:70:55 | ... + ... : String | SensitiveCookieNotHttpOnly.java:71:42:71:50 | secString |
@@ -24,9 +28,13 @@ nodes
| SensitiveCookieNotHttpOnly.java:42:42:42:49 | "token=" : String | semmle.label | "token=" : String |
| SensitiveCookieNotHttpOnly.java:42:42:42:57 | ... + ... : String | semmle.label | ... + ... : String |
| SensitiveCookieNotHttpOnly.java:42:42:42:69 | ... + ... | semmle.label | ... + ... |
+| SensitiveCookieNotHttpOnly.java:52:42:52:113 | new NewCookie(...) : NewCookie | semmle.label | new NewCookie(...) : NewCookie |
| SensitiveCookieNotHttpOnly.java:52:42:52:124 | toString(...) | semmle.label | toString(...) |
| SensitiveCookieNotHttpOnly.java:52:56:52:75 | "session-access-key" : String | semmle.label | "session-access-key" : String |
+| SensitiveCookieNotHttpOnly.java:63:37:63:115 | new NewCookie(...) : NewCookie | semmle.label | new NewCookie(...) : NewCookie |
| SensitiveCookieNotHttpOnly.java:63:51:63:70 | "session-access-key" : String | semmle.label | "session-access-key" : String |
+| SensitiveCookieNotHttpOnly.java:64:25:64:39 | accessKeyCookie : NewCookie | semmle.label | accessKeyCookie : NewCookie |
+| SensitiveCookieNotHttpOnly.java:64:25:64:50 | toString(...) : String | semmle.label | toString(...) : String |
| SensitiveCookieNotHttpOnly.java:65:42:65:47 | keyStr | semmle.label | keyStr |
| SensitiveCookieNotHttpOnly.java:70:28:70:35 | "token=" : String | semmle.label | "token=" : String |
| SensitiveCookieNotHttpOnly.java:70:28:70:43 | ... + ... : String | semmle.label | ... + ... : String |
diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureBasicAuth.expected b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureBasicAuth.expected
index 6a4ee5fdddd..e8e30825203 100644
--- a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureBasicAuth.expected
+++ b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureBasicAuth.expected
@@ -11,7 +11,9 @@ edges
| InsecureBasicAuth.java:62:21:62:26 | uriStr : String | InsecureBasicAuth.java:62:13:62:27 | new URI(...) : URI |
| InsecureBasicAuth.java:78:47:78:52 | "http" : String | InsecureBasicAuth.java:86:3:86:6 | post |
| InsecureBasicAuth.java:93:19:93:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:102:3:102:6 | post |
-| InsecureBasicAuth.java:109:19:109:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:119:3:119:6 | post |
+| InsecureBasicAuth.java:109:19:109:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:110:58:110:63 | uriStr : String |
+| InsecureBasicAuth.java:110:29:110:70 | new BasicRequestLine(...) : BasicRequestLine | InsecureBasicAuth.java:119:3:119:6 | post |
+| InsecureBasicAuth.java:110:58:110:63 | uriStr : String | InsecureBasicAuth.java:110:29:110:70 | new BasicRequestLine(...) : BasicRequestLine |
| InsecureBasicAuth.java:126:19:126:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:130:28:130:67 | (...)... : URLConnection |
| InsecureBasicAuth.java:130:28:130:67 | (...)... : URLConnection | InsecureBasicAuth.java:133:3:133:6 | conn |
| InsecureBasicAuth.java:145:21:145:28 | protocol : String | InsecureBasicAuth.java:146:28:146:67 | (...)... : URLConnection |
@@ -34,6 +36,8 @@ nodes
| InsecureBasicAuth.java:93:19:93:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | semmle.label | "http://www.example.com/rest/getuser.do?uid=abcdx" : String |
| InsecureBasicAuth.java:102:3:102:6 | post | semmle.label | post |
| InsecureBasicAuth.java:109:19:109:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | semmle.label | "http://www.example.com/rest/getuser.do?uid=abcdx" : String |
+| InsecureBasicAuth.java:110:29:110:70 | new BasicRequestLine(...) : BasicRequestLine | semmle.label | new BasicRequestLine(...) : BasicRequestLine |
+| InsecureBasicAuth.java:110:58:110:63 | uriStr : String | semmle.label | uriStr : String |
| InsecureBasicAuth.java:119:3:119:6 | post | semmle.label | post |
| InsecureBasicAuth.java:126:19:126:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | semmle.label | "http://www.example.com/rest/getuser.do?uid=abcdx" : String |
| InsecureBasicAuth.java:130:28:130:67 | (...)... : URLConnection | semmle.label | (...)... : URLConnection |
diff --git a/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery.expected b/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery.expected
deleted file mode 100644
index f6c7072a519..00000000000
--- a/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery.expected
+++ /dev/null
@@ -1,77 +0,0 @@
-edges
-| JaxWsSSRF.java:21:22:21:48 | getParameter(...) : String | JaxWsSSRF.java:22:23:22:25 | url |
-| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:25:31:25:34 | sink : String |
-| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:55:32:55:35 | url1 |
-| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:58:32:58:35 | url1 |
-| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:59:30:59:33 | url1 |
-| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:63:65:63:68 | uri2 |
-| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:64:59:64:61 | uri |
-| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:67:43:67:45 | uri |
-| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:69:29:69:32 | uri2 |
-| RequestForgery2.java:25:23:25:35 | new URI(...) : URI | RequestForgery2.java:64:59:64:61 | uri |
-| RequestForgery2.java:25:23:25:35 | new URI(...) : URI | RequestForgery2.java:67:43:67:45 | uri |
-| RequestForgery2.java:25:31:25:34 | sink : String | RequestForgery2.java:25:23:25:35 | new URI(...) : URI |
-| RequestForgery.java:19:23:19:58 | new URI(...) : URI | RequestForgery.java:22:52:22:54 | uri |
-| RequestForgery.java:19:23:19:58 | new URI(...) : URI | RequestForgery.java:27:57:27:59 | uri |
-| RequestForgery.java:19:31:19:57 | getParameter(...) : String | RequestForgery.java:19:23:19:58 | new URI(...) : URI |
-| RequestForgery.java:19:31:19:57 | getParameter(...) : String | RequestForgery.java:22:52:22:54 | uri |
-| RequestForgery.java:19:31:19:57 | getParameter(...) : String | RequestForgery.java:27:57:27:59 | uri |
-| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:32:47:32:67 | ... + ... |
-| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:37:43:37:56 | fooResourceUrl |
-| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:41:42:41:55 | fooResourceUrl |
-| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:45:47:45:60 | fooResourceUrl |
-| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:54:59:54:72 | fooResourceUrl |
-| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:58:74:58:96 | new URI(...) |
-| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:58:82:58:95 | fooResourceUrl : String |
-| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:62:57:62:70 | fooResourceUrl |
-| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:66:48:66:61 | fooResourceUrl |
-| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:69:30:69:43 | fooResourceUrl |
-| SpringSSRF.java:58:82:58:95 | fooResourceUrl : String | SpringSSRF.java:58:74:58:96 | new URI(...) |
-nodes
-| JaxWsSSRF.java:21:22:21:48 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| JaxWsSSRF.java:22:23:22:25 | url | semmle.label | url |
-| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| RequestForgery2.java:25:23:25:35 | new URI(...) : URI | semmle.label | new URI(...) : URI |
-| RequestForgery2.java:25:31:25:34 | sink : String | semmle.label | sink : String |
-| RequestForgery2.java:55:32:55:35 | url1 | semmle.label | url1 |
-| RequestForgery2.java:58:32:58:35 | url1 | semmle.label | url1 |
-| RequestForgery2.java:59:30:59:33 | url1 | semmle.label | url1 |
-| RequestForgery2.java:63:65:63:68 | uri2 | semmle.label | uri2 |
-| RequestForgery2.java:64:59:64:61 | uri | semmle.label | uri |
-| RequestForgery2.java:67:43:67:45 | uri | semmle.label | uri |
-| RequestForgery2.java:69:29:69:32 | uri2 | semmle.label | uri2 |
-| RequestForgery.java:19:23:19:58 | new URI(...) : URI | semmle.label | new URI(...) : URI |
-| RequestForgery.java:19:31:19:57 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| RequestForgery.java:22:52:22:54 | uri | semmle.label | uri |
-| RequestForgery.java:27:57:27:59 | uri | semmle.label | uri |
-| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| SpringSSRF.java:32:47:32:67 | ... + ... | semmle.label | ... + ... |
-| SpringSSRF.java:37:43:37:56 | fooResourceUrl | semmle.label | fooResourceUrl |
-| SpringSSRF.java:41:42:41:55 | fooResourceUrl | semmle.label | fooResourceUrl |
-| SpringSSRF.java:45:47:45:60 | fooResourceUrl | semmle.label | fooResourceUrl |
-| SpringSSRF.java:54:59:54:72 | fooResourceUrl | semmle.label | fooResourceUrl |
-| SpringSSRF.java:58:74:58:96 | new URI(...) | semmle.label | new URI(...) |
-| SpringSSRF.java:58:82:58:95 | fooResourceUrl : String | semmle.label | fooResourceUrl : String |
-| SpringSSRF.java:62:57:62:70 | fooResourceUrl | semmle.label | fooResourceUrl |
-| SpringSSRF.java:66:48:66:61 | fooResourceUrl | semmle.label | fooResourceUrl |
-| SpringSSRF.java:69:30:69:43 | fooResourceUrl | semmle.label | fooResourceUrl |
-#select
-| JaxWsSSRF.java:22:23:22:25 | url | JaxWsSSRF.java:21:22:21:48 | getParameter(...) : String | JaxWsSSRF.java:22:23:22:25 | url | Potential server side request forgery due to $@. | JaxWsSSRF.java:21:22:21:48 | getParameter(...) | a user-provided value |
-| RequestForgery2.java:55:32:55:35 | url1 | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:55:32:55:35 | url1 | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
-| RequestForgery2.java:58:32:58:35 | url1 | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:58:32:58:35 | url1 | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
-| RequestForgery2.java:59:30:59:33 | url1 | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:59:30:59:33 | url1 | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
-| RequestForgery2.java:63:65:63:68 | uri2 | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:63:65:63:68 | uri2 | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
-| RequestForgery2.java:64:59:64:61 | uri | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:64:59:64:61 | uri | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
-| RequestForgery2.java:67:43:67:45 | uri | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:67:43:67:45 | uri | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
-| RequestForgery2.java:69:29:69:32 | uri2 | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:69:29:69:32 | uri2 | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
-| RequestForgery.java:22:52:22:54 | uri | RequestForgery.java:19:31:19:57 | getParameter(...) : String | RequestForgery.java:22:52:22:54 | uri | Potential server side request forgery due to $@. | RequestForgery.java:19:31:19:57 | getParameter(...) | a user-provided value |
-| RequestForgery.java:27:57:27:59 | uri | RequestForgery.java:19:31:19:57 | getParameter(...) : String | RequestForgery.java:27:57:27:59 | uri | Potential server side request forgery due to $@. | RequestForgery.java:19:31:19:57 | getParameter(...) | a user-provided value |
-| SpringSSRF.java:32:47:32:67 | ... + ... | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:32:47:32:67 | ... + ... | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
-| SpringSSRF.java:37:43:37:56 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:37:43:37:56 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
-| SpringSSRF.java:41:42:41:55 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:41:42:41:55 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
-| SpringSSRF.java:45:47:45:60 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:45:47:45:60 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
-| SpringSSRF.java:54:59:54:72 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:54:59:54:72 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
-| SpringSSRF.java:58:74:58:96 | new URI(...) | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:58:74:58:96 | new URI(...) | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
-| SpringSSRF.java:62:57:62:70 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:62:57:62:70 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
-| SpringSSRF.java:66:48:66:61 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:66:48:66:61 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
-| SpringSSRF.java:69:30:69:43 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:69:30:69:43 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
diff --git a/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery.java b/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery.java
deleted file mode 100644
index a9e41a8172f..00000000000
--- a/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery.java
+++ /dev/null
@@ -1,34 +0,0 @@
-import java.io.IOException;
-import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-public class RequestForgery extends HttpServlet {
- private static final String VALID_URI = "http://lgtm.com";
- private HttpClient client = HttpClient.newHttpClient();
-
- protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- try {
-
- URI uri = new URI(request.getParameter("uri"));
- // BAD: a request parameter is incorporated without validation into a Http
- // request
- HttpRequest r = HttpRequest.newBuilder(uri).build();
- client.send(r, null);
-
- // GOOD: the request parameter is validated against a known fixed string
- if (VALID_URI.equals(request.getParameter("uri"))) {
- HttpRequest r2 = HttpRequest.newBuilder(uri).build();
- client.send(r2, null);
- }
- } catch (Exception e) {
- // TODO: handle exception
- }
- }
-}
\ No newline at end of file
diff --git a/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery.qlref b/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery.qlref
deleted file mode 100644
index 3e35024c212..00000000000
--- a/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery.qlref
+++ /dev/null
@@ -1 +0,0 @@
-experimental/Security/CWE/CWE-918/RequestForgery.ql
diff --git a/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery2.java b/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery2.java
deleted file mode 100644
index eb910bedd36..00000000000
--- a/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery2.java
+++ /dev/null
@@ -1,84 +0,0 @@
-import java.io.IOException;
-import java.net.URI;
-import java.net.*;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.Proxy.Type;
-import java.io.InputStream;
-
-import org.apache.http.client.methods.HttpGet;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-public class RequestForgery2 extends HttpServlet {
- private static final String VALID_URI = "http://lgtm.com";
- private HttpClient client = HttpClient.newHttpClient();
-
- protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- try {
-
- String sink = request.getParameter("uri");
- // URI(String str)
- URI uri = new URI(sink);
-
- // URI(String scheme, String ssp, String fragment)
- URI uri2 = new URI("http", sink, "fragement");
-
- // URI(String scheme, String userInfo, String host, int port, String path,
- // String query, String fragment)
- URI uri3 = new URI("http", "userinfo", "host", 1, "path", "query", "fragment");
- // URI(String scheme, String host, String path, String fragment)
- URI uri4 = new URI("http", "host", "path", "fragment");
- // URI(String scheme, String authority, String path, String query, String
- // fragment)
- URI uri5 = new URI("http", "authority", "path", "query", "fragment");
- URI uri6 = URI.create("http://foo.com/");
-
- // URL(String spec)
- URL url1 = new URL(sink);
- // URL(String protocol, String host, int port, String file)
- URL url2 = new URL("http", "host", 1, "file");
- // URL(String protocol, String host, String file)
- URL url3 = new URL("http", "host", "file");
- // URL(URL context, String spec)
- URL url4 = new URL(url3, "http");
- // URL(String protocol, String host, int port, String file, URLStreamHandler
- // handler)
- URL url5 = new URL("http", "host", 1, "file", new Helper2());
-
- // URL(URL context, String spec, URLStreamHandler handler)
- URL url6 = new URL(url3, "spec", new Helper2());
-
- URLConnection c1 = url1.openConnection();
- SocketAddress sa = new SocketAddress() {
- };
- URLConnection c2 = url1.openConnection(new Proxy(Type.HTTP, sa));
- InputStream c3 = url1.openStream();
-
- // java.net.http
- HttpClient client = HttpClient.newHttpClient();
- HttpRequest request2 = HttpRequest.newBuilder().uri(uri2).build();
- HttpRequest request3 = HttpRequest.newBuilder(uri).build();
-
- // Apache HTTPlib
- HttpGet httpGet = new HttpGet(uri);
- HttpGet httpGet2 = new HttpGet();
- httpGet2.setURI(uri2);
- } catch (Exception e) {
- // TODO: handle exception
- }
- }
-}
-
-
-class Helper2 extends URLStreamHandler {
- Helper2() {
- }
-
- protected URLConnection openConnection(URL u) throws IOException {
- return null;
- }
-}
diff --git a/java/ql/test/experimental/query-tests/security/CWE-918/Sinks.java b/java/ql/test/experimental/query-tests/security/CWE-918/Sinks.java
deleted file mode 100644
index f5d686c9af2..00000000000
--- a/java/ql/test/experimental/query-tests/security/CWE-918/Sinks.java
+++ /dev/null
@@ -1,72 +0,0 @@
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.Proxy;
-import java.net.SocketAddress;
-import java.net.URI;
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.URLStreamHandler;
-import java.net.Proxy.Type;
-import org.apache.http.client.methods.HttpGet;
-// import java.net.http.HttpClient;
-// import java.net.http.HttpRequest;
-
-public class Sinks {
- public static void main(String[] args) throws Exception {
- // URI(String str)
- URI uri = new URI("uri1");
-
- // URI(String scheme, String ssp, String fragment)
- URI uri2 = new URI("http", "ssp", "fragement");
-
- // URI(String scheme, String userInfo, String host, int port, String path,
- // String query, String fragment)
- URI uri3 = new URI("http", "userinfo", "host", 1, "path", "query", "fragment");
- // URI(String scheme, String host, String path, String fragment)
- URI uri4 = new URI("http", "host", "path", "fragment");
- // URI(String scheme, String authority, String path, String query, String
- // fragment)
- URI uri5 = new URI("http", "authority", "path", "query", "fragment");
- URI uri6 = URI.create("http://foo.com/");
-
- // URL(String spec)
- URL url1 = new URL("spec");
- // URL(String protocol, String host, int port, String file)
- URL url2 = new URL("http", "host", 1, "file");
- // URL(String protocol, String host, String file)
- URL url3 = new URL("http", "host", "file");
- // URL(URL context, String spec)
- URL url4 = new URL(url3, "http");
- // URL(String protocol, String host, int port, String file, URLStreamHandler
- // handler)
- URL url5 = new URL("http", "host", 1, "file", new Helper());
-
- // URL(URL context, String spec, URLStreamHandler handler)
- URL url6 = new URL(url3, "spec", new Helper());
-
- URLConnection c1 = url1.openConnection();
- SocketAddress sa = new SocketAddress() {
- };
- URLConnection c2 = url1.openConnection(new Proxy(Type.HTTP, sa));
- InputStream c3 = url1.openStream();
-
- // java.net.http
- // HttpClient client = HttpClient.newHttpClient();
- // HttpRequest request2 = HttpRequest.newBuilder().uri(uri2).build();
- // HttpRequest request3 = HttpRequest.newBuilder(uri).build();
-
- // Apache HTTPlib
- HttpGet httpGet = new HttpGet(uri);
- HttpGet httpGet2 = new HttpGet();
- httpGet2.setURI(uri2);
-
- }
-
-}
-
-class Helper extends URLStreamHandler {
- @Override
- protected URLConnection openConnection(URL arg0) throws IOException {
- return null;
- }
-}
\ No newline at end of file
diff --git a/java/ql/test/experimental/query-tests/security/CWE-918/SpringSSRF.java b/java/ql/test/experimental/query-tests/security/CWE-918/SpringSSRF.java
deleted file mode 100644
index a7d3cb32b87..00000000000
--- a/java/ql/test/experimental/query-tests/security/CWE-918/SpringSSRF.java
+++ /dev/null
@@ -1,73 +0,0 @@
-import org.springframework.web.client.RestTemplate;
-import org.springframework.http.RequestEntity;
-import org.springframework.http.ResponseEntity;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpStatus;
-import java.net.URI;
-import org.springframework.http.HttpMethod;
-import java.io.IOException;
-import java.net.URI;
-import java.net.*;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.Proxy.Type;
-import java.io.InputStream;
-
-import org.apache.http.client.methods.HttpGet;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-public class SpringSSRF extends HttpServlet {
-
- protected void doGet(HttpServletRequest request2, HttpServletResponse response2)
- throws ServletException, IOException {
- String fooResourceUrl = request2.getParameter("uri");;
- RestTemplate restTemplate = new RestTemplate();
- HttpEntity request = new HttpEntity<>(new String("bar"));
- try {
- {
- ResponseEntity response =
- restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
- }
-
- {
- ResponseEntity response =
- restTemplate.exchange(fooResourceUrl, HttpMethod.POST, request, String.class);
- }
- {
- ResponseEntity response =
- restTemplate.execute(fooResourceUrl, HttpMethod.POST, null, null, "test");
- }
- {
- ResponseEntity response =
- restTemplate.getForEntity(fooResourceUrl, String.class, "test");
- }
- {
- String body = new String("body");
- RequestEntity requestEntity =
- RequestEntity.post(new URI(fooResourceUrl)).body(body);
- ResponseEntity response = restTemplate.exchange(requestEntity, String.class);
- }
- {
- String response = restTemplate.patchForObject(fooResourceUrl, new String("object"),
- String.class, "hi");
- }
- {
- ResponseEntity response = restTemplate.postForEntity(new URI(fooResourceUrl),
- new String("object"), String.class);
- }
- {
- URI response = restTemplate.postForLocation(fooResourceUrl, new String("object"));
- }
- {
- String response =
- restTemplate.postForObject(fooResourceUrl, new String("object"), String.class);
- }
- {
- restTemplate.put(fooResourceUrl, new String("object"));
- }
- } catch (org.springframework.web.client.RestClientException | java.net.URISyntaxException e) {}
- }
-}
diff --git a/java/ql/test/experimental/query-tests/security/CWE-918/options b/java/ql/test/experimental/query-tests/security/CWE-918/options
deleted file mode 100644
index 1f5354b3f8d..00000000000
--- a/java/ql/test/experimental/query-tests/security/CWE-918/options
+++ /dev/null
@@ -1 +0,0 @@
-//semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/javax-ws-rs-api-2.1.1:${testdir}/../../../../stubs/apache-http-4.4.13/:${testdir}/../../../../stubs/servlet-api-2.4/
diff --git a/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/client/Client.java b/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/client/Client.java
deleted file mode 100644
index cddcf668d14..00000000000
--- a/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/client/Client.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package javax.ws.rs.client;
-
-public abstract interface Client extends javax.ws.rs.core.Configurable {
-
- public abstract javax.ws.rs.client.WebTarget target(java.lang.String arg0);
-
- public abstract javax.ws.rs.client.WebTarget target(java.net.URI arg0);
-
- public abstract javax.ws.rs.client.WebTarget target(javax.ws.rs.core.UriBuilder arg0);
-
- public abstract javax.ws.rs.client.WebTarget target(javax.ws.rs.core.Link arg0);
-}
\ No newline at end of file
diff --git a/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Configurable.java b/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Configurable.java
deleted file mode 100644
index e132dd5b418..00000000000
--- a/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Configurable.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package javax.ws.rs.core;
-
-public abstract interface Configurable {
-
- public abstract javax.ws.rs.core.Configuration getConfiguration();
-}
\ No newline at end of file
diff --git a/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Link.java b/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Link.java
deleted file mode 100644
index 38ed9572dca..00000000000
--- a/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Link.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package javax.ws.rs.core;
-
-public abstract class Link {
-
- public static final java.lang.String TITLE = "title";
-
- public static final java.lang.String REL = "rel";
-
- public static final java.lang.String TYPE = "type";
-
- public Link() {
- }
-
- public abstract java.net.URI getUri();
-
- public abstract javax.ws.rs.core.UriBuilder getUriBuilder();
-
- public abstract java.lang.String getRel();
-
- public abstract java.util.List getRels();
-
- public abstract java.lang.String getTitle();
-
- public abstract java.lang.String getType();
-
- public abstract java.util.Map getParams();
-
- public abstract java.lang.String toString();
-
- public static javax.ws.rs.core.Link valueOf(java.lang.String value) {
- return null;
- }
-
- // public static javax.ws.rs.core.Link.Builder fromUri(java.net.URI uri) {
- // return null;
- // }
-
- // public static javax.ws.rs.core.Link.Builder fromUri(java.lang.String uri) {
- // return null;
- // }
-
- // public static javax.ws.rs.core.Link.Builder fromUriBuilder(javax.ws.rs.core.UriBuilder uriBuilder) {
- // return null;
- // }
-
- // public static javax.ws.rs.core.Link.Builder fromLink(javax.ws.rs.core.Link link) {
- // return null;
- // }
-
- // public static javax.ws.rs.core.Link.Builder fromPath(java.lang.String path) {
- // return null;
- // }
-
- // public static javax.ws.rs.core.Link.Builder fromResource(java.lang.Class> resource) {
- // return null;
- // }
-
- // public static javax.ws.rs.core.Link.Builder fromMethod(java.lang.Class> resource, java.lang.String method) {
- // return null;
- // }
-}
\ No newline at end of file
diff --git a/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilder.java b/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilder.java
deleted file mode 100644
index d32f96c5043..00000000000
--- a/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilder.java
+++ /dev/null
@@ -1,62 +0,0 @@
-// Failed to get sources. Instead, stub sources have been generated by the disassembler.
-// Implementation of methods is unavailable.
-package javax.ws.rs.core;
-
-public abstract class UriBuilder {
-
- protected UriBuilder() {
- }
-
- protected static javax.ws.rs.core.UriBuilder newInstance() {
- return null;
- }
-
- public static javax.ws.rs.core.UriBuilder fromUri(java.net.URI uri) {
- return null;
- }
-
- public static javax.ws.rs.core.UriBuilder fromUri(java.lang.String uriTemplate) {
- return null;
- }
-
- public static javax.ws.rs.core.UriBuilder fromLink(javax.ws.rs.core.Link link) {
- return null;
- }
-
- public static javax.ws.rs.core.UriBuilder fromPath(java.lang.String path)
- throws java.lang.IllegalArgumentException {
- return null;
- }
-
- public static javax.ws.rs.core.UriBuilder fromResource(java.lang.Class> resource) {
- return null;
- }
-
- public static javax.ws.rs.core.UriBuilder fromMethod(java.lang.Class> resource, java.lang.String method) {
- return null;
- }
-
- public abstract javax.ws.rs.core.UriBuilder clone();
-
- public abstract javax.ws.rs.core.UriBuilder uri(java.net.URI arg0);
-
- public abstract javax.ws.rs.core.UriBuilder uri(java.lang.String arg0);
-
- public abstract java.net.URI buildFromMap(java.util.Map arg0);
-
- public abstract java.net.URI buildFromMap(java.util.Map arg0, boolean arg1)
- throws java.lang.IllegalArgumentException, javax.ws.rs.core.UriBuilderException;
-
- public abstract java.net.URI buildFromEncodedMap(java.util.Map arg0)
- throws java.lang.IllegalArgumentException, javax.ws.rs.core.UriBuilderException;
-
- public abstract java.net.URI build(java.lang.Object... arg0)
- throws java.lang.IllegalArgumentException, javax.ws.rs.core.UriBuilderException;
-
- public abstract java.net.URI build(java.lang.Object[] arg0, boolean arg1)
- throws java.lang.IllegalArgumentException, javax.ws.rs.core.UriBuilderException;
-
- public abstract java.net.URI buildFromEncoded(java.lang.Object... arg0)
- throws java.lang.IllegalArgumentException, javax.ws.rs.core.UriBuilderException;
-
-}
\ No newline at end of file
diff --git a/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilderException.java b/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilderException.java
deleted file mode 100644
index 55aad43d041..00000000000
--- a/java/ql/test/experimental/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilderException.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package javax.ws.rs.core;
-
-public class UriBuilderException extends java.lang.RuntimeException {
-
- private static final long serialVersionUID = 956255913370721193L;
-
- public UriBuilderException() {
- }
-
- public UriBuilderException(java.lang.String msg) {
- }
-
- public UriBuilderException(java.lang.String msg, java.lang.Throwable cause) {
- }
-
- public UriBuilderException(java.lang.Throwable cause) {
- }
-}
\ No newline at end of file
diff --git a/java/ql/test/library-tests/dataflow/external-models/sinks.ql b/java/ql/test/library-tests/dataflow/external-models/sinks.ql
index eb7388fc289..cda440ff4e7 100644
--- a/java/ql/test/library-tests/dataflow/external-models/sinks.ql
+++ b/java/ql/test/library-tests/dataflow/external-models/sinks.ql
@@ -7,7 +7,7 @@ class SinkModelTest extends SinkModelCsv {
override predicate row(string row) {
row =
[
- //"package;type;overrides;name;signature;ext;spec;kind",
+ //`namespace; type; subtypes; name; signature; ext; input; kind`
"my.qltest;B;false;sink1;(Object);;Argument[0];qltest",
"my.qltest;B;false;sinkMethod;();;ReturnValue;qltest",
"my.qltest;B$Tag;false;;;Annotated;ReturnValue;qltest-retval",
diff --git a/java/ql/test/library-tests/dataflow/external-models/srcs.ql b/java/ql/test/library-tests/dataflow/external-models/srcs.ql
index daa3440d940..4ec1d6d3c83 100644
--- a/java/ql/test/library-tests/dataflow/external-models/srcs.ql
+++ b/java/ql/test/library-tests/dataflow/external-models/srcs.ql
@@ -7,7 +7,7 @@ class SourceModelTest extends SourceModelCsv {
override predicate row(string row) {
row =
[
- //"package;type;overrides;name;signature;ext;spec;kind",
+ //`namespace; type; subtypes; name; signature; ext; output; kind`
"my.qltest;A;false;src1;();;ReturnValue;qltest",
"my.qltest;A;false;src1;(String);;ReturnValue;qltest",
"my.qltest;A;false;src1;(java.lang.String);;ReturnValue;qltest-alt",
diff --git a/java/ql/test/library-tests/dataflow/external-models/steps.ql b/java/ql/test/library-tests/dataflow/external-models/steps.ql
index 58edd018587..5909f1e5222 100644
--- a/java/ql/test/library-tests/dataflow/external-models/steps.ql
+++ b/java/ql/test/library-tests/dataflow/external-models/steps.ql
@@ -8,7 +8,7 @@ class SummaryModelTest extends SummaryModelCsv {
override predicate row(string row) {
row =
[
- //"package;type;overrides;name;signature;ext;inputspec;outputspec;kind",
+ //`namespace; type; subtypes; name; signature; ext; input; output; kind`
"my.qltest;C;false;stepArgRes;(Object);;Argument[0];ReturnValue;taint",
"my.qltest;C;false;stepArgArg;(Object,Object);;Argument[0];Argument[1];taint",
"my.qltest;C;false;stepArgQual;(Object);;Argument[0];Argument[-1];taint",
diff --git a/java/ql/test/library-tests/format-strings/Test.java b/java/ql/test/library-tests/format-strings/Test.java
new file mode 100644
index 00000000000..fe58a2b975c
--- /dev/null
+++ b/java/ql/test/library-tests/format-strings/Test.java
@@ -0,0 +1,17 @@
+public class Test {
+
+ public static void test () {
+ String.format("%s", "", "");
+ String.format("s", "");
+ String.format("%2$s %2$s", "", "");
+ String.format("%2$s %1$s", "", "");
+ String.format("%2$s %s", "");
+ String.format("%s% messageBodyReader = null; // $ MessageBodyReaderDeclaration
+ messageBodyReader.readFrom(null, null, null, null, null, null); // $ MessageBodyReaderReadFromCall MessageBodyReaderReadCall
+ CustomUnmarshallerJakarta CustomUnmarshallerJakarta = null;
+ CustomUnmarshallerJakarta.readFrom(null, null, null, null, null, null); // $ MessageBodyReaderReadCall
+ }
+}
\ No newline at end of file
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JakartaRsFlow.java b/java/ql/test/library-tests/frameworks/JaxWs/JakartaRsFlow.java
new file mode 100644
index 00000000000..f534e59b854
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/JakartaRsFlow.java
@@ -0,0 +1,410 @@
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import jakarta.ws.rs.core.AbstractMultivaluedMap;
+import jakarta.ws.rs.core.CacheControl;
+import jakarta.ws.rs.core.Cookie;
+import jakarta.ws.rs.core.EntityTag;
+import jakarta.ws.rs.core.Form;
+import jakarta.ws.rs.core.GenericEntity;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.Link;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedHashMap;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.NewCookie;
+import jakarta.ws.rs.core.PathSegment;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.UriBuilder;
+import jakarta.ws.rs.core.UriInfo;
+import jakarta.ws.rs.core.Variant;
+
+public class JakartaRsFlow {
+ String taint() { return "tainted"; }
+
+ private static class ResponseSource {
+ static Response taint() { return null; }
+ }
+
+ private static class ResponseBuilderSource {
+ static Response.ResponseBuilder taint() { return Response.noContent(); }
+ }
+
+ private static class IntSource {
+ static int taint() { return 0; }
+ }
+
+ private static class BooleanSource {
+ static boolean taint() { return false; }
+ }
+
+ private static class DateSource {
+ static Date taint() { return null; }
+ }
+
+ private static class SetStringSource {
+ static Set taint() { return new HashSet(); }
+ }
+
+ static HttpHeaders taint(HttpHeaders h) { return h; }
+
+ static PathSegment taint(PathSegment ps) { return ps; }
+
+ static UriInfo taint(UriInfo ui) { return ui; }
+
+ static Map taint(Map m) { return m; }
+
+ static Link taint(Link l) { return l; }
+
+ static Class taint(Class c) { return c; }
+
+ private static class UriSource {
+ static URI taint() throws Exception { return new URI(""); }
+ }
+
+ void sink(Object o) {}
+
+ void testResponse() {
+ sink(Response.accepted(taint())); // $ hasTaintFlow
+ sink(Response.fromResponse(ResponseSource.taint())); // $ hasTaintFlow
+ sink(Response.ok(taint())); // $ hasTaintFlow
+ sink(Response.ok(taint(), new MediaType())); // $ hasTaintFlow
+ sink(Response.ok(taint(), "type")); // $ hasTaintFlow
+ sink(Response.ok(taint(), new Variant(new MediaType(), "", ""))); // $ hasTaintFlow
+ }
+
+ void testResponseBuilder(MultivaluedMap multivaluedMap, List list) throws Exception {
+ sink(ResponseBuilderSource.taint().build()); // $ hasTaintFlow
+ sink(Response.noContent().entity(taint())); // $ hasTaintFlow
+ sink(ResponseBuilderSource.taint().allow(new HashSet())); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().cacheControl(new CacheControl())); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().clone()); // $ hasTaintFlow
+ sink(ResponseBuilderSource.taint().contentLocation(new URI(""))); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().cookie()); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().encoding("")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().entity("")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().expires(new Date())); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().header("", "")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().language("")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().lastModified(new Date())); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().link("", "")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().link(new URI(""), "")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().links()); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().location(new URI(""))); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().replaceAll(multivaluedMap)); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().status(400)); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().tag(new EntityTag(""))); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().tag("")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().type("")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().variant(new Variant(new MediaType(), "", ""))); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().variants(list)); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().variants()); // $ hasValueFlow
+ }
+
+ void testHttpHeaders(HttpHeaders h) {
+ sink(taint(h).getAcceptableLanguages()); // $ hasTaintFlow
+ sink(taint(h).getAcceptableMediaTypes()); // $ hasTaintFlow
+ sink(taint(h).getCookies()); // $ hasTaintFlow
+ sink(taint(h).getHeaderString("")); // $ hasTaintFlow
+ sink(taint(h).getLanguage()); // $ hasTaintFlow
+ sink(taint(h).getMediaType()); // $ hasTaintFlow
+ sink(taint(h).getRequestHeader("")); // $ hasTaintFlow
+ sink(taint(h).getRequestHeaders()); // $ hasTaintFlow
+ }
+
+ void testMultivaluedMapAdd(MultivaluedMap mm1, MultivaluedMap mm2) {
+ mm1.add(taint(), "value");
+ sink(mm1.keySet().iterator().next()); // $ hasValueFlow
+ mm2.add("key", taint());
+ sink(mm2.get("key").get(0)); // $ hasValueFlow
+ }
+
+ void testMultivaluedMapAddAll(MultivaluedMap mm1, MultivaluedMap mm2, MultivaluedMap mm3) {
+ mm1.addAll(taint(), "a", "b");
+ sink(mm1.keySet().iterator().next()); // $ hasValueFlow
+ List l = new ArrayList();
+ l.add(taint());
+ mm2.addAll("key", l);
+ sink(mm2.get("key").get(0)); // $ hasValueFlow
+ mm3.addAll("key", "a", taint());
+ sink(mm3.get("key").get(0)); // $ hasValueFlow
+ }
+
+ void testMultivaluedMapAddFirst(MultivaluedMap mm1, MultivaluedMap mm2) {
+ mm1.addFirst(taint(), "value");
+ sink(mm1.keySet().iterator().next()); // $ hasValueFlow
+ mm2.addFirst("key", taint());
+ sink(mm2.get("key").get(0)); // $ hasValueFlow
+ sink(mm2.getFirst("key")); // $ hasValueFlow
+ }
+
+ void testMultivaluedMapputSingle(MultivaluedMap mm1, MultivaluedMap mm2) {
+ mm1.putSingle(taint(), "value");
+ sink(mm1.keySet().iterator().next()); // $ hasValueFlow
+ mm2.putSingle("key", taint());
+ sink(mm2.get("key").get(0)); // $ hasValueFlow
+ }
+
+ class MyAbstractMultivaluedMapJak extends AbstractMultivaluedMap {
+ public MyAbstractMultivaluedMapJak(Map> map) {
+ super(map);
+ }
+ }
+
+ void testAbstractMultivaluedMap(Map> map1, Map> map2, List list) {
+ map1.put(taint(), list);
+ AbstractMultivaluedMap amm1 = new MyAbstractMultivaluedMapJak(map1);
+ sink(amm1.keySet().iterator().next()); // $ MISSING: hasValueFlow
+
+ list.add(taint());
+ map2.put("key", list);
+ AbstractMultivaluedMap amm2 = new MyAbstractMultivaluedMapJak(map2);
+ sink(amm2.get("key").get(0)); // $ MISSING: hasValueFlow SPURIOUS: hasTaintFlow
+ }
+
+ void testMultivaluedHashMap(Map map1, Map map2,
+ MultivaluedMap mm1, MultivaluedMap mm2) {
+ map1.put(taint(), "value");
+ MultivaluedHashMap mhm1 = new MultivaluedHashMap(map1);
+ sink(mhm1.keySet().iterator().next()); // $ hasValueFlow
+
+ map2.put("key", taint());
+ MultivaluedHashMap mhm2 = new MultivaluedHashMap(map2);
+ sink(mhm2.get("key").get(0)); // $ hasValueFlow
+
+ mm1.add(taint(), "value");
+ MultivaluedHashMap mhm3 = new MultivaluedHashMap(mm1);
+ sink(mhm3.keySet().iterator().next()); // $ hasValueFlow
+
+ mm2.add("key", taint());
+ MultivaluedHashMap mhm4 = new MultivaluedHashMap(mm2);
+ sink(mhm4.get("key").get(0)); // $ hasValueFlow
+ }
+
+ void testPathSegment(PathSegment ps1, PathSegment ps2) {
+ sink(taint(ps1).getMatrixParameters()); // $ hasTaintFlow
+ sink(taint(ps2).getPath()); // $ hasTaintFlow
+ }
+
+ void testUriInfo(UriInfo ui1, UriInfo ui2, UriInfo ui3, UriInfo ui4, UriInfo ui5) {
+ sink(taint(ui1).getPathParameters()); // $ hasTaintFlow
+ sink(taint(ui2).getPathSegments()); // $ hasTaintFlow
+ sink(taint(ui2).getQueryParameters()); // $ hasTaintFlow
+ sink(taint(ui2).getRequestUri()); // $ hasTaintFlow
+ sink(taint(ui2).getRequestUriBuilder()); // $ hasTaintFlow
+ }
+
+ void testCookie() {
+ sink(new Cookie(taint(), "", "", "", 0)); // $ hasTaintFlow
+ sink(new Cookie("", taint(), "", "", 0)); // $ hasTaintFlow
+ sink(new Cookie("", "", taint(), "", 0)); // $ hasTaintFlow
+ sink(new Cookie("", "", "", taint(), 0)); // $ hasTaintFlow
+ sink(new Cookie("", "", "", "", IntSource.taint())); // $ hasTaintFlow
+ sink(new Cookie(taint(), "", "", "")); // $ hasTaintFlow
+ sink(new Cookie("", taint(), "", "")); // $ hasTaintFlow
+ sink(new Cookie("", "", taint(), "")); // $ hasTaintFlow
+ sink(new Cookie("", "", "", taint())); // $ hasTaintFlow
+ sink(new Cookie(taint(), "")); // $ hasTaintFlow
+ sink(new Cookie("", taint())); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint())); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint()).getDomain()); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint()).getName()); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint()).getPath()); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint()).getValue()); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint()).getVersion()); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint()).toString()); // $ hasTaintFlow
+ }
+
+ void testNewCookie() {
+ sink(new NewCookie(Cookie.valueOf(taint()))); // $ hasTaintFlow
+
+ sink(new NewCookie(Cookie.valueOf(taint()), "", 0, true)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), taint(), 0, false)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), "", IntSource.taint(), true)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), "", 0, BooleanSource.taint())); // $ hasTaintFlow
+
+ sink(new NewCookie(Cookie.valueOf(taint()), "", 0, new Date(), true, true)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), taint(), 0, new Date(), true, false)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), "", IntSource.taint(), new Date(), false, true)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), "", 0, DateSource.taint(), false, false)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), "", 0, new Date(), BooleanSource.taint(), false)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), "", 0, new Date(), true, BooleanSource.taint())); // $ hasTaintFlow
+
+ sink(new NewCookie(taint(), "")); // $ hasTaintFlow
+ sink(new NewCookie("", taint())); // $ hasTaintFlow
+
+ sink(new NewCookie(taint(), "", "", "", 0, "", 0, true)); // $ hasTaintFlow
+ sink(new NewCookie("", taint(), "", "", 0, "", 0, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", taint(), "", 0, "", 0, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", taint(), 0, "", 0, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", IntSource.taint(), "", 0, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, taint(), 0, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, "", IntSource.taint(), true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, "", 0, BooleanSource.taint())); // $ hasTaintFlow
+
+ sink(new NewCookie(taint(), "", "", "", 0, "", 0, new Date(), true, true)); // $ hasTaintFlow
+ sink(new NewCookie("", taint(), "", "", 0, "", 0, new Date(), false, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", taint(), "", 0, "", 0, new Date(), true, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", taint(), 0, "", 0, new Date(), false, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", IntSource.taint(), "", 0, new Date(), true, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, taint(), 0, new Date(), true, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, "", IntSource.taint(), new Date(), false, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, "", 0, DateSource.taint(), false, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, "", 0, new Date(), BooleanSource.taint(), true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, "", 0, new Date(), false, BooleanSource.taint())); // $ hasTaintFlow
+
+ sink(new NewCookie(taint(), "", "", "", "", 0, true)); // $ hasTaintFlow
+ sink(new NewCookie("", taint(), "", "", "", 0, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", taint(), "", "", 0, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", taint(), "", 0, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", taint(), 0, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", "", IntSource.taint(), true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", "", 0, BooleanSource.taint())); // $ hasTaintFlow
+
+ sink(new NewCookie(taint(), "", "", "", "", 0, true, true)); // $ hasTaintFlow
+ sink(new NewCookie("", taint(), "", "", "", 0, false, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", taint(), "", "", 0, true, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", taint(), "", 0, false, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", taint(), 0, true, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", "", IntSource.taint(), false, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", "", 0, BooleanSource.taint(), false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", "", 0, true, BooleanSource.taint())); // $ hasTaintFlow
+
+ sink(NewCookie.valueOf(taint()).getComment()); // $ hasTaintFlow
+ sink(NewCookie.valueOf(taint()).getExpiry()); // $ hasTaintFlow
+ sink(NewCookie.valueOf(taint()).getMaxAge()); // $ hasTaintFlow
+ sink(NewCookie.valueOf(taint()).toCookie()); // $ hasTaintFlow
+ sink(NewCookie.valueOf(taint())); // $ hasTaintFlow
+ }
+
+ void testForm(MultivaluedMap mm1, MultivaluedMap mm2) {
+ sink(new Form(taint(), "")); // $ hasTaintFlow
+ sink(new Form("", taint())); // $ hasTaintFlow
+ mm1.add(taint(), "value");
+ sink(new Form(mm1)); // $ hasTaintFlow
+ mm2.add("key", taint());
+ sink(new Form(mm2)); // $ hasTaintFlow
+ Form f1 = new Form(taint(), "");
+ sink(f1.asMap()); // $ hasTaintFlow
+ Form f2 = new Form();
+ sink(f2.param(taint(), "b")); // $ hasTaintFlow
+ Form f3 = new Form();
+ sink(f3.param("a", taint())); // $ hasTaintFlow
+ Form f4 = new Form(taint(), "");
+ sink(f4.param("a", "b")); // $ hasTaintFlow
+ }
+
+ void testGenericEntity() {
+ Method m = DummyJakarta.class.getMethods()[0];
+ GenericEntity> ge = new GenericEntity>(SetStringSource.taint(), m.getGenericReturnType());
+ sink(ge); // $ hasTaintFlow
+ sink(ge.getEntity()); // $ hasTaintFlow
+ }
+
+ void testMediaType(Map m) {
+ sink(new MediaType(taint(), "")); // $ hasTaintFlow
+ sink(new MediaType("", taint())); // $ hasTaintFlow
+ sink(new MediaType(taint(), "", m)); // $ hasTaintFlow
+ sink(new MediaType("", taint(), m)); // $ hasTaintFlow
+ sink(new MediaType("", "", taint(m))); // $ hasTaintFlow
+ sink(new MediaType(taint(), "", "")); // $ hasTaintFlow
+ sink(new MediaType("", taint(), "")); // $ hasTaintFlow
+ sink(new MediaType("", "", taint())); // $ hasTaintFlow
+ sink(MediaType.valueOf(taint()).getParameters()); // $ hasTaintFlow
+ sink(MediaType.valueOf(taint()).getSubtype()); // $ hasTaintFlow
+ sink(MediaType.valueOf(taint()).getType()); // $ hasTaintFlow
+ sink(MediaType.valueOf(taint())); // $ hasTaintFlow
+ }
+
+ void testUriBuilder() throws Exception {
+ sink(UriBuilder.fromPath("").build(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").build("", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").build(taint(), false)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").build("", taint(), true)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).build("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).build("", false)); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").buildFromEncoded(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").buildFromEncoded("", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).buildFromEncoded("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").buildFromEncodedMap(taint(new HashMap()))); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).buildFromEncodedMap(new HashMap())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").buildFromMap(taint(new HashMap()), false)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).buildFromMap(new HashMap(), true)); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath(taint()).clone()); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").fragment(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).fragment("")); // $ hasTaintFlow
+ sink(UriBuilder.fromLink(taint(Link.valueOf("")))); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromUri(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").host(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).host("")); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").matrixParam(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").matrixParam("", "", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).matrixParam("", "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").path(taint(DummyJakarta.class))); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").path(DummyJakarta.class, taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).path(DummyJakarta.class)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").queryParam(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").queryParam("", "", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).queryParam("", "")); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").replaceMatrix(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).replaceMatrix("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").replaceMatrixParam(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").replaceMatrixParam("", "", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).replaceMatrixParam("", "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").replacePath(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).replacePath("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").replaceQuery(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).replaceQuery("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").replaceQueryParam(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").replaceQueryParam("", "", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).replaceQueryParam("", "")); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").resolveTemplate(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplate(taint(), "", false)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplate("", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplate("", taint(), true)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).resolveTemplate("", "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).resolveTemplate("", "", false)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplateFromEncoded(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplateFromEncoded("", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).resolveTemplateFromEncoded("", "")); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").resolveTemplates(taint(new HashMap()))); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplates(taint(new HashMap()), true)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).resolveTemplates(new HashMap())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).resolveTemplates(new HashMap(), false)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplatesFromEncoded(taint(new HashMap()))); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).resolveTemplatesFromEncoded(new HashMap())); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").scheme(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).scheme("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").schemeSpecificPart(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).schemeSpecificPart("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").segment(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").segment("", "", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).segment("", "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).toTemplate()); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").uri(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).uri("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").uri(UriSource.taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).uri(new URI(""))); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").userInfo(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).userInfo("")); // $ hasTaintFlow
+ }
+}
+
+class DummyJakarta {
+ private static Set foo() { return null; }
+}
\ No newline at end of file
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxRs.expected b/java/ql/test/library-tests/frameworks/JaxWs/JaxRs.expected
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxRs.ql b/java/ql/test/library-tests/frameworks/JaxWs/JaxRs.ql
new file mode 100644
index 00000000000..721d46672e9
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/JaxRs.ql
@@ -0,0 +1,155 @@
+import java
+import semmle.code.java.frameworks.JaxWS
+import semmle.code.java.security.XSS
+import TestUtilities.InlineExpectationsTest
+
+class JaxRsTest extends InlineExpectationsTest {
+ JaxRsTest() { this = "JaxRsTest" }
+
+ override string getARelevantTag() {
+ result =
+ [
+ "ResourceMethod", "RootResourceClass", "NonRootResourceClass",
+ "ResourceMethodOnResourceClass", "InjectableConstructor", "InjectableField",
+ "InjectionAnnotation", "ResponseDeclaration", "ResponseBuilderDeclaration",
+ "ClientDeclaration", "BeanParamConstructor", "MessageBodyReaderDeclaration",
+ "MessageBodyReaderReadFromCall", "MessageBodyReaderReadCall", "ProducesAnnotation",
+ "ConsumesAnnotation"
+ ]
+ }
+
+ override predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "ResourceMethod" and
+ exists(JaxRsResourceMethod resourceMethod |
+ resourceMethod.getLocation() = location and
+ element = resourceMethod.toString() and
+ if exists(resourceMethod.getProducesAnnotation())
+ then value = resourceMethod.getProducesAnnotation().getADeclaredContentType()
+ else value = ""
+ )
+ or
+ tag = "RootResourceClass" and
+ exists(JaxRsResourceClass resourceClass |
+ resourceClass.isRootResource() and
+ resourceClass.getLocation() = location and
+ element = resourceClass.toString() and
+ value = ""
+ )
+ or
+ tag = "NonRootResourceClass" and
+ exists(JaxRsResourceClass resourceClass |
+ not resourceClass.isRootResource() and
+ resourceClass.getLocation() = location and
+ element = resourceClass.toString() and
+ value = ""
+ )
+ or
+ tag = "ResourceMethodOnResourceClass" and
+ exists(JaxRsResourceMethod resourceMethod |
+ resourceMethod = any(JaxRsResourceClass ResourceClass).getAResourceMethod()
+ |
+ resourceMethod.getLocation() = location and
+ element = resourceMethod.toString() and
+ value = ""
+ )
+ or
+ tag = "InjectableConstructor" and
+ exists(Constructor cons |
+ cons = any(JaxRsResourceClass resourceClass).getAnInjectableConstructor()
+ |
+ cons.getLocation() = location and
+ element = cons.toString() and
+ value = ""
+ )
+ or
+ tag = "InjectableField" and
+ exists(Field field | field = any(JaxRsResourceClass resourceClass).getAnInjectableField() |
+ field.getLocation() = location and
+ element = field.toString() and
+ value = ""
+ )
+ or
+ tag = "InjectionAnnotation" and
+ exists(JaxRsInjectionAnnotation injectionAnnotation |
+ injectionAnnotation.getLocation() = location and
+ element = injectionAnnotation.toString() and
+ value = ""
+ )
+ or
+ tag = "ResponseDeclaration" and
+ exists(LocalVariableDecl decl |
+ decl.getType() instanceof JaxRsResponse and
+ decl.getLocation() = location and
+ element = decl.toString() and
+ value = ""
+ )
+ or
+ tag = "ResponseBuilderDeclaration" and
+ exists(LocalVariableDecl decl |
+ decl.getType() instanceof JaxRsResponseBuilder and
+ decl.getLocation() = location and
+ element = decl.toString() and
+ value = ""
+ )
+ or
+ tag = "ClientDeclaration" and
+ exists(LocalVariableDecl decl |
+ decl.getType() instanceof JaxRsClient and
+ decl.getLocation() = location and
+ element = decl.toString() and
+ value = ""
+ )
+ or
+ tag = "BeanParamConstructor" and
+ exists(JaxRsBeanParamConstructor cons |
+ cons.getLocation() = location and
+ element = cons.toString() and
+ value = ""
+ )
+ or
+ tag = "MessageBodyReaderDeclaration" and
+ exists(LocalVariableDecl decl |
+ decl.getType().(RefType).getSourceDeclaration() instanceof MessageBodyReader and
+ decl.getLocation() = location and
+ element = decl.toString() and
+ value = ""
+ )
+ or
+ tag = "MessageBodyReaderReadFromCall" and
+ exists(MethodAccess ma |
+ ma.getMethod() instanceof MessageBodyReaderReadFrom and
+ ma.getLocation() = location and
+ element = ma.toString() and
+ value = ""
+ )
+ or
+ tag = "MessageBodyReaderReadCall" and
+ exists(MethodAccess ma |
+ ma.getMethod() instanceof MessageBodyReaderRead and
+ ma.getLocation() = location and
+ element = ma.toString() and
+ value = ""
+ )
+ or
+ tag = "ProducesAnnotation" and
+ exists(JaxRSProducesAnnotation producesAnnotation |
+ producesAnnotation.getLocation() = location and
+ element = producesAnnotation.toString() and
+ value = producesAnnotation.getADeclaredContentType()
+ )
+ or
+ tag = "ConsumesAnnotation" and
+ exists(JaxRSConsumesAnnotation consumesAnnotation |
+ consumesAnnotation.getLocation() = location and
+ element = consumesAnnotation.toString() and
+ value = ""
+ )
+ or
+ tag = "XssSink" and
+ exists(XssSink xssSink |
+ xssSink.getLocation() = location and
+ element = xssSink.toString() and
+ value = ""
+ )
+ }
+}
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxRs1.java b/java/ql/test/library-tests/frameworks/JaxWs/JaxRs1.java
new file mode 100644
index 00000000000..ba21f36069b
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/JaxRs1.java
@@ -0,0 +1,215 @@
+import java.io.InputStream;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.PUT;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.HEAD;
+import javax.ws.rs.Path;
+import javax.ws.rs.BeanParam;
+import javax.ws.rs.CookieParam;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.MatrixParam;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.MessageBodyReader;
+
+@Path("")
+public class JaxRs1 { // $ RootResourceClass
+ public JaxRs1() { // $ InjectableConstructor
+ }
+
+ @GET
+ int Get() { // $ ResourceMethod ResourceMethodOnResourceClass
+ return 0; // $ XssSink
+ }
+
+ @POST
+ void Post() { // $ ResourceMethod ResourceMethodOnResourceClass
+ }
+
+ @Produces("text/plain") // $ ProducesAnnotation=text/plain
+ @DELETE
+ double Delete() { // $ ResourceMethod=text/plain ResourceMethodOnResourceClass
+ return 0.0; // $ XssSink
+ }
+
+ @Produces(MediaType.TEXT_HTML) // $ ProducesAnnotation=text/html
+ @PUT
+ void Put() { // $ ResourceMethod=text/html ResourceMethodOnResourceClass
+ }
+
+ @OPTIONS
+ void Options() { // $ ResourceMethod ResourceMethodOnResourceClass
+ }
+
+ @HEAD
+ void Head() { // $ ResourceMethod ResourceMethodOnResourceClass
+ }
+
+ @Path("")
+ NonRootResourceClass subResourceLocator() { // $ SubResourceLocator
+ return null;
+ }
+
+ public class NonRootResourceClass { // $ NonRootResourceClass
+ @GET
+ int Get() { // $ ResourceMethod ResourceMethodOnResourceClass
+ return 0; // $ XssSink
+ }
+
+ @Produces("text/html") // $ ProducesAnnotation=text/html
+ @POST
+ boolean Post() { // $ ResourceMethod=text/html ResourceMethodOnResourceClass
+ return false;
+ }
+
+ @Produces(MediaType.TEXT_PLAIN) // $ ProducesAnnotation=text/plain
+ @DELETE
+ double Delete() { // $ ResourceMethod=text/plain ResourceMethodOnResourceClass
+ return 0.0; // $ XssSink
+ }
+
+ @Path("")
+ AnotherNonRootResourceClass subResourceLocator1() { // $ SubResourceLocator
+ return null;
+ }
+
+ @GET
+ @Path("")
+ NotAResourceClass1 NotASubResourceLocator1() { // $ ResourceMethod ResourceMethodOnResourceClass
+ return null; // $ XssSink
+ }
+
+ @GET
+ NotAResourceClass2 NotASubResourceLocator2() { // $ ResourceMethod ResourceMethodOnResourceClass
+ return null; // $ XssSink
+ }
+
+ NotAResourceClass2 NotASubResourceLocator3() {
+ return null;
+ }
+ }
+}
+
+class AnotherNonRootResourceClass { // $ NonRootResourceClass
+ public AnotherNonRootResourceClass() {
+ }
+
+ public AnotherNonRootResourceClass(
+ @BeanParam int beanParam, // $ InjectionAnnotation
+ @CookieParam("") int cookieParam, // $ InjectionAnnotation
+ @FormParam("") int formParam, // $ InjectionAnnotation
+ @HeaderParam("") int headerParam, // $ InjectionAnnotation
+ @MatrixParam("") int matrixParam, // $ InjectionAnnotation
+ @PathParam("") int pathParam, // $ InjectionAnnotation
+ @QueryParam("") int queryParam, // $ InjectionAnnotation
+ @Context int context) { // $ InjectionAnnotation
+ }
+
+ @Path("")
+ public void resourceMethodWithBeanParamParameter(@BeanParam Foo foo) { // $ SubResourceLocator InjectionAnnotation
+ }
+}
+
+class Foo {
+ Foo() { // $ BeanParamConstructor
+ }
+
+ public Foo( // $ BeanParamConstructor
+ @BeanParam int beanParam, // $ InjectionAnnotation
+ @CookieParam("") int cookieParam, // $ InjectionAnnotation
+ @FormParam("") int formParam, // $ InjectionAnnotation
+ @HeaderParam("") int headerParam, // $ InjectionAnnotation
+ @MatrixParam("") int matrixParam, // $ InjectionAnnotation
+ @PathParam("") int pathParam, // $ InjectionAnnotation
+ @QueryParam("") int queryParam, // $ InjectionAnnotation
+ @Context int context) { // $ InjectionAnnotation
+ }
+
+ public Foo(
+ @BeanParam int beanParam, // $ InjectionAnnotation
+ @CookieParam("") int cookieParam, // $ InjectionAnnotation
+ @FormParam("") int formParam, // $ InjectionAnnotation
+ @HeaderParam("") int headerParam, // $ InjectionAnnotation
+ @MatrixParam("") int matrixParam, // $ InjectionAnnotation
+ @PathParam("") int pathParam, // $ InjectionAnnotation
+ @QueryParam("") int queryParam, // $ InjectionAnnotation
+ @Context int context, // $ InjectionAnnotation
+ int paramWithoutAnnotation) {
+ }
+}
+
+class NotAResourceClass1 {
+}
+
+class NotAResourceClass2 {
+}
+
+class ExtendsJaxRs1 extends JaxRs1 {
+ @Override
+ int Get() { // $ ResourceMethod
+ return 1;
+ }
+
+ @Override
+ @QueryParam("") // $ InjectionAnnotation
+ void Post() {
+ }
+
+ @Override
+ double Delete() { // $ ResourceMethod=text/plain
+ return 1.0;
+ }
+
+ @Override
+ void Put() { // $ ResourceMethod=text/html
+ }
+
+ @Produces("application/json") // $ ProducesAnnotation=application/json
+ @Override
+ void Options() {
+ }
+
+ @Produces(MediaType.TEXT_XML) // $ ProducesAnnotation=text/xml
+ @Override
+ void Head() {
+ }
+
+}
+
+@Produces(MediaType.TEXT_XML) // $ ProducesAnnotation=text/xml
+class ExtendsJaxRs1WithProducesAnnotation extends JaxRs1 {
+ @Override
+ int Get() { // $ ResourceMethod=text/xml
+ return 2;
+ }
+
+ @Override
+ @QueryParam("") // $ InjectionAnnotation
+ void Post() {
+ }
+
+ @Override
+ double Delete() { // $ ResourceMethod=text/plain
+ return 2.0;
+ }
+
+ @Override
+ void Put() { // $ ResourceMethod=text/html
+ }
+
+ @Override
+ void Options() { // $ ResourceMethod=text/xml
+ }
+}
\ No newline at end of file
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxRs2.java b/java/ql/test/library-tests/frameworks/JaxWs/JaxRs2.java
new file mode 100644
index 00000000000..7fa0413e841
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/JaxRs2.java
@@ -0,0 +1,99 @@
+import java.io.InputStream;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.PUT;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.HEAD;
+import javax.ws.rs.Path;
+import javax.ws.rs.BeanParam;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.CookieParam;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.MatrixParam;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.MessageBodyReader;
+
+@Path("")
+class JaxRs2 { // $ RootResourceClass
+ JaxRs2() {
+ }
+
+ public JaxRs2(// $ InjectableConstructor
+ @BeanParam int beanParam, // $ InjectionAnnotation
+ @CookieParam("") int cookieParam, // $ InjectionAnnotation
+ @FormParam("") int formParam, // $ InjectionAnnotation
+ @HeaderParam("") int headerParam, // $ InjectionAnnotation
+ @MatrixParam("") int matrixParam, // $ InjectionAnnotation
+ @PathParam("") int pathParam, // $ InjectionAnnotation
+ @QueryParam("") int queryParam, // $ InjectionAnnotation
+ @Context int context) { // $ InjectionAnnotation
+ }
+
+ public JaxRs2(
+ @BeanParam int beanParam, // $ InjectionAnnotation
+ @CookieParam("") int cookieParam, // $ InjectionAnnotation
+ @FormParam("") int formParam, // $ InjectionAnnotation
+ @HeaderParam("") int headerParam, // $ InjectionAnnotation
+ @MatrixParam("") int matrixParam, // $ InjectionAnnotation
+ @PathParam("") int pathParam, // $ InjectionAnnotation
+ @QueryParam("") int queryParam, // $ InjectionAnnotation
+ @Context int context, // $ InjectionAnnotation
+ int paramWithoutAnnotation) {
+ }
+
+ @BeanParam // $ InjectionAnnotation
+ int beanField; // $ InjectableField
+ @CookieParam("") // $ InjectionAnnotation
+ int cookieField; // $ InjectableField
+ @FormParam("") // $ InjectionAnnotation
+ int formField; // $ InjectableField
+ @HeaderParam("") // $ InjectionAnnotation
+ int headerField; // $ InjectableField
+ @MatrixParam("") // $ InjectionAnnotation
+ int matrixField; // $ InjectableField
+ @PathParam("") // $ InjectionAnnotation
+ int pathField; // $ InjectableField
+ @QueryParam("") // $ InjectionAnnotation
+ int queryField; // $ InjectableField
+ @Context // $ InjectionAnnotation
+ int context; // $ InjectableField
+ int fieldWithoutAnnotation;
+}
+
+class CustomUnmarshaller implements MessageBodyReader {
+
+ @Override
+ public boolean isReadable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) {
+ return true;
+ }
+
+
+ @Override
+ public Object readFrom(Class aClass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, InputStream inputStream) {
+ return null;
+ }
+}
+
+class Miscellaneous {
+ @Consumes("") // $ ConsumesAnnotation
+ public static void miscellaneous() throws IOException {
+ Response.ResponseBuilder responseBuilder = Response.accepted(); // $ ResponseBuilderDeclaration
+ Response response = responseBuilder.build(); // $ ResponseDeclaration
+ Client client; // $ ClientDeclaration
+ MessageBodyReader messageBodyReader = null; // $ MessageBodyReaderDeclaration
+ messageBodyReader.readFrom(null, null, null, null, null, null); // $ MessageBodyReaderReadFromCall MessageBodyReaderReadCall
+ CustomUnmarshaller customUnmarshaller = null;
+ customUnmarshaller.readFrom(null, null, null, null, null, null); // $ MessageBodyReaderReadCall
+ }
+}
\ No newline at end of file
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.expected b/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.expected
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.java b/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.java
new file mode 100644
index 00000000000..eecc3e444c9
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.java
@@ -0,0 +1,410 @@
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.ws.rs.core.AbstractMultivaluedMap;
+import javax.ws.rs.core.CacheControl;
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.EntityTag;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.GenericEntity;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Link;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.NewCookie;
+import javax.ws.rs.core.PathSegment;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.core.Variant;
+
+public class JaxRsFlow {
+ String taint() { return "tainted"; }
+
+ private static class ResponseSource {
+ static Response taint() { return null; }
+ }
+
+ private static class ResponseBuilderSource {
+ static Response.ResponseBuilder taint() { return Response.noContent(); }
+ }
+
+ private static class IntSource {
+ static int taint() { return 0; }
+ }
+
+ private static class BooleanSource {
+ static boolean taint() { return false; }
+ }
+
+ private static class DateSource {
+ static Date taint() { return null; }
+ }
+
+ private static class SetStringSource {
+ static Set taint() { return new HashSet(); }
+ }
+
+ static HttpHeaders taint(HttpHeaders h) { return h; }
+
+ static PathSegment taint(PathSegment ps) { return ps; }
+
+ static UriInfo taint(UriInfo ui) { return ui; }
+
+ static Map taint(Map m) { return m; }
+
+ static Link taint(Link l) { return l; }
+
+ static Class taint(Class c) { return c; }
+
+ private static class UriSource {
+ static URI taint() throws Exception { return new URI(""); }
+ }
+
+ void sink(Object o) {}
+
+ void testResponse() {
+ sink(Response.accepted(taint())); // $ hasTaintFlow
+ sink(Response.fromResponse(ResponseSource.taint())); // $ hasTaintFlow
+ sink(Response.ok(taint())); // $ hasTaintFlow
+ sink(Response.ok(taint(), new MediaType())); // $ hasTaintFlow
+ sink(Response.ok(taint(), "type")); // $ hasTaintFlow
+ sink(Response.ok(taint(), new Variant(new MediaType(), "", ""))); // $ hasTaintFlow
+ }
+
+ void testResponseBuilder(MultivaluedMap multivaluedMap, List list) throws Exception {
+ sink(ResponseBuilderSource.taint().build()); // $ hasTaintFlow
+ sink(Response.noContent().entity(taint())); // $ hasTaintFlow
+ sink(ResponseBuilderSource.taint().allow(new HashSet())); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().cacheControl(new CacheControl())); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().clone()); // $ hasTaintFlow
+ sink(ResponseBuilderSource.taint().contentLocation(new URI(""))); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().cookie()); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().encoding("")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().entity("")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().expires(new Date())); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().header("", "")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().language("")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().lastModified(new Date())); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().link("", "")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().link(new URI(""), "")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().links()); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().location(new URI(""))); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().replaceAll(multivaluedMap)); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().status(400)); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().tag(new EntityTag(""))); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().tag("")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().type("")); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().variant(new Variant(new MediaType(), "", ""))); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().variants(list)); // $ hasValueFlow
+ sink(ResponseBuilderSource.taint().variants()); // $ hasValueFlow
+ }
+
+ void testHttpHeaders(HttpHeaders h) {
+ sink(taint(h).getAcceptableLanguages()); // $ hasTaintFlow
+ sink(taint(h).getAcceptableMediaTypes()); // $ hasTaintFlow
+ sink(taint(h).getCookies()); // $ hasTaintFlow
+ sink(taint(h).getHeaderString("")); // $ hasTaintFlow
+ sink(taint(h).getLanguage()); // $ hasTaintFlow
+ sink(taint(h).getMediaType()); // $ hasTaintFlow
+ sink(taint(h).getRequestHeader("")); // $ hasTaintFlow
+ sink(taint(h).getRequestHeaders()); // $ hasTaintFlow
+ }
+
+ void testMultivaluedMapAdd(MultivaluedMap mm1, MultivaluedMap mm2) {
+ mm1.add(taint(), "value");
+ sink(mm1.keySet().iterator().next()); // $ hasValueFlow
+ mm2.add("key", taint());
+ sink(mm2.get("key").get(0)); // $ hasValueFlow
+ }
+
+ void testMultivaluedMapAddAll(MultivaluedMap mm1, MultivaluedMap mm2, MultivaluedMap mm3) {
+ mm1.addAll(taint(), "a", "b");
+ sink(mm1.keySet().iterator().next()); // $ hasValueFlow
+ List l = new ArrayList();
+ l.add(taint());
+ mm2.addAll("key", l);
+ sink(mm2.get("key").get(0)); // $ hasValueFlow
+ mm3.addAll("key", "a", taint());
+ sink(mm3.get("key").get(0)); // $ hasValueFlow
+ }
+
+ void testMultivaluedMapAddFirst(MultivaluedMap mm1, MultivaluedMap mm2) {
+ mm1.addFirst(taint(), "value");
+ sink(mm1.keySet().iterator().next()); // $ hasValueFlow
+ mm2.addFirst("key", taint());
+ sink(mm2.get("key").get(0)); // $ hasValueFlow
+ sink(mm2.getFirst("key")); // $ hasValueFlow
+ }
+
+ void testMultivaluedMapputSingle(MultivaluedMap mm1, MultivaluedMap mm2) {
+ mm1.putSingle(taint(), "value");
+ sink(mm1.keySet().iterator().next()); // $ hasValueFlow
+ mm2.putSingle("key", taint());
+ sink(mm2.get("key").get(0)); // $ hasValueFlow
+ }
+
+ class MyAbstractMultivaluedMap extends AbstractMultivaluedMap {
+ public MyAbstractMultivaluedMap(Map> map) {
+ super(map);
+ }
+ }
+
+ void testAbstractMultivaluedMap(Map> map1, Map> map2, List list) {
+ map1.put(taint(), list);
+ AbstractMultivaluedMap amm1 = new MyAbstractMultivaluedMap(map1);
+ sink(amm1.keySet().iterator().next()); // $ MISSING: hasValueFlow
+
+ list.add(taint());
+ map2.put("key", list);
+ AbstractMultivaluedMap amm2 = new MyAbstractMultivaluedMap(map2);
+ sink(amm2.get("key").get(0)); // $ MISSING: hasValueFlow SPURIOUS: hasTaintFlow
+ }
+
+ void testMultivaluedHashMap(Map map1, Map map2,
+ MultivaluedMap mm1, MultivaluedMap mm2) {
+ map1.put(taint(), "value");
+ MultivaluedHashMap mhm1 = new MultivaluedHashMap(map1);
+ sink(mhm1.keySet().iterator().next()); // $ hasValueFlow
+
+ map2.put("key", taint());
+ MultivaluedHashMap mhm2 = new MultivaluedHashMap(map2);
+ sink(mhm2.get("key").get(0)); // $ hasValueFlow
+
+ mm1.add(taint(), "value");
+ MultivaluedHashMap mhm3 = new MultivaluedHashMap(mm1);
+ sink(mhm3.keySet().iterator().next()); // $ hasValueFlow
+
+ mm2.add("key", taint());
+ MultivaluedHashMap mhm4 = new MultivaluedHashMap(mm2);
+ sink(mhm4.get("key").get(0)); // $ hasValueFlow
+ }
+
+ void testPathSegment(PathSegment ps1, PathSegment ps2) {
+ sink(taint(ps1).getMatrixParameters()); // $ hasTaintFlow
+ sink(taint(ps2).getPath()); // $ hasTaintFlow
+ }
+
+ void testUriInfo(UriInfo ui1, UriInfo ui2, UriInfo ui3, UriInfo ui4, UriInfo ui5) {
+ sink(taint(ui1).getPathParameters()); // $ hasTaintFlow
+ sink(taint(ui2).getPathSegments()); // $ hasTaintFlow
+ sink(taint(ui2).getQueryParameters()); // $ hasTaintFlow
+ sink(taint(ui2).getRequestUri()); // $ hasTaintFlow
+ sink(taint(ui2).getRequestUriBuilder()); // $ hasTaintFlow
+ }
+
+ void testCookie() {
+ sink(new Cookie(taint(), "", "", "", 0)); // $ hasTaintFlow
+ sink(new Cookie("", taint(), "", "", 0)); // $ hasTaintFlow
+ sink(new Cookie("", "", taint(), "", 0)); // $ hasTaintFlow
+ sink(new Cookie("", "", "", taint(), 0)); // $ hasTaintFlow
+ sink(new Cookie("", "", "", "", IntSource.taint())); // $ hasTaintFlow
+ sink(new Cookie(taint(), "", "", "")); // $ hasTaintFlow
+ sink(new Cookie("", taint(), "", "")); // $ hasTaintFlow
+ sink(new Cookie("", "", taint(), "")); // $ hasTaintFlow
+ sink(new Cookie("", "", "", taint())); // $ hasTaintFlow
+ sink(new Cookie(taint(), "")); // $ hasTaintFlow
+ sink(new Cookie("", taint())); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint())); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint()).getDomain()); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint()).getName()); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint()).getPath()); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint()).getValue()); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint()).getVersion()); // $ hasTaintFlow
+ sink(Cookie.valueOf(taint()).toString()); // $ hasTaintFlow
+ }
+
+ void testNewCookie() {
+ sink(new NewCookie(Cookie.valueOf(taint()))); // $ hasTaintFlow
+
+ sink(new NewCookie(Cookie.valueOf(taint()), "", 0, true)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), taint(), 0, false)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), "", IntSource.taint(), true)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), "", 0, BooleanSource.taint())); // $ hasTaintFlow
+
+ sink(new NewCookie(Cookie.valueOf(taint()), "", 0, new Date(), true, true)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), taint(), 0, new Date(), true, false)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), "", IntSource.taint(), new Date(), false, true)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), "", 0, DateSource.taint(), false, false)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), "", 0, new Date(), BooleanSource.taint(), false)); // $ hasTaintFlow
+ sink(new NewCookie(Cookie.valueOf(""), "", 0, new Date(), true, BooleanSource.taint())); // $ hasTaintFlow
+
+ sink(new NewCookie(taint(), "")); // $ hasTaintFlow
+ sink(new NewCookie("", taint())); // $ hasTaintFlow
+
+ sink(new NewCookie(taint(), "", "", "", 0, "", 0, true)); // $ hasTaintFlow
+ sink(new NewCookie("", taint(), "", "", 0, "", 0, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", taint(), "", 0, "", 0, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", taint(), 0, "", 0, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", IntSource.taint(), "", 0, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, taint(), 0, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, "", IntSource.taint(), true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, "", 0, BooleanSource.taint())); // $ hasTaintFlow
+
+ sink(new NewCookie(taint(), "", "", "", 0, "", 0, new Date(), true, true)); // $ hasTaintFlow
+ sink(new NewCookie("", taint(), "", "", 0, "", 0, new Date(), false, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", taint(), "", 0, "", 0, new Date(), true, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", taint(), 0, "", 0, new Date(), false, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", IntSource.taint(), "", 0, new Date(), true, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, taint(), 0, new Date(), true, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, "", IntSource.taint(), new Date(), false, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, "", 0, DateSource.taint(), false, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, "", 0, new Date(), BooleanSource.taint(), true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", 0, "", 0, new Date(), false, BooleanSource.taint())); // $ hasTaintFlow
+
+ sink(new NewCookie(taint(), "", "", "", "", 0, true)); // $ hasTaintFlow
+ sink(new NewCookie("", taint(), "", "", "", 0, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", taint(), "", "", 0, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", taint(), "", 0, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", taint(), 0, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", "", IntSource.taint(), true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", "", 0, BooleanSource.taint())); // $ hasTaintFlow
+
+ sink(new NewCookie(taint(), "", "", "", "", 0, true, true)); // $ hasTaintFlow
+ sink(new NewCookie("", taint(), "", "", "", 0, false, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", taint(), "", "", 0, true, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", taint(), "", 0, false, false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", taint(), 0, true, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", "", IntSource.taint(), false, true)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", "", 0, BooleanSource.taint(), false)); // $ hasTaintFlow
+ sink(new NewCookie("", "", "", "", "", 0, true, BooleanSource.taint())); // $ hasTaintFlow
+
+ sink(NewCookie.valueOf(taint()).getComment()); // $ hasTaintFlow
+ sink(NewCookie.valueOf(taint()).getExpiry()); // $ hasTaintFlow
+ sink(NewCookie.valueOf(taint()).getMaxAge()); // $ hasTaintFlow
+ sink(NewCookie.valueOf(taint()).toCookie()); // $ hasTaintFlow
+ sink(NewCookie.valueOf(taint())); // $ hasTaintFlow
+ }
+
+ void testForm(MultivaluedMap mm1, MultivaluedMap mm2) {
+ sink(new Form(taint(), "")); // $ hasTaintFlow
+ sink(new Form("", taint())); // $ hasTaintFlow
+ mm1.add(taint(), "value");
+ sink(new Form(mm1)); // $ hasTaintFlow
+ mm2.add("key", taint());
+ sink(new Form(mm2)); // $ hasTaintFlow
+ Form f1 = new Form(taint(), "");
+ sink(f1.asMap()); // $ hasTaintFlow
+ Form f2 = new Form();
+ sink(f2.param(taint(), "b")); // $ hasTaintFlow
+ Form f3 = new Form();
+ sink(f3.param("a", taint())); // $ hasTaintFlow
+ Form f4 = new Form(taint(), "");
+ sink(f4.param("a", "b")); // $ hasTaintFlow
+ }
+
+ void testGenericEntity() {
+ Method m = Dummy.class.getMethods()[0];
+ GenericEntity> ge = new GenericEntity>(SetStringSource.taint(), m.getGenericReturnType());
+ sink(ge); // $ hasTaintFlow
+ sink(ge.getEntity()); // $ hasTaintFlow
+ }
+
+ void testMediaType(Map m) {
+ sink(new MediaType(taint(), "")); // $ hasTaintFlow
+ sink(new MediaType("", taint())); // $ hasTaintFlow
+ sink(new MediaType(taint(), "", m)); // $ hasTaintFlow
+ sink(new MediaType("", taint(), m)); // $ hasTaintFlow
+ sink(new MediaType("", "", taint(m))); // $ hasTaintFlow
+ sink(new MediaType(taint(), "", "")); // $ hasTaintFlow
+ sink(new MediaType("", taint(), "")); // $ hasTaintFlow
+ sink(new MediaType("", "", taint())); // $ hasTaintFlow
+ sink(MediaType.valueOf(taint()).getParameters()); // $ hasTaintFlow
+ sink(MediaType.valueOf(taint()).getSubtype()); // $ hasTaintFlow
+ sink(MediaType.valueOf(taint()).getType()); // $ hasTaintFlow
+ sink(MediaType.valueOf(taint())); // $ hasTaintFlow
+ }
+
+ void testUriBuilder() throws Exception {
+ sink(UriBuilder.fromPath("").build(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").build("", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").build(taint(), false)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").build("", taint(), true)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).build("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).build("", false)); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").buildFromEncoded(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").buildFromEncoded("", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).buildFromEncoded("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").buildFromEncodedMap(taint(new HashMap()))); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).buildFromEncodedMap(new HashMap())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").buildFromMap(taint(new HashMap()), false)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).buildFromMap(new HashMap(), true)); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath(taint()).clone()); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").fragment(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).fragment("")); // $ hasTaintFlow
+ sink(UriBuilder.fromLink(taint(Link.valueOf("")))); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromUri(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").host(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).host("")); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").matrixParam(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").matrixParam("", "", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).matrixParam("", "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").path(taint(Dummy.class))); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").path(Dummy.class, taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).path(Dummy.class)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").queryParam(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").queryParam("", "", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).queryParam("", "")); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").replaceMatrix(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).replaceMatrix("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").replaceMatrixParam(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").replaceMatrixParam("", "", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).replaceMatrixParam("", "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").replacePath(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).replacePath("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").replaceQuery(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).replaceQuery("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").replaceQueryParam(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").replaceQueryParam("", "", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).replaceQueryParam("", "")); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").resolveTemplate(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplate(taint(), "", false)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplate("", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplate("", taint(), true)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).resolveTemplate("", "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).resolveTemplate("", "", false)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplateFromEncoded(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplateFromEncoded("", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).resolveTemplateFromEncoded("", "")); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").resolveTemplates(taint(new HashMap()))); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplates(taint(new HashMap()), true)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).resolveTemplates(new HashMap())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).resolveTemplates(new HashMap(), false)); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").resolveTemplatesFromEncoded(taint(new HashMap()))); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).resolveTemplatesFromEncoded(new HashMap())); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").scheme(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).scheme("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").schemeSpecificPart(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).schemeSpecificPart("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").segment(taint(), "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").segment("", "", taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).segment("", "")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).toTemplate()); // $ hasTaintFlow
+
+ sink(UriBuilder.fromPath("").uri(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).uri("")); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").uri(UriSource.taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).uri(new URI(""))); // $ hasTaintFlow
+ sink(UriBuilder.fromPath("").userInfo(taint())); // $ hasTaintFlow
+ sink(UriBuilder.fromPath(taint()).userInfo("")); // $ hasTaintFlow
+ }
+}
+
+class Dummy {
+ private static Set foo() { return null; }
+}
\ No newline at end of file
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.ql b/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.ql
new file mode 100644
index 00000000000..d3b1db90764
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.ql
@@ -0,0 +1,50 @@
+import java
+import semmle.code.java.dataflow.TaintTracking
+import TestUtilities.InlineExpectationsTest
+
+class TaintFlowConf extends TaintTracking::Configuration {
+ TaintFlowConf() { this = "qltest:frameworks:jax-rs-taint" }
+
+ override predicate isSource(DataFlow::Node n) {
+ n.asExpr().(MethodAccess).getMethod().hasName("taint")
+ }
+
+ override predicate isSink(DataFlow::Node n) {
+ exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
+ }
+}
+
+class ValueFlowConf extends DataFlow::Configuration {
+ ValueFlowConf() { this = "qltest:frameworks:jax-rs-value" }
+
+ override predicate isSource(DataFlow::Node n) {
+ n.asExpr().(MethodAccess).getMethod().hasName("taint")
+ }
+
+ override predicate isSink(DataFlow::Node n) {
+ exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
+ }
+}
+
+class HasFlowTest extends InlineExpectationsTest {
+ HasFlowTest() { this = "HasFlowTest" }
+
+ override string getARelevantTag() { result = ["hasTaintFlow", "hasValueFlow"] }
+
+ override predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "hasTaintFlow" and
+ exists(DataFlow::Node src, DataFlow::Node sink, TaintFlowConf conf | conf.hasFlow(src, sink) |
+ not any(ValueFlowConf vconf).hasFlow(src, sink) and
+ sink.getLocation() = location and
+ element = sink.toString() and
+ value = ""
+ )
+ or
+ tag = "hasValueFlow" and
+ exists(DataFlow::Node src, DataFlow::Node sink, ValueFlowConf conf | conf.hasFlow(src, sink) |
+ sink.getLocation() = location and
+ element = sink.toString() and
+ value = ""
+ )
+ }
+}
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.expected b/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.expected
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.java b/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.java
new file mode 100644
index 00000000000..511508cd774
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.java
@@ -0,0 +1,44 @@
+import javax.jws.WebMethod;
+import javax.jws.WebService;
+import javax.xml.ws.WebEndpoint;
+import javax.xml.ws.WebServiceClient;
+import javax.xml.ws.WebServiceProvider;
+
+@WebService
+class WebServiceClass { // $ JaxWsEndpoint
+
+ @WebMethod
+ void WebMethodMethod() { // $ JaxWsEndpointRemoteMethod
+ }
+
+ @WebEndpoint
+ void WebEndpointMethod() { // $ JaxWsEndpointRemoteMethod
+ }
+
+}
+
+@WebServiceProvider
+class WebServiceProviderClass { // $ JaxWsEndpoint
+
+ @WebMethod
+ void WebMethodMethod() { // $ JaxWsEndpointRemoteMethod
+ }
+
+ @WebEndpoint
+ void WebEndpointMethod() { // $ JaxWsEndpointRemoteMethod
+ }
+
+}
+
+@WebServiceClient
+class WebServiceClientClass { // $ JaxWsEndpoint
+
+ @WebMethod
+ void WebMethodMethod() { // $ JaxWsEndpointRemoteMethod
+ }
+
+ @WebEndpoint
+ void WebEndpointMethod() { // $ JaxWsEndpointRemoteMethod
+ }
+
+}
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.ql b/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.ql
new file mode 100644
index 00000000000..6ebd597bb0a
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.ql
@@ -0,0 +1,27 @@
+import java
+import semmle.code.java.frameworks.JaxWS
+import TestUtilities.InlineExpectationsTest
+
+class JaxWsEndpointTest extends InlineExpectationsTest {
+ JaxWsEndpointTest() { this = "JaxWsEndpointTest" }
+
+ override string getARelevantTag() { result = ["JaxWsEndpoint", "JaxWsEndpointRemoteMethod"] }
+
+ override predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "JaxWsEndpoint" and
+ exists(JaxWsEndpoint jaxWsEndpoint |
+ jaxWsEndpoint.getLocation() = location and
+ element = jaxWsEndpoint.toString() and
+ value = ""
+ )
+ or
+ tag = "JaxWsEndpointRemoteMethod" and
+ exists(Callable remoteMethod |
+ remoteMethod = any(JaxWsEndpoint jaxWsEndpoint).getARemoteMethod()
+ |
+ remoteMethod.getLocation() = location and
+ element = remoteMethod.toString() and
+ value = ""
+ )
+ }
+}
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirect.expected b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirect.expected
new file mode 100644
index 00000000000..a3557062441
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirect.expected
@@ -0,0 +1,19 @@
+edges
+| UrlRedirectJakarta.java:10:32:10:61 | getParameter(...) : String | UrlRedirectJakarta.java:10:24:10:62 | new URI(...) |
+| UrlRedirectJakarta.java:13:41:13:70 | getParameter(...) : String | UrlRedirectJakarta.java:13:33:13:71 | new URI(...) |
+| UrlRedirectJax.java:10:32:10:61 | getParameter(...) : String | UrlRedirectJax.java:10:24:10:62 | new URI(...) |
+| UrlRedirectJax.java:13:41:13:70 | getParameter(...) : String | UrlRedirectJax.java:13:33:13:71 | new URI(...) |
+nodes
+| UrlRedirectJakarta.java:10:24:10:62 | new URI(...) | semmle.label | new URI(...) |
+| UrlRedirectJakarta.java:10:32:10:61 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| UrlRedirectJakarta.java:13:33:13:71 | new URI(...) | semmle.label | new URI(...) |
+| UrlRedirectJakarta.java:13:41:13:70 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| UrlRedirectJax.java:10:24:10:62 | new URI(...) | semmle.label | new URI(...) |
+| UrlRedirectJax.java:10:32:10:61 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| UrlRedirectJax.java:13:33:13:71 | new URI(...) | semmle.label | new URI(...) |
+| UrlRedirectJax.java:13:41:13:70 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+#select
+| UrlRedirectJakarta.java:10:24:10:62 | new URI(...) | UrlRedirectJakarta.java:10:32:10:61 | getParameter(...) : String | UrlRedirectJakarta.java:10:24:10:62 | new URI(...) | Potentially untrusted URL redirection due to $@. | UrlRedirectJakarta.java:10:32:10:61 | getParameter(...) | user-provided value |
+| UrlRedirectJakarta.java:13:33:13:71 | new URI(...) | UrlRedirectJakarta.java:13:41:13:70 | getParameter(...) : String | UrlRedirectJakarta.java:13:33:13:71 | new URI(...) | Potentially untrusted URL redirection due to $@. | UrlRedirectJakarta.java:13:41:13:70 | getParameter(...) | user-provided value |
+| UrlRedirectJax.java:10:24:10:62 | new URI(...) | UrlRedirectJax.java:10:32:10:61 | getParameter(...) : String | UrlRedirectJax.java:10:24:10:62 | new URI(...) | Potentially untrusted URL redirection due to $@. | UrlRedirectJax.java:10:32:10:61 | getParameter(...) | user-provided value |
+| UrlRedirectJax.java:13:33:13:71 | new URI(...) | UrlRedirectJax.java:13:41:13:70 | getParameter(...) : String | UrlRedirectJax.java:13:33:13:71 | new URI(...) | Potentially untrusted URL redirection due to $@. | UrlRedirectJax.java:13:41:13:70 | getParameter(...) | user-provided value |
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirect.qlref b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirect.qlref
new file mode 100644
index 00000000000..b4772fb438f
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirect.qlref
@@ -0,0 +1 @@
+Security/CWE/CWE-601/UrlRedirect.ql
\ No newline at end of file
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJakarta.java b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJakarta.java
new file mode 100644
index 00000000000..897ee7890bd
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJakarta.java
@@ -0,0 +1,15 @@
+import java.io.IOException;
+import java.net.URI;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import jakarta.ws.rs.core.Response;
+
+public class UrlRedirectJakarta extends HttpServlet {
+ protected void doGetJax(HttpServletRequest request, Response jaxResponse) throws Exception {
+ // BAD
+ jaxResponse.seeOther(new URI(request.getParameter("target")));
+
+ // BAD
+ jaxResponse.temporaryRedirect(new URI(request.getParameter("target")));
+ }
+}
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJax.java b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJax.java
new file mode 100644
index 00000000000..4ba3d1f1331
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJax.java
@@ -0,0 +1,15 @@
+import java.io.IOException;
+import java.net.URI;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Response;
+
+public class UrlRedirectJax extends HttpServlet {
+ protected void doGetJax(HttpServletRequest request, Response jaxResponse) throws Exception {
+ // BAD
+ jaxResponse.seeOther(new URI(request.getParameter("target")));
+
+ // BAD
+ jaxResponse.temporaryRedirect(new URI(request.getParameter("target")));
+ }
+}
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/options b/java/ql/test/library-tests/frameworks/JaxWs/options
new file mode 100644
index 00000000000..a2050069049
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/options
@@ -0,0 +1 @@
+//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/javax-ws-rs-api-2.1.1:${testdir}/../../../stubs/javax-ws-rs-api-3.0.0:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/jsr181-api:${testdir}/../../../stubs/jaxws-api-2.0:${testdir}/../../../stubs/servlet-api-2.4
diff --git a/java/ql/test/library-tests/frameworks/apache-commons-lang3/PairTest.java b/java/ql/test/library-tests/frameworks/apache-commons-lang3/PairTest.java
new file mode 100644
index 00000000000..6db15beb181
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/apache-commons-lang3/PairTest.java
@@ -0,0 +1,150 @@
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.MutablePair;
+
+class PairTest {
+ String taint() { return "tainted"; }
+
+ private static class IntSource {
+ static int taint() { return 0; }
+ }
+
+ void sink(Object o) {}
+
+ void test() throws Exception {
+
+ ImmutablePair taintedLeft = ImmutablePair.of(taint(), "clean-right");
+ ImmutablePair taintedRight = ImmutablePair.of("clean-left", taint());
+ Pair taintedLeft2_ = ImmutablePair.left(taint());
+ ImmutablePair taintedLeft2 = (ImmutablePair)taintedLeft2_;
+ Pair taintedRight2_ = ImmutablePair.right(taint());
+ ImmutablePair taintedRight2 = (ImmutablePair)taintedRight2_;
+ Pair taintedLeft3 = Pair.of(taint(), "clean-right");
+ Pair taintedRight3 = Pair.of("clean-left", taint());
+ ImmutablePair taintedLeft4 = new ImmutablePair(taint(), "clean-right");
+ ImmutablePair taintedRight4 = new ImmutablePair("clean-left", taint());
+
+ // Check flow through ImmutablePairs:
+ sink(taintedLeft.getLeft()); // $hasValueFlow
+ sink(taintedLeft.getRight());
+ sink(taintedLeft.getKey()); // $hasValueFlow
+ sink(taintedLeft.getValue());
+ sink(taintedLeft.left); // $hasValueFlow
+ sink(taintedLeft.right);
+ sink(taintedRight.getLeft());
+ sink(taintedRight.getRight()); // $hasValueFlow
+ sink(taintedRight.getKey());
+ sink(taintedRight.getValue()); // $hasValueFlow
+ sink(taintedRight.left);
+ sink(taintedRight.right); // $hasValueFlow
+ sink(taintedLeft2.getLeft()); // $hasValueFlow
+ sink(taintedLeft2.getRight());
+ sink(taintedLeft2.getKey()); // $hasValueFlow
+ sink(taintedLeft2.getValue());
+ sink(taintedLeft2.left); // $hasValueFlow
+ sink(taintedLeft2.right);
+ sink(taintedRight2.getLeft());
+ sink(taintedRight2.getRight()); // $hasValueFlow
+ sink(taintedRight2.getKey());
+ sink(taintedRight2.getValue()); // $hasValueFlow
+ sink(taintedRight2.left);
+ sink(taintedRight2.right); // $hasValueFlow
+ sink(taintedLeft3.getLeft()); // $hasValueFlow
+ sink(taintedLeft3.getRight());
+ sink(taintedLeft3.getKey()); // $hasValueFlow
+ sink(taintedLeft3.getValue());
+ sink(taintedRight3.getLeft());
+ sink(taintedRight3.getRight()); // $hasValueFlow
+ sink(taintedRight3.getKey());
+ sink(taintedRight3.getValue()); // $hasValueFlow
+ sink(taintedLeft4.getLeft()); // $hasValueFlow
+ sink(taintedLeft4.getRight());
+ sink(taintedLeft4.getKey()); // $hasValueFlow
+ sink(taintedLeft4.getValue());
+ sink(taintedLeft4.left); // $hasValueFlow
+ sink(taintedLeft4.right);
+ sink(taintedRight4.getLeft());
+ sink(taintedRight4.getRight()); // $hasValueFlow
+ sink(taintedRight4.getKey());
+ sink(taintedRight4.getValue()); // $hasValueFlow
+ sink(taintedRight4.left);
+ sink(taintedRight4.right); // $hasValueFlow
+
+ // Check flow also works via an alias of type Pair:
+ sink(taintedLeft2_.getLeft()); // $hasValueFlow
+ sink(taintedLeft2_.getRight());
+ sink(taintedLeft2_.getKey()); // $hasValueFlow
+ sink(taintedLeft2_.getValue());
+ sink(taintedRight2_.getLeft());
+ sink(taintedRight2_.getRight()); // $hasValueFlow
+ sink(taintedRight2_.getKey());
+ sink(taintedRight2_.getValue()); // $hasValueFlow
+
+ // Check flow through MutablePairs:
+ MutablePair taintedLeftMutable = MutablePair.of(taint(), "clean-right");
+ MutablePair taintedRightMutable = MutablePair.of("clean-left", taint());
+ MutablePair setTaintLeft = MutablePair.of("clean-left", "clean-right");
+ setTaintLeft.setLeft(taint());
+ MutablePair setTaintRight = MutablePair.of("clean-left", "clean-right");
+ setTaintRight.setRight(taint());
+ MutablePair setTaintValue = MutablePair.of("clean-left", "clean-right");
+ setTaintValue.setValue(taint());
+ MutablePair taintedLeftMutableConstructed = new MutablePair(taint(), "clean-right");
+ MutablePair taintedRightMutableConstructed = new MutablePair("clean-left", taint());
+
+ sink(taintedLeftMutable.getLeft()); // $hasValueFlow
+ sink(taintedLeftMutable.getRight());
+ sink(taintedLeftMutable.getKey()); // $hasValueFlow
+ sink(taintedLeftMutable.getValue());
+ sink(taintedLeftMutable.left); // $hasValueFlow
+ sink(taintedLeftMutable.right);
+ sink(taintedRightMutable.getLeft());
+ sink(taintedRightMutable.getRight()); // $hasValueFlow
+ sink(taintedRightMutable.getKey());
+ sink(taintedRightMutable.getValue()); // $hasValueFlow
+ sink(taintedRightMutable.left);
+ sink(taintedRightMutable.right); // $hasValueFlow
+ sink(setTaintLeft.getLeft()); // $hasValueFlow
+ sink(setTaintLeft.getRight());
+ sink(setTaintLeft.getKey()); // $hasValueFlow
+ sink(setTaintLeft.getValue());
+ sink(setTaintLeft.left); // $hasValueFlow
+ sink(setTaintLeft.right);
+ sink(setTaintRight.getLeft());
+ sink(setTaintRight.getRight()); // $hasValueFlow
+ sink(setTaintRight.getKey());
+ sink(setTaintRight.getValue()); // $hasValueFlow
+ sink(setTaintRight.left);
+ sink(setTaintRight.right); // $hasValueFlow
+ sink(setTaintValue.getLeft());
+ sink(setTaintValue.getRight()); // $hasValueFlow
+ sink(setTaintValue.getKey());
+ sink(setTaintValue.getValue()); // $hasValueFlow
+ sink(setTaintValue.left);
+ sink(setTaintValue.right); // $hasValueFlow
+ sink(taintedLeftMutableConstructed.getLeft()); // $hasValueFlow
+ sink(taintedLeftMutableConstructed.getRight());
+ sink(taintedLeftMutableConstructed.getKey()); // $hasValueFlow
+ sink(taintedLeftMutableConstructed.getValue());
+ sink(taintedLeftMutableConstructed.left); // $hasValueFlow
+ sink(taintedLeftMutableConstructed.right);
+ sink(taintedRightMutableConstructed.getLeft());
+ sink(taintedRightMutableConstructed.getRight()); // $hasValueFlow
+ sink(taintedRightMutableConstructed.getKey());
+ sink(taintedRightMutableConstructed.getValue()); // $hasValueFlow
+ sink(taintedRightMutableConstructed.left);
+ sink(taintedRightMutableConstructed.right); // $hasValueFlow
+
+ // Check flow also works via an alias of type Pair:
+ Pair taintedLeftMutableAlias = taintedLeftMutable;
+ Pair taintedRightMutableAlias = taintedRightMutable;
+ sink(taintedLeftMutableAlias.getLeft()); // $hasValueFlow
+ sink(taintedLeftMutableAlias.getRight());
+ sink(taintedLeftMutableAlias.getKey()); // $hasValueFlow
+ sink(taintedLeftMutableAlias.getValue());
+ sink(taintedRightMutableAlias.getLeft());
+ sink(taintedRightMutableAlias.getRight()); // $hasValueFlow
+ sink(taintedRightMutableAlias.getKey());
+ sink(taintedRightMutableAlias.getValue()); // $hasValueFlow
+ }
+}
\ No newline at end of file
diff --git a/java/ql/test/library-tests/frameworks/apache-commons-lang3/TripleTest.java b/java/ql/test/library-tests/frameworks/apache-commons-lang3/TripleTest.java
new file mode 100644
index 00000000000..b6f9c53cc7e
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/apache-commons-lang3/TripleTest.java
@@ -0,0 +1,181 @@
+import org.apache.commons.lang3.tuple.Triple;
+import org.apache.commons.lang3.tuple.ImmutableTriple;
+import org.apache.commons.lang3.tuple.MutableTriple;
+
+class TripleTest {
+ String taint() { return "tainted"; }
+
+ private static class IntSource {
+ static int taint() { return 0; }
+ }
+
+ void sink(Object o) {}
+
+ void test() throws Exception {
+
+ ImmutableTriple taintedLeft = ImmutableTriple.of(taint(), "clean-middle", "clean-right");
+ ImmutableTriple taintedMiddle = ImmutableTriple.of("clean-left", taint(), "clean-right");
+ ImmutableTriple taintedRight = ImmutableTriple.of("clean-left", "clean-middle", taint());
+
+ // Check flow through ImmutableTriples:
+ sink(taintedLeft.getLeft()); // $hasValueFlow
+ sink(taintedLeft.getMiddle());
+ sink(taintedLeft.getRight());
+ sink(taintedLeft.left); // $hasValueFlow
+ sink(taintedLeft.middle);
+ sink(taintedLeft.right);
+ sink(taintedMiddle.getLeft());
+ sink(taintedMiddle.getMiddle()); // $hasValueFlow
+ sink(taintedMiddle.getRight());
+ sink(taintedMiddle.left);
+ sink(taintedMiddle.middle); // $hasValueFlow
+ sink(taintedMiddle.right);
+ sink(taintedRight.getLeft());
+ sink(taintedRight.getMiddle());
+ sink(taintedRight.getRight()); // $hasValueFlow
+ sink(taintedRight.left);
+ sink(taintedRight.middle);
+ sink(taintedRight.right); // $hasValueFlow
+
+ Triple taintedLeft2 = taintedLeft;
+ Triple taintedMiddle2 = taintedMiddle;
+ Triple taintedRight2 = taintedRight;
+
+ // Check flow also works via an alias of type Triple:
+ sink(taintedLeft2.getLeft()); // $hasValueFlow
+ sink(taintedLeft2.getMiddle());
+ sink(taintedLeft2.getRight());
+ sink(taintedMiddle2.getLeft());
+ sink(taintedMiddle2.getMiddle()); // $hasValueFlow
+ sink(taintedMiddle2.getRight());
+ sink(taintedRight2.getLeft());
+ sink(taintedRight2.getMiddle());
+ sink(taintedRight2.getRight()); // $hasValueFlow
+
+ // Check flow via Triple.of:
+ Triple taintedLeft3 = Triple.of(taint(), "clean-middle", "clean-right");
+ Triple taintedMiddle3 = Triple.of("clean-left", taint(), "clean-right");
+ Triple taintedRight3 = Triple.of("clean-left", "clean-middle", taint());
+
+ sink(taintedLeft3.getLeft()); // $hasValueFlow
+ sink(taintedLeft3.getMiddle());
+ sink(taintedLeft3.getRight());
+ sink(taintedMiddle3.getLeft());
+ sink(taintedMiddle3.getMiddle()); // $hasValueFlow
+ sink(taintedMiddle3.getRight());
+ sink(taintedRight3.getLeft());
+ sink(taintedRight3.getMiddle());
+ sink(taintedRight3.getRight()); // $hasValueFlow
+
+ // Check flow via constructor:
+ ImmutableTriple taintedLeft4 = new ImmutableTriple(taint(), "clean-middle", "clean-right");
+ ImmutableTriple taintedMiddle4 = new ImmutableTriple("clean-left", taint(), "clean-right");
+ ImmutableTriple taintedRight4 = new ImmutableTriple("clean-left", "clean-middle", taint());
+
+ sink(taintedLeft4.getLeft()); // $hasValueFlow
+ sink(taintedLeft4.getMiddle());
+ sink(taintedLeft4.getRight());
+ sink(taintedMiddle4.getLeft());
+ sink(taintedMiddle4.getMiddle()); // $hasValueFlow
+ sink(taintedMiddle4.getRight());
+ sink(taintedRight4.getLeft());
+ sink(taintedRight4.getMiddle());
+ sink(taintedRight4.getRight()); // $hasValueFlow
+
+ MutableTriple mutableTaintedLeft = MutableTriple.of(taint(), "clean-middle", "clean-right");
+ MutableTriple mutableTaintedMiddle = MutableTriple.of("clean-left", taint(), "clean-right");
+ MutableTriple mutableTaintedRight = MutableTriple.of("clean-left", "clean-middle", taint());
+ MutableTriple setTaintedLeft = MutableTriple.of("clean-left", "clean-middle", "clean-right");
+ setTaintedLeft.setLeft(taint());
+ MutableTriple setTaintedMiddle = MutableTriple.of("clean-left", "clean-middle", "clean-right");
+ setTaintedMiddle.setMiddle(taint());
+ MutableTriple setTaintedRight = MutableTriple.of("clean-left", "clean-middle", "clean-right");
+ setTaintedRight.setRight(taint());
+ MutableTriple mutableTaintedLeftConstructed = new MutableTriple(taint(), "clean-middle", "clean-right");
+ MutableTriple mutableTaintedMiddleConstructed = new MutableTriple("clean-left", taint(), "clean-right");
+ MutableTriple mutableTaintedRightConstructed = new MutableTriple("clean-left", "clean-middle", taint());
+
+ // Check flow through MutableTriples:
+ sink(mutableTaintedLeft.getLeft()); // $hasValueFlow
+ sink(mutableTaintedLeft.getMiddle());
+ sink(mutableTaintedLeft.getRight());
+ sink(mutableTaintedLeft.left); // $hasValueFlow
+ sink(mutableTaintedLeft.middle);
+ sink(mutableTaintedLeft.right);
+ sink(mutableTaintedMiddle.getLeft());
+ sink(mutableTaintedMiddle.getMiddle()); // $hasValueFlow
+ sink(mutableTaintedMiddle.getRight());
+ sink(mutableTaintedMiddle.left);
+ sink(mutableTaintedMiddle.middle); // $hasValueFlow
+ sink(mutableTaintedMiddle.right);
+ sink(mutableTaintedRight.getLeft());
+ sink(mutableTaintedRight.getMiddle());
+ sink(mutableTaintedRight.getRight()); // $hasValueFlow
+ sink(mutableTaintedRight.left);
+ sink(mutableTaintedRight.middle);
+ sink(mutableTaintedRight.right); // $hasValueFlow
+ sink(setTaintedLeft.getLeft()); // $hasValueFlow
+ sink(setTaintedLeft.getMiddle());
+ sink(setTaintedLeft.getRight());
+ sink(setTaintedLeft.left); // $hasValueFlow
+ sink(setTaintedLeft.middle);
+ sink(setTaintedLeft.right);
+ sink(setTaintedMiddle.getLeft());
+ sink(setTaintedMiddle.getMiddle()); // $hasValueFlow
+ sink(setTaintedMiddle.getRight());
+ sink(setTaintedMiddle.left);
+ sink(setTaintedMiddle.middle); // $hasValueFlow
+ sink(setTaintedMiddle.right);
+ sink(setTaintedRight.getLeft());
+ sink(setTaintedRight.getMiddle());
+ sink(setTaintedRight.getRight()); // $hasValueFlow
+ sink(setTaintedRight.left);
+ sink(setTaintedRight.middle);
+ sink(setTaintedRight.right); // $hasValueFlow
+ sink(mutableTaintedLeftConstructed.getLeft()); // $hasValueFlow
+ sink(mutableTaintedLeftConstructed.getMiddle());
+ sink(mutableTaintedLeftConstructed.getRight());
+ sink(mutableTaintedLeftConstructed.left); // $hasValueFlow
+ sink(mutableTaintedLeftConstructed.middle);
+ sink(mutableTaintedLeftConstructed.right);
+ sink(mutableTaintedMiddleConstructed.getLeft());
+ sink(mutableTaintedMiddleConstructed.getMiddle()); // $hasValueFlow
+ sink(mutableTaintedMiddleConstructed.getRight());
+ sink(mutableTaintedMiddleConstructed.left);
+ sink(mutableTaintedMiddleConstructed.middle); // $hasValueFlow
+ sink(mutableTaintedMiddleConstructed.right);
+ sink(mutableTaintedRightConstructed.getLeft());
+ sink(mutableTaintedRightConstructed.getMiddle());
+ sink(mutableTaintedRightConstructed.getRight()); // $hasValueFlow
+ sink(mutableTaintedRightConstructed.left);
+ sink(mutableTaintedRightConstructed.middle);
+ sink(mutableTaintedRightConstructed.right); // $hasValueFlow
+
+ Triple mutableTaintedLeft2 = mutableTaintedLeft;
+ Triple mutableTaintedMiddle2 = mutableTaintedMiddle;
+ Triple mutableTaintedRight2 = mutableTaintedRight;
+ Triple setTaintedLeft2 = setTaintedLeft;
+ Triple setTaintedMiddle2 = setTaintedMiddle;
+ Triple setTaintedRight2 = setTaintedRight;
+
+ // Check flow also works via an alias of type Triple:
+ sink(mutableTaintedLeft2.getLeft()); // $hasValueFlow
+ sink(mutableTaintedLeft2.getMiddle());
+ sink(mutableTaintedLeft2.getRight());
+ sink(mutableTaintedMiddle2.getLeft());
+ sink(mutableTaintedMiddle2.getMiddle()); // $hasValueFlow
+ sink(mutableTaintedMiddle2.getRight());
+ sink(mutableTaintedRight2.getLeft());
+ sink(mutableTaintedRight2.getMiddle());
+ sink(mutableTaintedRight2.getRight()); // $hasValueFlow
+ sink(setTaintedLeft2.getLeft()); // $hasValueFlow
+ sink(setTaintedLeft2.getMiddle());
+ sink(setTaintedLeft2.getRight());
+ sink(setTaintedMiddle2.getLeft());
+ sink(setTaintedMiddle2.getMiddle()); // $hasValueFlow
+ sink(setTaintedMiddle2.getRight());
+ sink(setTaintedRight2.getLeft());
+ sink(setTaintedRight2.getMiddle());
+ sink(setTaintedRight2.getRight()); // $hasValueFlow
+ }
+}
\ No newline at end of file
diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.expected b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.expected
new file mode 100644
index 00000000000..35595b1bfc3
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.expected
@@ -0,0 +1,19 @@
+edges
+| HttpsUrlsTest.java:23:23:23:31 | "http://" : String | HttpsUrlsTest.java:28:50:28:50 | u |
+| HttpsUrlsTest.java:36:23:36:28 | "http" : String | HttpsUrlsTest.java:41:50:41:50 | u |
+| HttpsUrlsTest.java:49:23:49:31 | "http://" : String | HttpsUrlsTest.java:55:50:55:50 | u |
+| HttpsUrlsTest.java:87:23:87:28 | "http" : String | HttpsUrlsTest.java:92:50:92:50 | u |
+nodes
+| HttpsUrlsTest.java:23:23:23:31 | "http://" : String | semmle.label | "http://" : String |
+| HttpsUrlsTest.java:28:50:28:50 | u | semmle.label | u |
+| HttpsUrlsTest.java:36:23:36:28 | "http" : String | semmle.label | "http" : String |
+| HttpsUrlsTest.java:41:50:41:50 | u | semmle.label | u |
+| HttpsUrlsTest.java:49:23:49:31 | "http://" : String | semmle.label | "http://" : String |
+| HttpsUrlsTest.java:55:50:55:50 | u | semmle.label | u |
+| HttpsUrlsTest.java:87:23:87:28 | "http" : String | semmle.label | "http" : String |
+| HttpsUrlsTest.java:92:50:92:50 | u | semmle.label | u |
+#select
+| HttpsUrlsTest.java:28:50:28:67 | openConnection(...) | HttpsUrlsTest.java:23:23:23:31 | "http://" : String | HttpsUrlsTest.java:28:50:28:50 | u | URL may have been constructed with HTTP protocol, using $@. | HttpsUrlsTest.java:23:23:23:31 | "http://" | this source |
+| HttpsUrlsTest.java:41:50:41:67 | openConnection(...) | HttpsUrlsTest.java:36:23:36:28 | "http" : String | HttpsUrlsTest.java:41:50:41:50 | u | URL may have been constructed with HTTP protocol, using $@. | HttpsUrlsTest.java:36:23:36:28 | "http" | this source |
+| HttpsUrlsTest.java:55:50:55:67 | openConnection(...) | HttpsUrlsTest.java:49:23:49:31 | "http://" : String | HttpsUrlsTest.java:55:50:55:50 | u | URL may have been constructed with HTTP protocol, using $@. | HttpsUrlsTest.java:49:23:49:31 | "http://" | this source |
+| HttpsUrlsTest.java:92:50:92:67 | openConnection(...) | HttpsUrlsTest.java:87:23:87:28 | "http" : String | HttpsUrlsTest.java:92:50:92:50 | u | URL may have been constructed with HTTP protocol, using $@. | HttpsUrlsTest.java:87:23:87:28 | "http" | this source |
diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.qlref b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.qlref
new file mode 100644
index 00000000000..bd936a400c0
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.qlref
@@ -0,0 +1 @@
+Security/CWE/CWE-319/HttpsUrls.ql
\ No newline at end of file
diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrlsTest.java b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrlsTest.java
new file mode 100644
index 00000000000..900718904d2
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrlsTest.java
@@ -0,0 +1,119 @@
+// Semmle test case for CWE-319: Cleartext Transmission of Sensitive Data
+// http://cwe.mitre.org/data/definitions/319.html
+package test.cwe319.cwe.examples;
+
+import java.net.URL;
+import java.io.*;
+import java.rmi.*;
+import java.rmi.server.*;
+import java.rmi.registry.*;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.rmi.ssl.*;
+
+interface Hello extends java.rmi.Remote {
+ String sayHello() throws java.rmi.RemoteException;
+}
+
+class HelloImpl implements Hello {
+ public static void main(String[] args) {
+ try {
+ // HttpsUrls
+ {
+ String protocol = "http://";
+ URL u = new URL(protocol + "www.secret.example.org/");
+ // using HttpsURLConnections to enforce SSL is desirable
+ // BAD: this will give a ClassCastException at runtime, as the
+ // http URL cannot be used to make an HttpsURLConnection
+ HttpsURLConnection hu = (HttpsURLConnection) u.openConnection();
+ hu.setRequestMethod("PUT");
+ hu.connect();
+ OutputStream os = hu.getOutputStream();
+ hu.disconnect();
+ }
+
+ {
+ String protocol = "http";
+ URL u = new URL(protocol, "www.secret.example.org", "foo");
+ // using HttpsURLConnections to enforce SSL is desirable
+ // BAD: this will give a ClassCastException at runtime, as the
+ // http URL cannot be used to make an HttpsURLConnection
+ HttpsURLConnection hu = (HttpsURLConnection) u.openConnection();
+ hu.setRequestMethod("PUT");
+ hu.connect();
+ OutputStream os = hu.getOutputStream();
+ hu.disconnect();
+ }
+
+ {
+ String protocol = "http://";
+ // the second URL overwrites the first, as it has a protocol
+ URL u = new URL(new URL("https://www.secret.example.org"), protocol + "www.secret.example.org");
+ // using HttpsURLConnections to enforce SSL is desirable
+ // BAD: this will give a ClassCastException at runtime, as the
+ // http URL cannot be used to make an HttpsURLConnection
+ HttpsURLConnection hu = (HttpsURLConnection) u.openConnection();
+ hu.setRequestMethod("PUT");
+ hu.connect();
+ OutputStream os = hu.getOutputStream();
+ hu.disconnect();
+ }
+
+ {
+ String protocol = "https://";
+ URL u = new URL(protocol + "www.secret.example.org/");
+ // using HttpsURLConnections to enforce SSL is desirable
+ // GOOD: open connection to URL using HTTPS
+ HttpsURLConnection hu = (HttpsURLConnection) u.openConnection();
+ hu.setRequestMethod("PUT");
+ hu.connect();
+ OutputStream os = hu.getOutputStream();
+ hu.disconnect();
+ }
+
+ {
+ String protocol = "https";
+ URL u = new URL(protocol, "www.secret.example.org", "foo");
+ // using HttpsURLConnections to enforce SSL is desirable
+ // GOOD: open connection to URL using HTTPS
+ HttpsURLConnection hu = (HttpsURLConnection) u.openConnection();
+ hu.setRequestMethod("PUT");
+ hu.connect();
+ OutputStream os = hu.getOutputStream();
+ hu.disconnect();
+ }
+
+ {
+ String protocol = "http";
+ URL u = new URL(protocol, "internal-url", "foo");
+ // FALSE POSITIVE: the query has no way of knowing whether the url will
+ // resolve to somewhere outside the internal network, where there
+ // are unlikely to be interception attempts
+ HttpsURLConnection hu = (HttpsURLConnection) u.openConnection();
+ hu.setRequestMethod("PUT");
+ hu.connect();
+ OutputStream os = hu.getOutputStream();
+ hu.disconnect();
+ }
+
+ {
+ String input = "URL is: http://www.secret-example.org";
+ String url = input.substring(8);
+ URL u = new URL(url);
+ // FALSE NEGATIVE: we cannot tell that the substring results in a url
+ // string
+ HttpsURLConnection hu = (HttpsURLConnection) u.openConnection();
+ hu.setRequestMethod("PUT");
+ hu.connect();
+ OutputStream os = hu.getOutputStream();
+ hu.disconnect();
+ }
+ } catch (Exception e) {
+ // fail
+ }
+ }
+
+ public String sayHello() {
+ return "Hello";
+ }
+}
\ No newline at end of file
diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSL.expected b/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSL.expected
index d7769378f72..40f76e3bb10 100644
--- a/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSL.expected
+++ b/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSL.expected
@@ -1 +1 @@
-| Test.java:11:15:11:41 | getInputStream(...) | Stream using vulnerable non-SSL connection. |
+| UseSSLTest.java:11:15:11:41 | getInputStream(...) | Stream using vulnerable non-SSL connection. |
diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-319/Test.java b/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSLTest.java
similarity index 95%
rename from java/ql/test/query-tests/security/CWE-311/CWE-319/Test.java
rename to java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSLTest.java
index 9e2f3f923e8..b6ff8b57fbf 100644
--- a/java/ql/test/query-tests/security/CWE-311/CWE-319/Test.java
+++ b/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSLTest.java
@@ -2,7 +2,7 @@ import java.net.HttpURLConnection;
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
-class Test {
+class UseSSLTest {
public void m1(HttpURLConnection connection) throws java.io.IOException {
InputStream input;
if (connection instanceof HttpsURLConnection) {
diff --git a/java/ql/test/query-tests/security/CWE-502/C.java b/java/ql/test/query-tests/security/CWE-502/C.java
new file mode 100644
index 00000000000..bae0ca8ceae
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-502/C.java
@@ -0,0 +1,114 @@
+import java.util.HashMap;
+import java.io.StringReader;
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import com.cedarsoftware.util.io.JsonReader;
+import com.esotericsoftware.yamlbeans.YamlReader;
+import org.ho.yaml.Yaml;
+import org.ho.yaml.YamlConfig;
+import org.exolab.castor.xml.Unmarshaller;
+import com.caucho.hessian.io.Hessian2Input;
+import com.caucho.hessian.io.HessianInput;
+import com.caucho.burlap.io.BurlapInput;
+import com.caucho.hessian.io.Hessian2Input;
+import com.caucho.hessian.io.HessianInput;
+import java.io.ByteArrayInputStream;
+
+@Controller
+public class C {
+
+ @GetMapping(value = "jyaml")
+ public void bad1(HttpServletRequest request) throws Exception {
+ String data = request.getParameter("data");
+ Yaml.load(data); //bad
+ Yaml.loadStream(data); //bad
+ Yaml.loadStreamOfType(data, Object.class); //bad
+ Yaml.loadType(data, Object.class); //bad
+
+ org.ho.yaml.YamlConfig yamlConfig = new YamlConfig();
+ yamlConfig.load(data); //bad
+ yamlConfig.loadStream(data); //bad
+ yamlConfig.loadStreamOfType(data, Object.class); //bad
+ yamlConfig.loadType(data, Object.class); //bad
+ }
+
+ @GetMapping(value = "jsonio")
+ public void bad2(HttpServletRequest request) {
+ String data = request.getParameter("data");
+
+ HashMap hashMap = new HashMap();
+ hashMap.put("USE_MAPS", true);
+
+ JsonReader.jsonToJava(data); //bad
+
+ JsonReader jr = new JsonReader(data, null); //bad
+ jr.readObject();
+ }
+
+ @GetMapping(value = "yamlbeans")
+ public void bad3(HttpServletRequest request) throws Exception {
+ String data = request.getParameter("data");
+ YamlReader r = new YamlReader(data);
+ r.read(); //bad
+ r.read(Object.class); //bad
+ r.read(Object.class, Object.class); //bad
+ }
+
+ @GetMapping(value = "hessian")
+ public void bad4(HttpServletRequest request) throws Exception {
+ byte[] bytes = request.getParameter("data").getBytes();
+ ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+ HessianInput hessianInput = new HessianInput(bis);
+ hessianInput.readObject(); //bad
+ hessianInput.readObject(Object.class); //bad
+ }
+
+ @GetMapping(value = "hessian2")
+ public void bad5(HttpServletRequest request) throws Exception {
+ byte[] bytes = request.getParameter("data").getBytes();
+ ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+ Hessian2Input hessianInput = new Hessian2Input(bis);
+ hessianInput.readObject(); //bad
+ hessianInput.readObject(Object.class); //bad
+ }
+
+ @GetMapping(value = "castor")
+ public void bad6(HttpServletRequest request) throws Exception {
+ Unmarshaller unmarshaller = new Unmarshaller();
+ unmarshaller.unmarshal(new StringReader(request.getParameter("data"))); //bad
+ }
+
+ @GetMapping(value = "burlap")
+ public void bad7(HttpServletRequest request) throws Exception {
+ byte[] serializedData = request.getParameter("data").getBytes();
+ ByteArrayInputStream is = new ByteArrayInputStream(serializedData);
+ BurlapInput burlapInput = new BurlapInput(is);
+ burlapInput.readObject(); //bad
+
+ BurlapInput burlapInput1 = new BurlapInput();
+ burlapInput1.init(is);
+ burlapInput1.readObject(); //bad
+ }
+
+ @GetMapping(value = "jsonio1")
+ public void good1(HttpServletRequest request) {
+ String data = request.getParameter("data");
+
+ HashMap hashMap = new HashMap();
+ hashMap.put("USE_MAPS", true);
+
+ JsonReader.jsonToJava(data, hashMap); //good
+ }
+
+ @GetMapping(value = "jsonio2")
+ public void good2(HttpServletRequest request) {
+ String data = request.getParameter("data");
+
+ HashMap hashMap = new HashMap();
+ hashMap.put("USE_MAPS", true);
+
+ JsonReader jr1 = new JsonReader(data, hashMap); //good
+ jr1.readObject();
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected
index 2af8369c111..7b02131cd73 100644
--- a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected
+++ b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected
@@ -48,6 +48,38 @@ edges
| B.java:27:31:27:51 | getInputStream(...) : InputStream | B.java:29:5:29:15 | inputStream : InputStream |
| B.java:29:5:29:15 | inputStream : InputStream | B.java:29:22:29:26 | bytes [post update] : byte[] |
| B.java:29:22:29:26 | bytes [post update] : byte[] | B.java:31:23:31:23 | s |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:24:13:24:16 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:25:19:25:22 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:26:25:26:28 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:27:17:27:20 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:30:19:30:22 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:31:25:31:28 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:32:31:32:34 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:33:23:33:26 | data |
+| C.java:38:17:38:44 | getParameter(...) : String | C.java:43:25:43:28 | data |
+| C.java:38:17:38:44 | getParameter(...) : String | C.java:46:3:46:4 | jr |
+| C.java:51:17:51:44 | getParameter(...) : String | C.java:53:3:53:3 | r |
+| C.java:51:17:51:44 | getParameter(...) : String | C.java:54:3:54:3 | r |
+| C.java:51:17:51:44 | getParameter(...) : String | C.java:55:3:55:3 | r |
+| C.java:60:18:60:45 | getParameter(...) : String | C.java:61:55:61:59 | bytes : byte[] |
+| C.java:60:18:60:45 | getParameter(...) : String | C.java:63:3:63:14 | hessianInput |
+| C.java:60:18:60:45 | getParameter(...) : String | C.java:64:3:64:14 | hessianInput |
+| C.java:61:30:61:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:63:3:63:14 | hessianInput |
+| C.java:61:30:61:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:64:3:64:14 | hessianInput |
+| C.java:61:55:61:59 | bytes : byte[] | C.java:61:30:61:60 | new ByteArrayInputStream(...) : ByteArrayInputStream |
+| C.java:69:18:69:45 | getParameter(...) : String | C.java:70:55:70:59 | bytes : byte[] |
+| C.java:69:18:69:45 | getParameter(...) : String | C.java:72:3:72:14 | hessianInput |
+| C.java:69:18:69:45 | getParameter(...) : String | C.java:73:3:73:14 | hessianInput |
+| C.java:70:30:70:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:72:3:72:14 | hessianInput |
+| C.java:70:30:70:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:73:3:73:14 | hessianInput |
+| C.java:70:55:70:59 | bytes : byte[] | C.java:70:30:70:60 | new ByteArrayInputStream(...) : ByteArrayInputStream |
+| C.java:79:43:79:70 | getParameter(...) : String | C.java:79:26:79:71 | new StringReader(...) |
+| C.java:84:27:84:54 | getParameter(...) : String | C.java:85:54:85:67 | serializedData : byte[] |
+| C.java:84:27:84:54 | getParameter(...) : String | C.java:87:3:87:13 | burlapInput |
+| C.java:84:27:84:54 | getParameter(...) : String | C.java:91:3:91:14 | burlapInput1 |
+| C.java:85:29:85:68 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:87:3:87:13 | burlapInput |
+| C.java:85:29:85:68 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:91:3:91:14 | burlapInput1 |
+| C.java:85:54:85:67 | serializedData : byte[] | C.java:85:29:85:68 | new ByteArrayInputStream(...) : ByteArrayInputStream |
| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) |
| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:40:22:51 | entityStream : InputStream |
| TestMessageBodyReader.java:22:40:22:51 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) |
@@ -111,6 +143,39 @@ nodes
| B.java:29:5:29:15 | inputStream : InputStream | semmle.label | inputStream : InputStream |
| B.java:29:22:29:26 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
| B.java:31:23:31:23 | s | semmle.label | s |
+| C.java:23:17:23:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:24:13:24:16 | data | semmle.label | data |
+| C.java:25:19:25:22 | data | semmle.label | data |
+| C.java:26:25:26:28 | data | semmle.label | data |
+| C.java:27:17:27:20 | data | semmle.label | data |
+| C.java:30:19:30:22 | data | semmle.label | data |
+| C.java:31:25:31:28 | data | semmle.label | data |
+| C.java:32:31:32:34 | data | semmle.label | data |
+| C.java:33:23:33:26 | data | semmle.label | data |
+| C.java:38:17:38:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:43:25:43:28 | data | semmle.label | data |
+| C.java:46:3:46:4 | jr | semmle.label | jr |
+| C.java:51:17:51:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:53:3:53:3 | r | semmle.label | r |
+| C.java:54:3:54:3 | r | semmle.label | r |
+| C.java:55:3:55:3 | r | semmle.label | r |
+| C.java:60:18:60:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:61:30:61:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | semmle.label | new ByteArrayInputStream(...) : ByteArrayInputStream |
+| C.java:61:55:61:59 | bytes : byte[] | semmle.label | bytes : byte[] |
+| C.java:63:3:63:14 | hessianInput | semmle.label | hessianInput |
+| C.java:64:3:64:14 | hessianInput | semmle.label | hessianInput |
+| C.java:69:18:69:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:70:30:70:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | semmle.label | new ByteArrayInputStream(...) : ByteArrayInputStream |
+| C.java:70:55:70:59 | bytes : byte[] | semmle.label | bytes : byte[] |
+| C.java:72:3:72:14 | hessianInput | semmle.label | hessianInput |
+| C.java:73:3:73:14 | hessianInput | semmle.label | hessianInput |
+| C.java:79:26:79:71 | new StringReader(...) | semmle.label | new StringReader(...) |
+| C.java:79:43:79:70 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:84:27:84:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:85:29:85:68 | new ByteArrayInputStream(...) : ByteArrayInputStream | semmle.label | new ByteArrayInputStream(...) : ByteArrayInputStream |
+| C.java:85:54:85:67 | serializedData : byte[] | semmle.label | serializedData : byte[] |
+| C.java:87:3:87:13 | burlapInput | semmle.label | burlapInput |
+| C.java:91:3:91:14 | burlapInput1 | semmle.label | burlapInput1 |
| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | semmle.label | entityStream : InputStream |
| TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | semmle.label | new ObjectInputStream(...) |
| TestMessageBodyReader.java:22:40:22:51 | entityStream : InputStream | semmle.label | entityStream : InputStream |
@@ -141,4 +206,24 @@ nodes
| B.java:15:12:15:28 | parse(...) | B.java:12:31:12:51 | getInputStream(...) : InputStream | B.java:15:23:15:27 | bytes | Unsafe deserialization of $@. | B.java:12:31:12:51 | getInputStream(...) | user input |
| B.java:23:12:23:30 | parseObject(...) | B.java:19:31:19:51 | getInputStream(...) : InputStream | B.java:23:29:23:29 | s | Unsafe deserialization of $@. | B.java:19:31:19:51 | getInputStream(...) | user input |
| B.java:31:12:31:24 | parse(...) | B.java:27:31:27:51 | getInputStream(...) : InputStream | B.java:31:23:31:23 | s | Unsafe deserialization of $@. | B.java:27:31:27:51 | getInputStream(...) | user input |
+| C.java:24:3:24:17 | load(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:24:13:24:16 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:25:3:25:23 | loadStream(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:25:19:25:22 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:26:3:26:43 | loadStreamOfType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:26:25:26:28 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:27:3:27:35 | loadType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:27:17:27:20 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:30:3:30:23 | load(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:30:19:30:22 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:31:3:31:29 | loadStream(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:31:25:31:28 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:32:3:32:49 | loadStreamOfType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:32:31:32:34 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:33:3:33:41 | loadType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:33:23:33:26 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:43:3:43:29 | jsonToJava(...) | C.java:38:17:38:44 | getParameter(...) : String | C.java:43:25:43:28 | data | Unsafe deserialization of $@. | C.java:38:17:38:44 | getParameter(...) | user input |
+| C.java:46:3:46:17 | readObject(...) | C.java:38:17:38:44 | getParameter(...) : String | C.java:46:3:46:4 | jr | Unsafe deserialization of $@. | C.java:38:17:38:44 | getParameter(...) | user input |
+| C.java:53:3:53:10 | read(...) | C.java:51:17:51:44 | getParameter(...) : String | C.java:53:3:53:3 | r | Unsafe deserialization of $@. | C.java:51:17:51:44 | getParameter(...) | user input |
+| C.java:54:3:54:22 | read(...) | C.java:51:17:51:44 | getParameter(...) : String | C.java:54:3:54:3 | r | Unsafe deserialization of $@. | C.java:51:17:51:44 | getParameter(...) | user input |
+| C.java:55:3:55:36 | read(...) | C.java:51:17:51:44 | getParameter(...) : String | C.java:55:3:55:3 | r | Unsafe deserialization of $@. | C.java:51:17:51:44 | getParameter(...) | user input |
+| C.java:63:3:63:27 | readObject(...) | C.java:60:18:60:45 | getParameter(...) : String | C.java:63:3:63:14 | hessianInput | Unsafe deserialization of $@. | C.java:60:18:60:45 | getParameter(...) | user input |
+| C.java:64:3:64:39 | readObject(...) | C.java:60:18:60:45 | getParameter(...) : String | C.java:64:3:64:14 | hessianInput | Unsafe deserialization of $@. | C.java:60:18:60:45 | getParameter(...) | user input |
+| C.java:72:3:72:27 | readObject(...) | C.java:69:18:69:45 | getParameter(...) : String | C.java:72:3:72:14 | hessianInput | Unsafe deserialization of $@. | C.java:69:18:69:45 | getParameter(...) | user input |
+| C.java:73:3:73:39 | readObject(...) | C.java:69:18:69:45 | getParameter(...) : String | C.java:73:3:73:14 | hessianInput | Unsafe deserialization of $@. | C.java:69:18:69:45 | getParameter(...) | user input |
+| C.java:79:3:79:72 | unmarshal(...) | C.java:79:43:79:70 | getParameter(...) : String | C.java:79:26:79:71 | new StringReader(...) | Unsafe deserialization of $@. | C.java:79:43:79:70 | getParameter(...) | user input |
+| C.java:87:3:87:26 | readObject(...) | C.java:84:27:84:54 | getParameter(...) : String | C.java:87:3:87:13 | burlapInput | Unsafe deserialization of $@. | C.java:84:27:84:54 | getParameter(...) | user input |
+| C.java:91:3:91:27 | readObject(...) | C.java:84:27:84:54 | getParameter(...) : String | C.java:91:3:91:14 | burlapInput1 | Unsafe deserialization of $@. | C.java:84:27:84:54 | getParameter(...) | user input |
| TestMessageBodyReader.java:22:18:22:65 | readObject(...) | TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | Unsafe deserialization of $@. | TestMessageBodyReader.java:20:55:20:78 | entityStream | user input |
diff --git a/java/ql/test/query-tests/security/CWE-502/options b/java/ql/test/query-tests/security/CWE-502/options
index 6df0c9374c2..ebf1581cc8a 100644
--- a/java/ql/test/query-tests/security/CWE-502/options
+++ b/java/ql/test/query-tests/security/CWE-502/options
@@ -1 +1 @@
-//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74
+//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74:${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/jyaml-1.3:${testdir}/../../../stubs/json-io-4.10.0:${testdir}/../../../stubs/yamlbeans-1.09:${testdir}/../../../stubs/hessian-4.0.38:${testdir}/../../../stubs/castor-1.4.1
diff --git a/java/ql/test/query-tests/security/CWE-918/ApacheHttpSSRF.java b/java/ql/test/query-tests/security/CWE-918/ApacheHttpSSRF.java
new file mode 100644
index 00000000000..a3f476ccfec
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-918/ApacheHttpSSRF.java
@@ -0,0 +1,64 @@
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.client.methods.HttpOptions;
+import org.apache.http.client.methods.HttpTrace;
+import org.apache.http.client.methods.HttpPatch;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.message.BasicHttpRequest;
+import org.apache.http.message.BasicHttpEntityEnclosingRequest;
+import org.apache.http.message.BasicRequestLine;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class ApacheHttpSSRF extends HttpServlet {
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ try {
+
+ String sink = request.getParameter("uri");
+ URI uri = new URI(sink);
+
+ HttpGet httpGet = new HttpGet(uri); // $ SSRF
+ HttpGet httpGet2 = new HttpGet();
+ httpGet2.setURI(uri); // $ SSRF
+
+ new HttpHead(uri); // $ SSRF
+ new HttpPost(uri); // $ SSRF
+ new HttpPut(uri); // $ SSRF
+ new HttpDelete(uri); // $ SSRF
+ new HttpOptions(uri); // $ SSRF
+ new HttpTrace(uri); // $ SSRF
+ new HttpPatch(uri); // $ SSRF
+
+ new BasicHttpRequest(new BasicRequestLine("GET", uri.toString(), null)); // $ SSRF
+ new BasicHttpRequest("GET", uri.toString()); // $ SSRF
+ new BasicHttpRequest("GET", uri.toString(), null); // $ SSRF
+
+ new BasicHttpEntityEnclosingRequest(new BasicRequestLine("GET", uri.toString(), null)); // $ SSRF
+ new BasicHttpEntityEnclosingRequest("GET", uri.toString()); // $ SSRF
+ new BasicHttpEntityEnclosingRequest("GET", uri.toString(), null); // $ SSRF
+
+ RequestBuilder.get(uri); // $ SSRF
+ RequestBuilder.post(uri); // $ SSRF
+ RequestBuilder.put(uri); // $ SSRF
+ RequestBuilder.delete(uri); // $ SSRF
+ RequestBuilder.options(uri); // $ SSRF
+ RequestBuilder.head(uri); // $ SSRF
+ RequestBuilder.trace(uri); // $ SSRF
+ RequestBuilder.patch(uri); // $ SSRF
+ RequestBuilder.get("").setUri(uri); // $ SSRF
+
+ } catch (Exception e) {
+ // TODO: handle exception
+ }
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-918/JakartaWsSSRF.java b/java/ql/test/query-tests/security/CWE-918/JakartaWsSSRF.java
new file mode 100644
index 00000000000..ced25365211
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-918/JakartaWsSSRF.java
@@ -0,0 +1,18 @@
+import jakarta.ws.rs.client.*;
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class JakartaWsSSRF extends HttpServlet {
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ Client client = ClientBuilder.newClient();
+ String url = request.getParameter("url");
+ client.target(url); // $ SSRF
+ }
+
+}
diff --git a/java/ql/test/query-tests/security/CWE-918/JavaNetHttpSSRF.java b/java/ql/test/query-tests/security/CWE-918/JavaNetHttpSSRF.java
new file mode 100644
index 00000000000..7cc5578ebf3
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-918/JavaNetHttpSSRF.java
@@ -0,0 +1,45 @@
+import java.io.IOException;
+import java.net.Proxy;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.Proxy.Type;
+import java.io.InputStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class JavaNetHttpSSRF extends HttpServlet {
+ private static final String VALID_URI = "http://lgtm.com";
+ private HttpClient client = HttpClient.newHttpClient();
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ try {
+
+ String sink = request.getParameter("uri");
+ URI uri = new URI(sink);
+ URI uri2 = new URI("http", sink, "fragement");
+ URL url1 = new URL(sink);
+
+ URLConnection c1 = url1.openConnection(); // $ SSRF
+ SocketAddress sa = new SocketAddress() {
+ };
+ URLConnection c2 = url1.openConnection(new Proxy(Type.HTTP, sa)); // $ SSRF
+ InputStream c3 = url1.openStream(); // $ SSRF
+
+ // java.net.http
+ HttpClient client = HttpClient.newHttpClient();
+ HttpRequest request2 = HttpRequest.newBuilder().uri(uri2).build(); // $ SSRF
+ HttpRequest request3 = HttpRequest.newBuilder(uri).build(); // $ SSRF
+
+ } catch (Exception e) {
+ // TODO: handle exception
+ }
+ }
+}
diff --git a/java/ql/test/experimental/query-tests/security/CWE-918/JaxWsSSRF.java b/java/ql/test/query-tests/security/CWE-918/JaxWsSSRF.java
similarity index 68%
rename from java/ql/test/experimental/query-tests/security/CWE-918/JaxWsSSRF.java
rename to java/ql/test/query-tests/security/CWE-918/JaxWsSSRF.java
index cb774b8c44a..da650e2de6c 100644
--- a/java/ql/test/experimental/query-tests/security/CWE-918/JaxWsSSRF.java
+++ b/java/ql/test/query-tests/security/CWE-918/JaxWsSSRF.java
@@ -1,13 +1,6 @@
import javax.ws.rs.client.*;
import java.io.IOException;
-import java.net.URI;
-import java.net.*;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.Proxy.Type;
-import java.io.InputStream;
-import org.apache.http.client.methods.HttpGet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
@@ -19,7 +12,7 @@ public class JaxWsSSRF extends HttpServlet {
throws ServletException, IOException {
Client client = ClientBuilder.newClient();
String url = request.getParameter("url");
- client.target(url);
+ client.target(url); // $ SSRF
}
}
diff --git a/java/ql/test/query-tests/security/CWE-918/RequestForgery.expected b/java/ql/test/query-tests/security/CWE-918/RequestForgery.expected
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/java/ql/test/query-tests/security/CWE-918/RequestForgery.ql b/java/ql/test/query-tests/security/CWE-918/RequestForgery.ql
new file mode 100644
index 00000000000..d7e481ce618
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-918/RequestForgery.ql
@@ -0,0 +1,18 @@
+import java
+import semmle.code.java.security.RequestForgeryConfig
+import TestUtilities.InlineExpectationsTest
+
+class HasFlowTest extends InlineExpectationsTest {
+ HasFlowTest() { this = "HasFlowTest" }
+
+ override string getARelevantTag() { result = "SSRF" }
+
+ override predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "SSRF" and
+ exists(RequestForgeryConfiguration conf, DataFlow::Node sink | conf.hasFlowTo(sink) |
+ sink.getLocation() = location and
+ element = sink.toString() and
+ value = ""
+ )
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-918/SanitizationTests.java b/java/ql/test/query-tests/security/CWE-918/SanitizationTests.java
new file mode 100644
index 00000000000..9a65374024c
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-918/SanitizationTests.java
@@ -0,0 +1,123 @@
+import java.io.IOException;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class SanitizationTests extends HttpServlet {
+ private static final String VALID_URI = "http://lgtm.com";
+ private HttpClient client = HttpClient.newHttpClient();
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ try {
+
+ URI uri = new URI(request.getParameter("uri"));
+ // BAD: a request parameter is incorporated without validation into a Http
+ // request
+ HttpRequest r = HttpRequest.newBuilder(uri).build(); // $ SSRF
+ client.send(r, null);
+
+ // GOOD: sanitisation by concatenation with a prefix that prevents targeting an arbitrary host.
+ // We test a few different ways of sanitisation: via string conctentation (perhaps nested),
+ // via a stringbuilder (for which we consider appends done in the constructor, chained onto
+ // the constructor and applied in subsequent statements) and via String.format.
+ String safeUri3 = "https://example.com/" + request.getParameter("uri3");
+ HttpRequest r3 = HttpRequest.newBuilder(new URI(safeUri3)).build();
+ client.send(r3, null);
+
+ String safeUri4 = "https://example.com/" + ("someprefix" + request.getParameter("uri4"));
+ HttpRequest r4 = HttpRequest.newBuilder(new URI(safeUri4)).build();
+ client.send(r4, null);
+
+ StringBuilder safeUri5 = new StringBuilder();
+ safeUri5.append("https://example.com/").append(request.getParameter("uri5"));
+ HttpRequest r5 = HttpRequest.newBuilder(new URI(safeUri5.toString())).build();
+ client.send(r5, null);
+
+ StringBuilder safeUri5a = new StringBuilder("https://example.com/");
+ safeUri5a.append(request.getParameter("uri5a"));
+ HttpRequest r5a = HttpRequest.newBuilder(new URI(safeUri5a.toString())).build();
+ client.send(r5a, null);
+
+ StringBuilder safeUri5b = (new StringBuilder("https://example.com/")).append("dir/");
+ safeUri5b.append(request.getParameter("uri5b"));
+ HttpRequest r5b = HttpRequest.newBuilder(new URI(safeUri5b.toString())).build();
+ client.send(r5b, null);
+
+ StringBuilder safeUri5c = (new StringBuilder("prefix")).append("https://example.com/dir/");
+ safeUri5c.append(request.getParameter("uri5c"));
+ HttpRequest r5c = HttpRequest.newBuilder(new URI(safeUri5c.toString())).build();
+ client.send(r5c, null);
+
+ String safeUri6 = String.format("https://example.com/%s", request.getParameter("uri6"));
+ HttpRequest r6 = HttpRequest.newBuilder(new URI(safeUri6)).build();
+ client.send(r6, null);
+
+ String safeUri7 = String.format("%s/%s", "https://example.com", request.getParameter("uri7"));
+ HttpRequest r7 = HttpRequest.newBuilder(new URI(safeUri7)).build();
+ client.send(r7, null);
+
+ String safeUri8 = String.format("%s%s", "https://example.com/", request.getParameter("uri8"));
+ HttpRequest r8 = HttpRequest.newBuilder(new URI(safeUri8)).build();
+ client.send(r8, null);
+
+ String safeUri9 = String.format("http://%s", "myserver.com") + "/" + request.getParameter("uri9");
+ HttpRequest r9 = HttpRequest.newBuilder(new URI(safeUri9)).build();
+ client.send(r9, null);
+
+ // BAD: cases where a string that would sanitise is used, but occurs in the wrong
+ // place to sanitise user input:
+ String unsafeUri3 = request.getParameter("baduri3") + "https://example.com/";
+ HttpRequest unsafer3 = HttpRequest.newBuilder(new URI(unsafeUri3)).build(); // $ SSRF
+ client.send(unsafer3, null);
+
+ String unsafeUri4 = ("someprefix" + request.getParameter("baduri4")) + "https://example.com/";
+ HttpRequest unsafer4 = HttpRequest.newBuilder(new URI(unsafeUri4)).build(); // $ SSRF
+ client.send(unsafer4, null);
+
+ StringBuilder unsafeUri5 = new StringBuilder();
+ unsafeUri5.append(request.getParameter("baduri5")).append("https://example.com/");
+ HttpRequest unsafer5 = HttpRequest.newBuilder(new URI(unsafeUri5.toString())).build(); // $ SSRF
+ client.send(unsafer5, null);
+
+ StringBuilder unafeUri5a = new StringBuilder(request.getParameter("uri5a"));
+ unafeUri5a.append("https://example.com/");
+ HttpRequest unsafer5a = HttpRequest.newBuilder(new URI(unafeUri5a.toString())).build(); // $ SSRF
+ client.send(unsafer5a, null);
+
+ StringBuilder unsafeUri5b = (new StringBuilder(request.getParameter("uri5b"))).append("dir/");
+ unsafeUri5b.append("https://example.com/");
+ HttpRequest unsafer5b = HttpRequest.newBuilder(new URI(unsafeUri5b.toString())).build(); // $ SSRF
+ client.send(unsafer5b, null);
+
+ StringBuilder unsafeUri5c = (new StringBuilder("https")).append(request.getParameter("uri5c"));
+ unsafeUri5c.append("://example.com/dir/");
+ HttpRequest unsafer5c = HttpRequest.newBuilder(new URI(unsafeUri5c.toString())).build(); // $ SSRF
+ client.send(unsafer5c, null);
+
+ String unsafeUri6 = String.format("%shttps://example.com/", request.getParameter("baduri6"));
+ HttpRequest unsafer6 = HttpRequest.newBuilder(new URI(unsafeUri6)).build(); // $ SSRF
+ client.send(unsafer6, null);
+
+ String unsafeUri7 = String.format("%s/%s", request.getParameter("baduri7"), "https://example.com");
+ HttpRequest unsafer7 = HttpRequest.newBuilder(new URI(unsafeUri7)).build(); // $ SSRF
+ client.send(unsafer7, null);
+
+ String unsafeUri8 = String.format("%s%s", request.getParameter("baduri8"), "https://example.com/");
+ HttpRequest unsafer8 = HttpRequest.newBuilder(new URI(unsafeUri8)).build(); // $ SSRF
+ client.send(unsafer8, null);
+
+ String unsafeUri9 = request.getParameter("baduri9") + "/" + String.format("http://%s", "myserver.com");
+ HttpRequest unsafer9 = HttpRequest.newBuilder(new URI(unsafeUri9)).build(); // $ SSRF
+ client.send(unsafer9, null);
+
+ } catch (Exception e) {
+ // TODO: handle exception
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/ql/test/query-tests/security/CWE-918/SpringSSRF.java b/java/ql/test/query-tests/security/CWE-918/SpringSSRF.java
new file mode 100644
index 00000000000..6af4829ba02
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-918/SpringSSRF.java
@@ -0,0 +1,70 @@
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpStatus;
+import java.net.URI;
+import org.springframework.http.HttpMethod;
+import java.io.IOException;
+import java.net.URI;
+import java.net.*;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.Proxy.Type;
+import java.io.InputStream;
+
+import org.apache.http.client.methods.HttpGet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class SpringSSRF extends HttpServlet {
+
+ protected void doGet(HttpServletRequest request2, HttpServletResponse response2)
+ throws ServletException, IOException {
+ String fooResourceUrl = request2.getParameter("uri");;
+ RestTemplate restTemplate = new RestTemplate();
+ HttpEntity request = new HttpEntity<>(new String("bar"));
+ try {
+ restTemplate.getForEntity(fooResourceUrl + "/1", String.class); // $ SSRF
+ restTemplate.exchange(fooResourceUrl, HttpMethod.POST, request, String.class); // $ SSRF
+ restTemplate.execute(fooResourceUrl, HttpMethod.POST, null, null, "test"); // $ SSRF
+ restTemplate.getForObject(fooResourceUrl, String.class, "test"); // $ SSRF
+ restTemplate.patchForObject(fooResourceUrl, new String("object"), String.class, "hi"); // $ SSRF
+ restTemplate.postForEntity(new URI(fooResourceUrl), new String("object"), String.class); // $ SSRF
+ restTemplate.postForLocation(fooResourceUrl, new String("object")); // $ SSRF
+ restTemplate.postForObject(fooResourceUrl, new String("object"), String.class); // $ SSRF
+ restTemplate.put(fooResourceUrl, new String("object")); // $ SSRF
+ restTemplate.delete(fooResourceUrl); // $ SSRF
+ restTemplate.headForHeaders(fooResourceUrl); // $ SSRF
+ restTemplate.optionsForAllow(fooResourceUrl); // $ SSRF
+ {
+ String body = new String("body");
+ URI uri = new URI(fooResourceUrl);
+ RequestEntity requestEntity =
+ RequestEntity.post(uri).body(body); // $ SSRF
+ ResponseEntity response = restTemplate.exchange(requestEntity, String.class);
+ RequestEntity.get(uri); // $ SSRF
+ RequestEntity.put(uri); // $ SSRF
+ RequestEntity.delete(uri); // $ SSRF
+ RequestEntity.options(uri); // $ SSRF
+ RequestEntity.patch(uri); // $ SSRF
+ RequestEntity.head(uri); // $ SSRF
+ RequestEntity.method(null, uri); // $ SSRF
+ }
+ {
+ URI uri = new URI(fooResourceUrl);
+ MultiValueMap headers = null;
+ java.lang.reflect.Type type = null;
+ new RequestEntity(null, uri); // $ SSRF
+ new RequestEntity(headers, null, uri); // $ SSRF
+ new RequestEntity("body", null, uri); // $ SSRF
+ new RequestEntity("body", headers, null, uri); // $ SSRF
+ new RequestEntity("body", null, uri, type); // $ SSRF
+ new RequestEntity("body", headers, null, uri, type); // $ SSRF
+ }
+ } catch (org.springframework.web.client.RestClientException | java.net.URISyntaxException e) {}
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-918/options b/java/ql/test/query-tests/security/CWE-918/options
new file mode 100644
index 00000000000..79224345b48
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-918/options
@@ -0,0 +1 @@
+//semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/javax-ws-rs-api-2.1.1:${testdir}/../../../stubs/javax-ws-rs-api-3.0.0:${testdir}/../../../stubs/apache-http-4.4.13/:${testdir}/../../../stubs/servlet-api-2.4/
diff --git a/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/tuple/ImmutablePair.java b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/tuple/ImmutablePair.java
new file mode 100644
index 00000000000..ee4cacd78a6
--- /dev/null
+++ b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/tuple/ImmutablePair.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang3.tuple;
+
+import java.util.Map;
+
+/**
+ * An immutable pair consisting of two {@code Object} elements.
+ *
+ * Although the implementation is immutable, there is no restriction on the objects
+ * that may be stored. If mutable objects are stored in the pair, then the pair
+ * itself effectively becomes mutable. The class is also {@code final}, so a subclass
+ * can not add undesirable behavior.
+ *
+ * #ThreadSafe# if both paired objects are thread-safe
+ *
+ * @param the left element type
+ * @param the right element type
+ *
+ * @since 3.0
+ */
+public final class ImmutablePair extends Pair {
+
+ /**
+ * An empty array.
+ *
+ * Consider using {@link #emptyArray()} to avoid generics warnings.
+ *
+ *
+ * @since 3.10.
+ */
+ public static final ImmutablePair, ?>[] EMPTY_ARRAY = null;
+
+ /**
+ * An immutable pair of nulls.
+ */
+ // This is not defined with generics to avoid warnings in call sites.
+ @SuppressWarnings("rawtypes")
+ private static final ImmutablePair NULL = null;
+
+ /** Serialization version */
+ private static final long serialVersionUID = 4954918890077093841L;
+
+ /**
+ * Returns the empty array singleton that can be assigned without compiler warning.
+ *
+ * @param the left element type
+ * @param the right element type
+ * @return the empty array singleton that can be assigned without compiler warning.
+ *
+ * @since 3.10.
+ */
+ @SuppressWarnings("unchecked")
+ public static ImmutablePair[] emptyArray() {
+ return null;
+ }
+
+ /**
+ * Creates an immutable pair of two objects inferring the generic types.
+ *
+ * This factory allows the pair to be created using inference to
+ * obtain the generic types.
+ *
+ * @param the left element type
+ * @param the right element type
+ * @param left the left element, may be null
+ * @return a pair formed from the two parameters, not null
+ * @since 3.11
+ */
+ public static Pair left(final L left) {
+ return null;
+ }
+
+ /**
+ * Returns an immutable pair of nulls.
+ *
+ * @param the left element of this pair. Value is {@code null}.
+ * @param the right element of this pair. Value is {@code null}.
+ * @return an immutable pair of nulls.
+ * @since 3.6
+ */
+ public static ImmutablePair nullPair() {
+ return null;
+ }
+
+ /**
+ * Creates an immutable pair of two objects inferring the generic types.
+ *
+ * This factory allows the pair to be created using inference to
+ * obtain the generic types.
+ *
+ * @param the left element type
+ * @param the right element type
+ * @param left the left element, may be null
+ * @param right the right element, may be null
+ * @return a pair formed from the two parameters, not null
+ */
+ public static ImmutablePair of(final L left, final R right) {
+ return null;
+ }
+
+ /**
+ * Creates an immutable pair from an existing pair.
+ *
+ * This factory allows the pair to be created using inference to
+ * obtain the generic types.
+ *
+ * @param the left element type
+ * @param the right element type
+ * @param pair the existing pair.
+ * @return a pair formed from the two parameters, not null
+ * @since 3.10
+ */
+ public static ImmutablePair of(final Map.Entry pair) {
+ return null;
+ }
+
+ /**
+ * Creates an immutable pair of two objects inferring the generic types.
+ *
+ * This factory allows the pair to be created using inference to
+ * obtain the generic types.
+ *
+ * @param the left element type
+ * @param the right element type
+ * @param right the right element, may be null
+ * @return a pair formed from the two parameters, not null
+ * @since 3.11
+ */
+ public static Pair right(final R right) {
+ return null;
+ }
+
+ /** Left object */
+ public final L left;
+
+ /** Right object */
+ public final R right;
+
+ /**
+ * Create a new pair instance.
+ *
+ * @param left the left value, may be null
+ * @param right the right value, may be null
+ */
+ public ImmutablePair(final L left, final R right) {
+ this.left = null;
+ this.right = null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public L getLeft() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public R getRight() {
+ return null;
+ }
+
+ /**
+ * Throws {@code UnsupportedOperationException}.
+ *
+ * This pair is immutable, so this operation is not supported.
+ *
+ * @param value the value to set
+ * @return never
+ * @throws UnsupportedOperationException as this operation is not supported
+ */
+ @Override
+ public R setValue(final R value) {
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/tuple/ImmutableTriple.java b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/tuple/ImmutableTriple.java
new file mode 100644
index 00000000000..846fcbd9052
--- /dev/null
+++ b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/tuple/ImmutableTriple.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang3.tuple;
+
+/**
+ * An immutable triple consisting of three {@code Object} elements.
+ *
+ * Although the implementation is immutable, there is no restriction on the objects
+ * that may be stored. If mutable objects are stored in the triple, then the triple
+ * itself effectively becomes mutable. The class is also {@code final}, so a subclass
+ * can not add undesirable behavior.
+ *
+ * #ThreadSafe# if all three objects are thread-safe
+ *
+ * @param the left element type
+ * @param the middle element type
+ * @param the right element type
+ *
+ * @since 3.2
+ */
+public final class ImmutableTriple extends Triple {
+
+ /**
+ * An empty array.
+ *
+ * Consider using {@link #emptyArray()} to avoid generics warnings.
+ *
+ *
+ * @since 3.10.
+ */
+ public static final ImmutableTriple, ?, ?>[] EMPTY_ARRAY = null;
+
+ /**
+ * Returns the empty array singleton that can be assigned without compiler warning.
+ *
+ * @param the left element type
+ * @param the middle element type
+ * @param the right element type
+ * @return the empty array singleton that can be assigned without compiler warning.
+ *
+ * @since 3.10.
+ */
+ @SuppressWarnings("unchecked")
+ public static ImmutableTriple[] emptyArray() {
+ return null;
+ }
+
+ /**
+ * Returns an immutable triple of nulls.
+ *
+ * @param the left element of this triple. Value is {@code null}.
+ * @param the middle element of this triple. Value is {@code null}.
+ * @param the right element of this triple. Value is {@code null}.
+ * @return an immutable triple of nulls.
+ * @since 3.6
+ */
+ public static ImmutableTriple nullTriple() {
+ return null;
+ }
+
+ /**
+ * Obtains an immutable triple of three objects inferring the generic types.
+ *
+ * This factory allows the triple to be created using inference to
+ * obtain the generic types.
+ *
+ * @param the left element type
+ * @param the middle element type
+ * @param the right element type
+ * @param left the left element, may be null
+ * @param middle the middle element, may be null
+ * @param right the right element, may be null
+ * @return a triple formed from the three parameters, not null
+ */
+ public static ImmutableTriple of(final L left, final M middle, final R right) {
+ return null;
+ }
+ /** Left object */
+ public final L left;
+ /** Middle object */
+ public final M middle;
+
+ /** Right object */
+ public final R right;
+
+ /**
+ * Create a new triple instance.
+ *
+ * @param left the left value, may be null
+ * @param middle the middle value, may be null
+ * @param right the right value, may be null
+ */
+ public ImmutableTriple(final L left, final M middle, final R right) {
+ this.left = null;
+ this.middle = null;
+ this.right = null;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public L getLeft() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public M getMiddle() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public R getRight() {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/tuple/MutablePair.java b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/tuple/MutablePair.java
new file mode 100644
index 00000000000..5826a2145fc
--- /dev/null
+++ b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/tuple/MutablePair.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang3.tuple;
+
+import java.util.Map;
+
+/**
+ * A mutable pair consisting of two {@code Object} elements.
+ *
+ * Not #ThreadSafe#
+ *
+ * @param the left element type
+ * @param the right element type
+ *
+ * @since 3.0
+ */
+public class MutablePair extends Pair {
+
+ /**
+ * An empty array.
+ *
+ * Consider using {@link #emptyArray()} to avoid generics warnings.
+ *
+ *
+ * @since 3.10.
+ */
+ public static final MutablePair, ?>[] EMPTY_ARRAY = null;
+
+ /**
+ * Returns the empty array singleton that can be assigned without compiler warning.
+ *
+ * @param the left element type
+ * @param the right element type
+ * @return the empty array singleton that can be assigned without compiler warning.
+ *
+ * @since 3.10.
+ */
+ @SuppressWarnings("unchecked")
+ public static MutablePair[] emptyArray() {
+ return null;
+ }
+
+ /**
+ * Creates a mutable pair of two objects inferring the generic types.
+ *
+ * This factory allows the pair to be created using inference to
+ * obtain the generic types.
+ *
+ * @param the left element type
+ * @param the right element type
+ * @param left the left element, may be null
+ * @param right the right element, may be null
+ * @return a pair formed from the two parameters, not null
+ */
+ public static MutablePair of(final L left, final R right) {
+ return null;
+ }
+
+ /**
+ * Creates a mutable pair from an existing pair.
+ *
+ * This factory allows the pair to be created using inference to
+ * obtain the generic types.
+ *
+ * @param the left element type
+ * @param the right element type
+ * @param pair the existing pair.
+ * @return a pair formed from the two parameters, not null
+ */
+ public static MutablePair of(final Map.Entry pair) {
+ return null;
+ }
+
+ /** Left object */
+ public L left;
+
+ /** Right object */
+ public R right;
+
+ /**
+ * Create a new pair instance of two nulls.
+ */
+ public MutablePair() {
+ }
+
+ /**
+ * Create a new pair instance.
+ *
+ * @param left the left value, may be null
+ * @param right the right value, may be null
+ */
+ public MutablePair(final L left, final R right) {
+ this.left = null;
+ this.right = null;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public L getLeft() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public R getRight() {
+ return null;
+ }
+
+ /**
+ * Sets the left element of the pair.
+ *
+ * @param left the new value of the left element, may be null
+ */
+ public void setLeft(final L left) {
+
+ }
+
+ /**
+ * Sets the right element of the pair.
+ *
+ * @param right the new value of the right element, may be null
+ */
+ public void setRight(final R right) {
+
+ }
+
+ /**
+ * Sets the {@code Map.Entry} value.
+ * This sets the right element of the pair.
+ *
+ * @param value the right value to set, not null
+ * @return the old value for the right element
+ */
+ @Override
+ public R setValue(final R value) {
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/tuple/MutableTriple.java b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/tuple/MutableTriple.java
new file mode 100644
index 00000000000..dc489c44293
--- /dev/null
+++ b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/tuple/MutableTriple.java
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang3.tuple;
+
+/**
+ * A mutable triple consisting of three {@code Object} elements.
+ *
+ * Not #ThreadSafe#
+ *
+ * @param the left element type
+ * @param the middle element type
+ * @param the right element type
+ *
+ * @since 3.2
+ */
+public class MutableTriple extends Triple