mirror of
https://github.com/github/codeql.git
synced 2026-04-18 05:24:01 +02:00
Merge branch 'main' into sourcesinkdoc
This commit is contained in:
1
.github/codeql/codeql-config.yml
vendored
1
.github/codeql/codeql-config.yml
vendored
@@ -8,5 +8,6 @@ paths-ignore:
|
||||
- '/java/'
|
||||
- '/python/'
|
||||
- '/javascript/ql/test'
|
||||
- '/javascript/ql/integration-tests'
|
||||
- '/javascript/extractor/tests'
|
||||
- '/rust/ql'
|
||||
|
||||
7
.github/workflows/codeql-analysis.yml
vendored
7
.github/workflows/codeql-analysis.yml
vendored
@@ -18,6 +18,10 @@ on:
|
||||
|
||||
jobs:
|
||||
CodeQL-Build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: ['actions', 'csharp']
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -38,9 +42,8 @@ jobs:
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@main
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
with:
|
||||
languages: csharp
|
||||
languages: ${{ matrix.language }}
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
The following example, correctly creates a temporary directory and extracts the contents of the artifact there before calling `cmd.sh`.
|
||||
|
||||
```yaml
|
||||
name: Insecure Workflow
|
||||
name: Secure Workflow
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
The following example, correctly creates a temporary directory and extracts the contents of the artifact there before calling `cmd.sh`.
|
||||
|
||||
```yaml
|
||||
name: Insecure Workflow
|
||||
name: Secure Workflow
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
|
||||
@@ -8,3 +8,4 @@ extractor: actions
|
||||
defaultSuiteFile: codeql-suites/actions-code-scanning.qls
|
||||
dependencies:
|
||||
codeql/actions-all: ${workspace}
|
||||
codeql/suite-helpers: ${workspace}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
import csharp
|
||||
import Dispose
|
||||
import semmle.code.csharp.frameworks.System
|
||||
import semmle.code.csharp.frameworks.system.threading.Tasks
|
||||
import semmle.code.csharp.commons.Disposal
|
||||
|
||||
private class ReturnNode extends DataFlow::ExprNode {
|
||||
@@ -24,15 +25,27 @@ private class ReturnNode extends DataFlow::ExprNode {
|
||||
}
|
||||
}
|
||||
|
||||
private class Task extends Type {
|
||||
Task() {
|
||||
this instanceof SystemThreadingTasksTaskClass or
|
||||
this instanceof SystemThreadingTasksTaskTClass
|
||||
}
|
||||
}
|
||||
|
||||
module DisposeCallOnLocalIDisposableConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) {
|
||||
node.asExpr() =
|
||||
any(LocalScopeDisposableCreation disposable |
|
||||
// Only care about library types - user types often have spurious IDisposable declarations
|
||||
disposable.getType().fromLibrary() and
|
||||
// WebControls are usually disposed automatically
|
||||
not disposable.getType() instanceof WebControl
|
||||
)
|
||||
exists(LocalScopeDisposableCreation disposable, Type t |
|
||||
node.asExpr() = disposable and
|
||||
t = disposable.getType()
|
||||
|
|
||||
// Only care about library types - user types often have spurious IDisposable declarations
|
||||
t.fromLibrary() and
|
||||
// WebControls are usually disposed automatically
|
||||
not t instanceof WebControl and
|
||||
// It is typically not nessesary to dispose tasks
|
||||
// https://devblogs.microsoft.com/pfxteam/do-i-need-to-dispose-of-tasks/
|
||||
not t instanceof Task
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
|
||||
@@ -119,9 +119,14 @@ class ConstantMatchingCondition extends ConstantCondition {
|
||||
}
|
||||
|
||||
override predicate isWhiteListed() {
|
||||
exists(SwitchExpr se, int i |
|
||||
se.getCase(i).getPattern() = this.(DiscardExpr) and
|
||||
exists(Switch se, Case c, int i |
|
||||
c = se.getCase(i) and
|
||||
c.getPattern() = this.(DiscardExpr)
|
||||
|
|
||||
i > 0
|
||||
or
|
||||
i = 0 and
|
||||
exists(Expr cond | c.getCondition() = cond and not isConstantCondition(cond, true))
|
||||
)
|
||||
or
|
||||
this = any(PositionalPatternExpr ppe).getPattern(_)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cs/local-not-disposed` query no longer flags un-disposed tasks as this is often not needed (explained [here](https://devblogs.microsoft.com/pfxteam/do-i-need-to-dispose-of-tasks/)).
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Increase query precision for `cs/constant-condition` and allow the use of discards in switch/case statements and also take the condition (if any) into account.
|
||||
@@ -8,3 +8,4 @@
|
||||
- cs/self-assignment
|
||||
- cs/inefficient-containskey
|
||||
- cs/call-to-object-tostring
|
||||
- cs/local-not-disposed
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Xml;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
class Test
|
||||
{
|
||||
@@ -86,6 +87,13 @@ class Test
|
||||
using (XmlReader.Create(source ?? new StringReader("xml"), null))
|
||||
;
|
||||
|
||||
// GOOD: Flagging these generates too much noise and there is a general
|
||||
// acceptance that Tasks are not disposed.
|
||||
// https://devblogs.microsoft.com/pfxteam/do-i-need-to-dispose-of-tasks/
|
||||
Task t = new Task(() => { });
|
||||
t.Start();
|
||||
t.Wait();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
| NoDisposeCallOnLocalIDisposable.cs:50:19:50:38 | object creation of type Timer | Disposable 'Timer' is created but not disposed. |
|
||||
| NoDisposeCallOnLocalIDisposable.cs:51:18:51:73 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. |
|
||||
| NoDisposeCallOnLocalIDisposable.cs:52:9:52:64 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. |
|
||||
| NoDisposeCallOnLocalIDisposable.cs:74:25:74:71 | call to method Create | Disposable 'XmlReader' is created but not disposed. |
|
||||
| NoDisposeCallOnLocalIDisposable.cs:74:42:74:64 | object creation of type StringReader | Disposable 'StringReader' is created but not disposed. |
|
||||
| NoDisposeCallOnLocalIDisposable.cs:79:38:79:67 | object creation of type StreamWriter | Disposable 'StreamWriter' is created but not disposed. |
|
||||
| NoDisposeCallOnLocalIDisposable.cs:51:19:51:38 | object creation of type Timer | Disposable 'Timer' is created but not disposed. |
|
||||
| NoDisposeCallOnLocalIDisposable.cs:52:18:52:73 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. |
|
||||
| NoDisposeCallOnLocalIDisposable.cs:53:9:53:64 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. |
|
||||
| NoDisposeCallOnLocalIDisposable.cs:75:25:75:71 | call to method Create | Disposable 'XmlReader' is created but not disposed. |
|
||||
| NoDisposeCallOnLocalIDisposable.cs:75:42:75:64 | object creation of type StringReader | Disposable 'StringReader' is created but not disposed. |
|
||||
| NoDisposeCallOnLocalIDisposable.cs:80:38:80:67 | object creation of type StreamWriter | Disposable 'StreamWriter' is created but not disposed. |
|
||||
| NoDisposeCallOnLocalIDisposableBad.cs:8:22:8:56 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. |
|
||||
|
||||
@@ -35,18 +35,18 @@ class ConstantNullness
|
||||
{
|
||||
void M1(int i)
|
||||
{
|
||||
var j = ((string)null)?.Length; // BAD
|
||||
var s = ((int?)i)?.ToString(); // BAD
|
||||
var j = ((string)null)?.Length; // $ Alert
|
||||
var s = ((int?)i)?.ToString(); // $ Alert
|
||||
var k = s?.Length; // GOOD
|
||||
k = s?.ToLower()?.Length; // GOOD
|
||||
}
|
||||
|
||||
void M2(int i)
|
||||
{
|
||||
var j = (int?)null ?? 0; // BAD
|
||||
var s = "" ?? "a"; // BAD
|
||||
j = (int?)i ?? 1; // BAD
|
||||
s = ""?.CommaJoinWith(s); // BAD
|
||||
var j = (int?)null ?? 0; // $ Alert
|
||||
var s = "" ?? "a"; // $ Alert
|
||||
j = (int?)i ?? 1; // $ Alert
|
||||
s = ""?.CommaJoinWith(s); // $ Alert
|
||||
s = s ?? ""; // GOOD
|
||||
s = (i == 0 ? s : null) ?? s; // GOOD
|
||||
var k = (i == 0 ? s : null)?.Length; // GOOD
|
||||
@@ -59,9 +59,9 @@ class ConstantMatching
|
||||
{
|
||||
switch (1 + 2)
|
||||
{
|
||||
case 2: // BAD
|
||||
case 2: // $ Alert
|
||||
break;
|
||||
case 3: // BAD
|
||||
case 3: // $ Alert
|
||||
break;
|
||||
case int _: // GOOD
|
||||
break;
|
||||
@@ -72,7 +72,7 @@ class ConstantMatching
|
||||
{
|
||||
switch ((object)s)
|
||||
{
|
||||
case int _: // BAD
|
||||
case int _: // $ Alert
|
||||
break;
|
||||
case "": // GOOD
|
||||
break;
|
||||
@@ -92,7 +92,7 @@ class ConstantMatching
|
||||
{
|
||||
return o switch
|
||||
{
|
||||
_ => o.ToString() // BAD
|
||||
_ => o.ToString() // $ Alert
|
||||
};
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ class ConstantMatching
|
||||
return;
|
||||
if (!b2)
|
||||
return;
|
||||
if (b1 && b2) // BAD
|
||||
if (b1 && b2) // $ Alert
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -124,6 +124,35 @@ class ConstantMatching
|
||||
_ => "" // GOOD
|
||||
};
|
||||
}
|
||||
|
||||
string M8(int i)
|
||||
{
|
||||
return i switch
|
||||
{
|
||||
_ when i % 2 == 0 => "even", // GOOD
|
||||
_ => "odd" // GOOD
|
||||
};
|
||||
}
|
||||
|
||||
string M9(int i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case var _: // $ Alert
|
||||
return "even";
|
||||
}
|
||||
}
|
||||
|
||||
string M10(int i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case var _ when i % 2 == 0: // GOOD
|
||||
return "even";
|
||||
case var _: // GOOD
|
||||
return "odd";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Assertions
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
| ConstantCondition.cs:95:13:95:13 | _ | Pattern always matches. |
|
||||
| ConstantCondition.cs:114:13:114:14 | access to parameter b1 | Condition always evaluates to 'true'. |
|
||||
| ConstantCondition.cs:114:19:114:20 | access to parameter b2 | Condition always evaluates to 'true'. |
|
||||
| ConstantConditionBad.cs:5:16:5:20 | ... > ... | Condition always evaluates to 'false'. |
|
||||
| ConstantCondition.cs:141:22:141:22 | _ | Pattern always matches. |
|
||||
| ConstantConditionalExpressionCondition.cs:11:22:11:34 | ... == ... | Condition always evaluates to 'true'. |
|
||||
| ConstantConditionalExpressionCondition.cs:12:21:12:25 | false | Condition always evaluates to 'false'. |
|
||||
| ConstantConditionalExpressionCondition.cs:13:21:13:30 | ... == ... | Condition always evaluates to 'true'. |
|
||||
@@ -19,6 +19,7 @@
|
||||
| ConstantIfCondition.cs:11:17:11:29 | ... == ... | Condition always evaluates to 'true'. |
|
||||
| ConstantIfCondition.cs:14:17:14:21 | false | Condition always evaluates to 'false'. |
|
||||
| ConstantIfCondition.cs:17:17:17:26 | ... == ... | Condition always evaluates to 'true'. |
|
||||
| ConstantIfCondition.cs:30:20:30:24 | ... > ... | Condition always evaluates to 'false'. |
|
||||
| ConstantIsNullOrEmpty.cs:10:21:10:54 | call to method IsNullOrEmpty | Condition always evaluates to 'false'. |
|
||||
| ConstantIsNullOrEmpty.cs:46:21:46:46 | call to method IsNullOrEmpty | Condition always evaluates to 'true'. |
|
||||
| ConstantIsNullOrEmpty.cs:50:21:50:44 | call to method IsNullOrEmpty | Condition always evaluates to 'true'. |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Bad Practices/Control-Flow/ConstantCondition.ql
|
||||
query: Bad Practices/Control-Flow/ConstantCondition.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
class Bad
|
||||
{
|
||||
public int Max(int a, int b)
|
||||
{
|
||||
return a > a ? a : b;
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,10 @@ namespace ConstantConditionalExpression
|
||||
|
||||
public void Foo()
|
||||
{
|
||||
int i = (ZERO == 1 - 1) ? 0 : 1; // BAD
|
||||
int j = false ? 0 : 1; // BAD
|
||||
int k = " " == " " ? 0 : 1; // BAD
|
||||
int l = (" "[0] == ' ') ? 0 : 1; // BAD: but not flagged
|
||||
int i = (ZERO == 1 - 1) ? 0 : 1; // $ Alert
|
||||
int j = false ? 0 : 1; // $ Alert
|
||||
int k = " " == " " ? 0 : 1; // $ Alert
|
||||
int l = (" "[0] == ' ') ? 0 : 1; // Missing Alert
|
||||
int m = Bar() == 0 ? 0 : 1; // GOOD
|
||||
}
|
||||
|
||||
@@ -21,5 +21,4 @@ namespace ConstantConditionalExpression
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ namespace ConstantForCondition
|
||||
{
|
||||
public void M()
|
||||
{
|
||||
for (int i = 0; false; i++) // GOOD
|
||||
for (int i = 0; false; i++) // $ Alert
|
||||
;
|
||||
for (int i = 0; 0 == 1; i++) // BAD
|
||||
for (int i = 0; 0 == 1; i++) // $ Alert
|
||||
;
|
||||
for (; ; ) // GOOD
|
||||
;
|
||||
|
||||
@@ -8,23 +8,28 @@ namespace ConstantIfCondition
|
||||
|
||||
public void Foo()
|
||||
{
|
||||
if (ZERO == 1 - 1)
|
||||
{ // BAD
|
||||
if (ZERO == 1 - 1) // $ Alert
|
||||
{
|
||||
}
|
||||
if (false)
|
||||
{ // BAD
|
||||
if (false) // $ Alert
|
||||
{
|
||||
}
|
||||
if (" " == " ")
|
||||
{ // BAD
|
||||
if (" " == " ") // $ Alert
|
||||
{
|
||||
}
|
||||
if (" "[0] == ' ')
|
||||
{ // BAD: but not flagged
|
||||
if (" "[0] == ' ') // Missing Alert
|
||||
{
|
||||
}
|
||||
if (Bar() == 0)
|
||||
{ // GOOD
|
||||
if (Bar() == 0) // GOOD
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public int Max(int a, int b)
|
||||
{
|
||||
return a > a ? a : b; // $ Alert
|
||||
}
|
||||
|
||||
public int Bar()
|
||||
{
|
||||
return ZERO;
|
||||
|
||||
@@ -7,17 +7,17 @@ namespace ConstantIsNullOrEmpty
|
||||
static void Main(string[] args)
|
||||
{
|
||||
{
|
||||
if (string.IsNullOrEmpty(nameof(args))) // bad: always false
|
||||
if (string.IsNullOrEmpty(nameof(args))) // $ Alert
|
||||
{
|
||||
}
|
||||
|
||||
string? x = null;
|
||||
if (string.IsNullOrEmpty(x)) // would be nice... bad: always true
|
||||
if (string.IsNullOrEmpty(x)) // Missing Alert (always true)
|
||||
{
|
||||
}
|
||||
|
||||
string y = "";
|
||||
if (string.IsNullOrEmpty(y)) // would be nice... bad: always true
|
||||
if (string.IsNullOrEmpty(y)) // Missing Alert (always true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -28,12 +28,12 @@ namespace ConstantIsNullOrEmpty
|
||||
}
|
||||
|
||||
string z = " ";
|
||||
if (string.IsNullOrEmpty(z)) // would be nice... bad: always false
|
||||
if (string.IsNullOrEmpty(z)) // Missing Alert (always false)
|
||||
{
|
||||
}
|
||||
|
||||
string a = "a";
|
||||
if (string.IsNullOrEmpty(a)) // would be nice... bad: always false
|
||||
if (string.IsNullOrEmpty(a)) // Missing Alert (always false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -43,18 +43,18 @@ namespace ConstantIsNullOrEmpty
|
||||
{
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(null)) // bad: always true
|
||||
if (string.IsNullOrEmpty(null)) // $ Alert
|
||||
{
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty("")) // bad: always true
|
||||
if (string.IsNullOrEmpty("")) // $ Alert
|
||||
{
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(" ")) // bad: always false
|
||||
if (string.IsNullOrEmpty(" ")) // $ Alert
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace ConstantNullCoalescingLeftHandOperand
|
||||
|
||||
public void Foo()
|
||||
{
|
||||
object i = NULL_OBJECT ?? ""; // BAD
|
||||
object j = null ?? ""; // BAD
|
||||
object i = NULL_OBJECT ?? ""; // $ Alert
|
||||
object j = null ?? ""; // $ Alert
|
||||
object k = Bar() ?? ""; // GOOD
|
||||
}
|
||||
|
||||
|
||||
@@ -9,28 +9,28 @@ namespace ConstantWhileCondition
|
||||
|
||||
public void Foo()
|
||||
{
|
||||
while (ZERO == 1 - 1)
|
||||
{ // BAD
|
||||
while (ZERO == 1 - 1) // $ Alert
|
||||
{
|
||||
break;
|
||||
}
|
||||
while (false)
|
||||
{ // GOOD
|
||||
while (false) // $ Alert
|
||||
{
|
||||
break;
|
||||
}
|
||||
while (true)
|
||||
{ // GOOD
|
||||
while (true) // GOOD
|
||||
{
|
||||
break;
|
||||
}
|
||||
while (" " == " ")
|
||||
{ // BAD
|
||||
while (" " == " ") // $ Alert
|
||||
{
|
||||
break;
|
||||
}
|
||||
while (" "[0] == ' ')
|
||||
{ // BAD: but not flagged
|
||||
while (" "[0] == ' ') // Missing Alert
|
||||
{
|
||||
break;
|
||||
}
|
||||
while (Bar() == 0)
|
||||
{ // GOOD
|
||||
while (Bar() == 0) // GOOD
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ predicate isCloseSink(DataFlow::Node sink, DataFlow::CallNode closeCall) {
|
||||
// where the function is called on the sink
|
||||
closeCall.getReceiver() = sink and
|
||||
// and check that it is not dominated by a call to `os.File.Sync`.
|
||||
// TODO: fix this logic when `closeCall` is in a defer statement.
|
||||
not exists(IR::Instruction syncInstr, DataFlow::Node syncReceiver, DataFlow::CallNode syncCall |
|
||||
// match the instruction corresponding to an `os.File.Sync` call with the predecessor
|
||||
syncCall.asInstruction() = syncInstr and
|
||||
|
||||
@@ -1,48 +1,52 @@
|
||||
#select
|
||||
| tests.go:9:8:9:8 | f | tests.go:31:5:31:78 | ... := ...[0] | tests.go:9:8:9:8 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:31:15:31:78 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:9:8:9:8 | f | tests.go:45:5:45:76 | ... := ...[0] | tests.go:9:8:9:8 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:45:15:45:76 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:14:3:14:3 | f | tests.go:31:5:31:78 | ... := ...[0] | tests.go:14:3:14:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:31:15:31:78 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:14:3:14:3 | f | tests.go:45:5:45:76 | ... := ...[0] | tests.go:14:3:14:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:45:15:45:76 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:56:3:56:3 | f | tests.go:54:5:54:78 | ... := ...[0] | tests.go:56:3:56:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:54:15:54:78 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:68:3:68:3 | f | tests.go:66:5:66:76 | ... := ...[0] | tests.go:68:3:68:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:66:15:66:76 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:110:9:110:9 | f | tests.go:108:5:108:78 | ... := ...[0] | tests.go:110:9:110:9 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:108:15:108:78 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:129:3:129:3 | f | tests.go:125:5:125:78 | ... := ...[0] | tests.go:129:3:129:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:125:15:125:78 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:10:8:10:8 | f | tests.go:32:5:32:78 | ... := ...[0] | tests.go:10:8:10:8 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:32:15:32:78 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:10:8:10:8 | f | tests.go:46:5:46:76 | ... := ...[0] | tests.go:10:8:10:8 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:46:15:46:76 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:15:3:15:3 | f | tests.go:32:5:32:78 | ... := ...[0] | tests.go:15:3:15:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:32:15:32:78 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:15:3:15:3 | f | tests.go:46:5:46:76 | ... := ...[0] | tests.go:15:3:15:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:46:15:46:76 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:57:3:57:3 | f | tests.go:55:5:55:78 | ... := ...[0] | tests.go:57:3:57:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:55:15:55:78 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:69:3:69:3 | f | tests.go:67:5:67:76 | ... := ...[0] | tests.go:69:3:69:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:67:15:67:76 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:111:9:111:9 | f | tests.go:109:5:109:78 | ... := ...[0] | tests.go:111:9:111:9 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:109:15:109:78 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:130:3:130:3 | f | tests.go:126:5:126:78 | ... := ...[0] | tests.go:130:3:130:3 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:126:15:126:78 | call to OpenFile | call to OpenFile |
|
||||
| tests.go:151:8:151:8 | f | tests.go:147:2:147:74 | ... := ...[0] | tests.go:151:8:151:8 | f | File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly. | tests.go:147:12:147:74 | call to OpenFile | call to OpenFile |
|
||||
edges
|
||||
| tests.go:8:24:8:24 | definition of f | tests.go:9:8:9:8 | f | provenance | |
|
||||
| tests.go:12:32:12:32 | definition of f | tests.go:13:13:15:2 | capture variable f | provenance | |
|
||||
| tests.go:13:13:15:2 | capture variable f | tests.go:14:3:14:3 | f | provenance | |
|
||||
| tests.go:31:5:31:78 | ... := ...[0] | tests.go:32:21:32:21 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:31:5:31:78 | ... := ...[0] | tests.go:33:29:33:29 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:32:21:32:21 | f | tests.go:8:24:8:24 | definition of f | provenance | |
|
||||
| tests.go:33:29:33:29 | f | tests.go:12:32:12:32 | definition of f | provenance | |
|
||||
| tests.go:45:5:45:76 | ... := ...[0] | tests.go:46:21:46:21 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:45:5:45:76 | ... := ...[0] | tests.go:47:29:47:29 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:46:21:46:21 | f | tests.go:8:24:8:24 | definition of f | provenance | |
|
||||
| tests.go:47:29:47:29 | f | tests.go:12:32:12:32 | definition of f | provenance | |
|
||||
| tests.go:54:5:54:78 | ... := ...[0] | tests.go:56:3:56:3 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:66:5:66:76 | ... := ...[0] | tests.go:68:3:68:3 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:108:5:108:78 | ... := ...[0] | tests.go:110:9:110:9 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:125:5:125:78 | ... := ...[0] | tests.go:129:3:129:3 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:9:24:9:24 | definition of f | tests.go:10:8:10:8 | f | provenance | |
|
||||
| tests.go:13:32:13:32 | definition of f | tests.go:14:13:16:2 | capture variable f | provenance | |
|
||||
| tests.go:14:13:16:2 | capture variable f | tests.go:15:3:15:3 | f | provenance | |
|
||||
| tests.go:32:5:32:78 | ... := ...[0] | tests.go:33:21:33:21 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:32:5:32:78 | ... := ...[0] | tests.go:34:29:34:29 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:33:21:33:21 | f | tests.go:9:24:9:24 | definition of f | provenance | |
|
||||
| tests.go:34:29:34:29 | f | tests.go:13:32:13:32 | definition of f | provenance | |
|
||||
| tests.go:46:5:46:76 | ... := ...[0] | tests.go:47:21:47:21 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:46:5:46:76 | ... := ...[0] | tests.go:48:29:48:29 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:47:21:47:21 | f | tests.go:9:24:9:24 | definition of f | provenance | |
|
||||
| tests.go:48:29:48:29 | f | tests.go:13:32:13:32 | definition of f | provenance | |
|
||||
| tests.go:55:5:55:78 | ... := ...[0] | tests.go:57:3:57:3 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:67:5:67:76 | ... := ...[0] | tests.go:69:3:69:3 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:109:5:109:78 | ... := ...[0] | tests.go:111:9:111:9 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:126:5:126:78 | ... := ...[0] | tests.go:130:3:130:3 | f | provenance | Src:MaD:1 |
|
||||
| tests.go:147:2:147:74 | ... := ...[0] | tests.go:151:8:151:8 | f | provenance | Src:MaD:1 |
|
||||
models
|
||||
| 1 | Source: os; ; false; OpenFile; ; ; ReturnValue[0]; file; manual |
|
||||
nodes
|
||||
| tests.go:8:24:8:24 | definition of f | semmle.label | definition of f |
|
||||
| tests.go:9:8:9:8 | f | semmle.label | f |
|
||||
| tests.go:12:32:12:32 | definition of f | semmle.label | definition of f |
|
||||
| tests.go:13:13:15:2 | capture variable f | semmle.label | capture variable f |
|
||||
| tests.go:14:3:14:3 | f | semmle.label | f |
|
||||
| tests.go:31:5:31:78 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| tests.go:32:21:32:21 | f | semmle.label | f |
|
||||
| tests.go:33:29:33:29 | f | semmle.label | f |
|
||||
| tests.go:45:5:45:76 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| tests.go:46:21:46:21 | f | semmle.label | f |
|
||||
| tests.go:47:29:47:29 | f | semmle.label | f |
|
||||
| tests.go:54:5:54:78 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| tests.go:56:3:56:3 | f | semmle.label | f |
|
||||
| tests.go:66:5:66:76 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| tests.go:68:3:68:3 | f | semmle.label | f |
|
||||
| tests.go:108:5:108:78 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| tests.go:110:9:110:9 | f | semmle.label | f |
|
||||
| tests.go:125:5:125:78 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| tests.go:129:3:129:3 | f | semmle.label | f |
|
||||
| tests.go:9:24:9:24 | definition of f | semmle.label | definition of f |
|
||||
| tests.go:10:8:10:8 | f | semmle.label | f |
|
||||
| tests.go:13:32:13:32 | definition of f | semmle.label | definition of f |
|
||||
| tests.go:14:13:16:2 | capture variable f | semmle.label | capture variable f |
|
||||
| tests.go:15:3:15:3 | f | semmle.label | f |
|
||||
| tests.go:32:5:32:78 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| tests.go:33:21:33:21 | f | semmle.label | f |
|
||||
| tests.go:34:29:34:29 | f | semmle.label | f |
|
||||
| tests.go:46:5:46:76 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| tests.go:47:21:47:21 | f | semmle.label | f |
|
||||
| tests.go:48:29:48:29 | f | semmle.label | f |
|
||||
| tests.go:55:5:55:78 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| tests.go:57:3:57:3 | f | semmle.label | f |
|
||||
| tests.go:67:5:67:76 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| tests.go:69:3:69:3 | f | semmle.label | f |
|
||||
| tests.go:109:5:109:78 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| tests.go:111:9:111:9 | f | semmle.label | f |
|
||||
| tests.go:126:5:126:78 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| tests.go:130:3:130:3 | f | semmle.label | f |
|
||||
| tests.go:147:2:147:74 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| tests.go:151:8:151:8 | f | semmle.label | f |
|
||||
subpaths
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
query: InconsistentCode/UnhandledCloseWritableHandle.ql
|
||||
postprocess: utils/test/PrettyPrintModels.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func closeFileDeferred(f *os.File) {
|
||||
defer f.Close() // NOT OK, if `f` is writable
|
||||
defer f.Close() // $ Alert=w Alert=rw
|
||||
}
|
||||
|
||||
func closeFileDeferredIndirect(f *os.File) {
|
||||
var cont = func() {
|
||||
f.Close() // NOT OK, if `f` is writable
|
||||
f.Close() // $ Alert=w Alert=rw
|
||||
}
|
||||
|
||||
defer cont()
|
||||
@@ -28,7 +29,7 @@ func closeFileDeferredIndirectReturn(f *os.File) {
|
||||
|
||||
func deferredCalls() {
|
||||
// open file for writing
|
||||
if f, err := os.OpenFile("foo.txt", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666); err != nil {
|
||||
if f, err := os.OpenFile("foo.txt", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666); err != nil { // $ Source=w
|
||||
closeFileDeferred(f) // NOT OK
|
||||
closeFileDeferredIndirect(f) // NOT OK
|
||||
closeFileDeferredIndirectReturn(f) // OK - the error is not discarded at the call to Close (though it is discarded later)
|
||||
@@ -42,7 +43,7 @@ func deferredCalls() {
|
||||
}
|
||||
|
||||
// open file for reading and writing
|
||||
if f, err := os.OpenFile("foo.txt", os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666); err != nil {
|
||||
if f, err := os.OpenFile("foo.txt", os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666); err != nil { // $ Source=rw
|
||||
closeFileDeferred(f) // NOT OK
|
||||
closeFileDeferredIndirect(f) // NOT OK
|
||||
closeFileDeferredIndirectReturn(f) // OK - the error is not discarded at the call to Close (though it is discarded later)
|
||||
@@ -51,9 +52,9 @@ func deferredCalls() {
|
||||
|
||||
func notDeferred() {
|
||||
// open file for writing
|
||||
if f, err := os.OpenFile("foo.txt", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666); err != nil {
|
||||
if f, err := os.OpenFile("foo.txt", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666); err != nil { // $ Source
|
||||
// the handle is write-only and we don't check if `Close` succeeds
|
||||
f.Close() // NOT OK
|
||||
f.Close() // $ Alert
|
||||
}
|
||||
|
||||
// open file for reading
|
||||
@@ -63,9 +64,9 @@ func notDeferred() {
|
||||
}
|
||||
|
||||
// open file for reading and writing
|
||||
if f, err := os.OpenFile("foo.txt", os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666); err != nil {
|
||||
if f, err := os.OpenFile("foo.txt", os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666); err != nil { // $ Source
|
||||
// the handle is read-write and we don't check if `Close` succeeds
|
||||
f.Close() // NOT OK
|
||||
f.Close() // $ Alert
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,9 +106,9 @@ func deferredCloseWithSync() {
|
||||
|
||||
func deferredCloseWithSyncEarlyReturn(n int) {
|
||||
// open file for writing
|
||||
if f, err := os.OpenFile("foo.txt", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666); err != nil {
|
||||
if f, err := os.OpenFile("foo.txt", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666); err != nil { // $ Source
|
||||
// a call to `Close` is deferred
|
||||
defer f.Close() // NOT OK
|
||||
defer f.Close() // $ Alert
|
||||
|
||||
if n > 100 {
|
||||
return
|
||||
@@ -122,10 +123,36 @@ func deferredCloseWithSyncEarlyReturn(n int) {
|
||||
|
||||
func unhandledSync() {
|
||||
// open file for writing
|
||||
if f, err := os.OpenFile("foo.txt", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666); err != nil {
|
||||
if f, err := os.OpenFile("foo.txt", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666); err != nil { // $ Source
|
||||
// we have a call to `Sync` which precedes the call to `Close`, but there is no check
|
||||
// to see if `Sync` may have failed
|
||||
f.Sync()
|
||||
f.Close() // NOT OK
|
||||
f.Close() // $ Alert
|
||||
}
|
||||
}
|
||||
|
||||
func returnedSync() error {
|
||||
// open file for writing
|
||||
f, err := os.OpenFile("foo.txt", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
// we have a call to `Sync` which precedes the call to `Close`, but there is no check
|
||||
// to see if `Sync` may have failed
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
return f.Sync()
|
||||
}
|
||||
|
||||
func copyFile(destFile string, mode os.FileMode, src io.Reader) error {
|
||||
f, err := os.OpenFile(destFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode) // $ Source
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close() // $ SPURIOUS: Alert
|
||||
|
||||
_, err = io.Copy(f, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.Sync()
|
||||
}
|
||||
|
||||
6
java/ql/integration-tests/java/maven-download-failure/.gitattributes
vendored
Normal file
6
java/ql/integration-tests/java/maven-download-failure/.gitattributes
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"markdownMessage": "Java analysis used build tool Maven to pick a JDK version and/or to recommend external dependencies.",
|
||||
"severity": "unknown",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
"id": "java/autobuilder/buildless/using-build-tool-advice",
|
||||
"name": "Java analysis used build tool Maven to pick a JDK version and/or to recommend external dependencies"
|
||||
},
|
||||
"visibility": {
|
||||
"cliSummaryTable": true,
|
||||
"statusPage": false,
|
||||
"telemetry": true
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Java analysis used the system default JDK.",
|
||||
"severity": "unknown",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
"id": "java/autobuilder/buildless/jdk-system-default",
|
||||
"name": "Java analysis used the system default JDK"
|
||||
},
|
||||
"visibility": {
|
||||
"cliSummaryTable": true,
|
||||
"statusPage": false,
|
||||
"telemetry": true
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Java analysis with build-mode 'none' completed.",
|
||||
"severity": "unknown",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
"id": "java/autobuilder/buildless/complete",
|
||||
"name": "Java analysis with build-mode 'none' completed"
|
||||
},
|
||||
"visibility": {
|
||||
"cliSummaryTable": true,
|
||||
"statusPage": false,
|
||||
"telemetry": true
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Java was extracted with build-mode set to 'none'. This means that all Java source in the working directory will be scanned, with build tools such as Maven and Gradle only contributing information about external dependencies.",
|
||||
"severity": "note",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
"id": "java/autobuilder/buildless/mode-active",
|
||||
"name": "Java was extracted with build-mode set to 'none'"
|
||||
},
|
||||
"visibility": {
|
||||
"cliSummaryTable": true,
|
||||
"statusPage": true,
|
||||
"telemetry": true
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Reading the dependency graph from build files provided 2 classpath entries",
|
||||
"severity": "unknown",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
"id": "java/autobuilder/buildless/depgraph-provided-by-maven",
|
||||
"name": "Java analysis extracted precise dependency graph information from tool Maven"
|
||||
},
|
||||
"visibility": {
|
||||
"cliSummaryTable": true,
|
||||
"statusPage": false,
|
||||
"telemetry": true
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "The maven-enforcer-plugin recommended a specific Maven version be used. Trying to download it failed; extraction will continue, but retrieving dependency information from Maven may fail if the system default version is incompatible with project build scripts. Consider checking if a firewall configuration or similar is preventing downloading the required version.",
|
||||
"severity": "note",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
"id": "java/autobuilder/buildless/maven-download-failed",
|
||||
"name": "Java analysis failed to download a Maven version recommended by the maven-enforcer-plugin"
|
||||
},
|
||||
"visibility": {
|
||||
"cliSummaryTable": true,
|
||||
"statusPage": true,
|
||||
"telemetry": true
|
||||
}
|
||||
}
|
||||
10
java/ql/integration-tests/java/maven-download-failure/mvn
Executable file
10
java/ql/integration-tests/java/maven-download-failure/mvn
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
>&2 echo "Running mvn wrapper script"
|
||||
|
||||
if [ "$1" == "dependency:copy" ]; then
|
||||
>&2 echo "Arguments ($@) look like a dependency:copy command; failing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
${REAL_MVN_PATH} "$@"
|
||||
1
java/ql/integration-tests/java/maven-download-failure/mvn.cmd
Executable file
1
java/ql/integration-tests/java/maven-download-failure/mvn.cmd
Executable file
@@ -0,0 +1 @@
|
||||
@bash mvn %*
|
||||
133
java/ql/integration-tests/java/maven-download-failure/pom.xml
Normal file
133
java/ql/integration-tests/java/maven-download-failure/pom.xml
Normal file
@@ -0,0 +1,133 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>maven-sample</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<name>maven-sample</name>
|
||||
<!-- FIXME change it to the project's website -->
|
||||
<url>http://www.example.com</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.7</maven.compiler.source>
|
||||
<maven.compiler.target>1.7</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<version>1.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>check-maven-version</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>java</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<mainClass>com.example.App</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.diffplug.spotless</groupId>
|
||||
<artifactId>spotless-maven-plugin</artifactId>
|
||||
<version>2.19.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<phase>compile</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<java>
|
||||
<licenseHeader>
|
||||
<content>/* FAIL ME */</content>
|
||||
</licenseHeader>
|
||||
</java>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce-maven</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireMavenVersion>
|
||||
<version>[3.1.1,)</version>
|
||||
</requireMavenVersion>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
|
||||
<plugins>
|
||||
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
</plugin>
|
||||
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.7.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,7 @@
|
||||
pom.xml
|
||||
src/main/java/com/example/App.java
|
||||
src/main/resources/my-app.properties
|
||||
src/main/resources/page.xml
|
||||
src/main/resources/struts.xml
|
||||
src/test/java/com/example/AppTest.java
|
||||
test-db/working/settings.xml
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.example;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* Hello world!
|
||||
*
|
||||
*/
|
||||
public class App
|
||||
{
|
||||
public static void main( String[] args )
|
||||
{
|
||||
System.out.println( "Hello World!" );
|
||||
String expectedVersion = System.getenv("EXPECT_MAVEN");
|
||||
Path mavenHome = Paths.get(System.getProperty("maven.home")).normalize();
|
||||
String observedVersion = mavenHome.getFileName().toString();
|
||||
if (expectedVersion != null && !expectedVersion.equals(observedVersion)) {
|
||||
System.err.println("Wrong maven version, expected '" + expectedVersion + "' but got '" + observedVersion + "'" + mavenHome);
|
||||
System.exit(1);
|
||||
}
|
||||
String commandMatcher = System.getenv("EXPECT_COMMAND_REGEX");
|
||||
String command = System.getProperty("sun.java.command");
|
||||
if (commandMatcher != null && !Pattern.matches(commandMatcher, command)) {
|
||||
System.err.println("Wrong command line, '" + command + "' does not match '" + commandMatcher + "'");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
version=1.0
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>A sample</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Hello world!</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<struts>
|
||||
This is a sample file
|
||||
</struts>
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.example;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit test for simple App.
|
||||
*/
|
||||
public class AppTest
|
||||
{
|
||||
/**
|
||||
* Rigorous Test :-)
|
||||
*/
|
||||
@Test
|
||||
public void shouldAnswerWithTrue()
|
||||
{
|
||||
assertTrue( true );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import os
|
||||
import os.path
|
||||
import shutil
|
||||
|
||||
def test(codeql, java, check_diagnostics):
|
||||
|
||||
# Avoid shutil resolving mvn to the wrapper script in the test dir:
|
||||
os.environ["NoDefaultCurrentDirectoryInExePath"] = "0"
|
||||
runenv = {
|
||||
"PATH": os.path.realpath(os.path.dirname(__file__)) + os.pathsep + os.getenv("PATH"),
|
||||
"REAL_MVN_PATH": shutil.which("mvn"),
|
||||
}
|
||||
del os.environ["NoDefaultCurrentDirectoryInExePath"]
|
||||
codeql.database.create(build_mode = "none", _env = runenv)
|
||||
5
java/ql/lib/change-notes/2025-03-03-maven-fixes.md
Normal file
5
java/ql/lib/change-notes/2025-03-03-maven-fixes.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Java build-mode `none` no longer fails when a required version of Maven cannot be downloaded, such as due to a firewall. It will now attempt to use the system version of Maven if present, or otherwise proceed without detailed dependency information.
|
||||
* Java build-mode `none` now correctly uses Maven dependency information on Windows platforms.
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Provides classes for working with Spring classes and interfaces from
|
||||
* `org.springframework.boot.*`.
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
/**
|
||||
* The class `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest`.
|
||||
*/
|
||||
class SpringEndpointRequest extends Class {
|
||||
SpringEndpointRequest() {
|
||||
this.hasQualifiedName("org.springframework.boot.actuate.autoconfigure.security.servlet",
|
||||
"EndpointRequest")
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to `EndpointRequest.toAnyEndpoint` method. */
|
||||
class SpringToAnyEndpointCall extends MethodCall {
|
||||
SpringToAnyEndpointCall() {
|
||||
this.getMethod().hasName("toAnyEndpoint") and
|
||||
this.getMethod().getDeclaringType() instanceof SpringEndpointRequest
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Provides classes for working with Spring classes and interfaces from
|
||||
* `org.springframework.security.*`.
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
/** The class `org.springframework.security.config.annotation.web.builders.HttpSecurity`. */
|
||||
class SpringHttpSecurity extends Class {
|
||||
SpringHttpSecurity() {
|
||||
this.hasQualifiedName("org.springframework.security.config.annotation.web.builders",
|
||||
"HttpSecurity")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The class
|
||||
* `org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer$AuthorizedUrl`
|
||||
* or the class
|
||||
* `org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer$AuthorizedUrl`.
|
||||
*/
|
||||
class SpringAuthorizedUrl extends Class {
|
||||
SpringAuthorizedUrl() {
|
||||
this.hasQualifiedName("org.springframework.security.config.annotation.web.configurers",
|
||||
[
|
||||
"ExpressionUrlAuthorizationConfigurer<HttpSecurity>$AuthorizedUrl<>",
|
||||
"AuthorizeHttpRequestsConfigurer<HttpSecurity>$AuthorizedUrl<>"
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The class `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`.
|
||||
*/
|
||||
class SpringAbstractRequestMatcherRegistry extends Class {
|
||||
SpringAbstractRequestMatcherRegistry() {
|
||||
this.hasQualifiedName("org.springframework.security.config.annotation.web",
|
||||
"AbstractRequestMatcherRegistry<AuthorizedUrl<>>")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `HttpSecurity.authorizeRequests` method.
|
||||
*
|
||||
* Note: this method is deprecated and scheduled for removal
|
||||
* in Spring Security 7.0.
|
||||
*/
|
||||
class SpringAuthorizeRequestsCall extends MethodCall {
|
||||
SpringAuthorizeRequestsCall() {
|
||||
this.getMethod().hasName("authorizeRequests") and
|
||||
this.getMethod().getDeclaringType() instanceof SpringHttpSecurity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `HttpSecurity.authorizeHttpRequests` method.
|
||||
*
|
||||
* Note: the no-argument version of this method is deprecated
|
||||
* and scheduled for removal in Spring Security 7.0.
|
||||
*/
|
||||
class SpringAuthorizeHttpRequestsCall extends MethodCall {
|
||||
SpringAuthorizeHttpRequestsCall() {
|
||||
this.getMethod().hasName("authorizeHttpRequests") and
|
||||
this.getMethod().getDeclaringType() instanceof SpringHttpSecurity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `HttpSecurity.requestMatcher` method.
|
||||
*
|
||||
* Note: this method was removed in Spring Security 6.0.
|
||||
* It was replaced by `securityMatcher`.
|
||||
*/
|
||||
class SpringRequestMatcherCall extends MethodCall {
|
||||
SpringRequestMatcherCall() {
|
||||
this.getMethod().hasName("requestMatcher") and
|
||||
this.getMethod().getDeclaringType() instanceof SpringHttpSecurity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `HttpSecurity.requestMatchers` method.
|
||||
*
|
||||
* Note: this method was removed in Spring Security 6.0.
|
||||
* It was replaced by `securityMatchers`.
|
||||
*/
|
||||
class SpringRequestMatchersCall extends MethodCall {
|
||||
SpringRequestMatchersCall() {
|
||||
this.getMethod().hasName("requestMatchers") and
|
||||
this.getMethod().getDeclaringType() instanceof SpringHttpSecurity
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to the `HttpSecurity.securityMatcher` method. */
|
||||
class SpringSecurityMatcherCall extends MethodCall {
|
||||
SpringSecurityMatcherCall() {
|
||||
this.getMethod().hasName("securityMatcher") and
|
||||
this.getMethod().getDeclaringType() instanceof SpringHttpSecurity
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to the `HttpSecurity.securityMatchers` method. */
|
||||
class SpringSecurityMatchersCall extends MethodCall {
|
||||
SpringSecurityMatchersCall() {
|
||||
this.getMethod().hasName("securityMatchers") and
|
||||
this.getMethod().getDeclaringType() instanceof SpringHttpSecurity
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to the `AuthorizedUrl.permitAll` method. */
|
||||
class SpringPermitAllCall extends MethodCall {
|
||||
SpringPermitAllCall() {
|
||||
this.getMethod().hasName("permitAll") and
|
||||
this.getMethod().getDeclaringType() instanceof SpringAuthorizedUrl
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to the `AbstractRequestMatcherRegistry.anyRequest` method. */
|
||||
class SpringAnyRequestCall extends MethodCall {
|
||||
SpringAnyRequestCall() {
|
||||
this.getMethod().hasName("anyRequest") and
|
||||
this.getMethod().getDeclaringType() instanceof SpringAbstractRequestMatcherRegistry
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/** Provides classes and predicates to reason about exposed actuators in Spring Boot. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.frameworks.spring.SpringSecurity
|
||||
private import semmle.code.java.frameworks.spring.SpringBoot
|
||||
|
||||
/**
|
||||
* A call to an `HttpSecurity` matcher method with argument
|
||||
* `EndpointRequest.toAnyEndpoint()`.
|
||||
*/
|
||||
private class HttpSecurityMatcherCall extends MethodCall {
|
||||
HttpSecurityMatcherCall() {
|
||||
(
|
||||
this instanceof SpringRequestMatcherCall or
|
||||
this instanceof SpringSecurityMatcherCall
|
||||
) and
|
||||
this.getArgument(0) instanceof SpringToAnyEndpointCall
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to an `HttpSecurity` matchers method with lambda
|
||||
* argument `EndpointRequest.toAnyEndpoint()`.
|
||||
*/
|
||||
private class HttpSecurityMatchersCall extends MethodCall {
|
||||
HttpSecurityMatchersCall() {
|
||||
(
|
||||
this instanceof SpringRequestMatchersCall or
|
||||
this instanceof SpringSecurityMatchersCall
|
||||
) and
|
||||
this.getArgument(0).(LambdaExpr).getExprBody() instanceof SpringToAnyEndpointCall
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to an `AbstractRequestMatcherRegistry.requestMatchers` method with
|
||||
* argument `EndpointRequest.toAnyEndpoint()`.
|
||||
*/
|
||||
private class RegistryRequestMatchersCall extends MethodCall {
|
||||
RegistryRequestMatchersCall() {
|
||||
this.getMethod().hasName("requestMatchers") and
|
||||
this.getMethod().getDeclaringType() instanceof SpringAbstractRequestMatcherRegistry and
|
||||
this.getAnArgument() instanceof SpringToAnyEndpointCall
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to an `HttpSecurity` method that authorizes requests. */
|
||||
private class AuthorizeCall extends MethodCall {
|
||||
AuthorizeCall() {
|
||||
this instanceof SpringAuthorizeRequestsCall or
|
||||
this instanceof SpringAuthorizeHttpRequestsCall
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `permitAllCall` is called on request(s) mapped to actuator endpoint(s). */
|
||||
predicate permitsSpringBootActuators(SpringPermitAllCall permitAllCall) {
|
||||
exists(AuthorizeCall authorizeCall |
|
||||
// .requestMatcher(EndpointRequest).authorizeRequests([...]).[...]
|
||||
authorizeCall.getQualifier() instanceof HttpSecurityMatcherCall
|
||||
or
|
||||
// .requestMatchers(matcher -> EndpointRequest).authorizeRequests([...]).[...]
|
||||
authorizeCall.getQualifier() instanceof HttpSecurityMatchersCall
|
||||
|
|
||||
// [...].authorizeRequests(r -> r.anyRequest().permitAll()) or
|
||||
// [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll())
|
||||
authorizeCall.getArgument(0).(LambdaExpr).getExprBody() = permitAllCall and
|
||||
(
|
||||
permitAllCall.getQualifier() instanceof SpringAnyRequestCall or
|
||||
permitAllCall.getQualifier() instanceof RegistryRequestMatchersCall
|
||||
)
|
||||
or
|
||||
// [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or
|
||||
// [...].authorizeRequests().anyRequest().permitAll()
|
||||
authorizeCall.getNumArgument() = 0 and
|
||||
exists(RegistryRequestMatchersCall registryRequestMatchersCall |
|
||||
registryRequestMatchersCall.getQualifier() = authorizeCall and
|
||||
permitAllCall.getQualifier() = registryRequestMatchersCall
|
||||
)
|
||||
or
|
||||
exists(SpringAnyRequestCall anyRequestCall |
|
||||
anyRequestCall.getQualifier() = authorizeCall and
|
||||
permitAllCall.getQualifier() = anyRequestCall
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(AuthorizeCall authorizeCall |
|
||||
// http.authorizeRequests([...]).[...]
|
||||
authorizeCall.getQualifier() instanceof VarAccess
|
||||
|
|
||||
// [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll())
|
||||
authorizeCall.getArgument(0).(LambdaExpr).getExprBody() = permitAllCall and
|
||||
permitAllCall.getQualifier() instanceof RegistryRequestMatchersCall
|
||||
or
|
||||
// [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or
|
||||
authorizeCall.getNumArgument() = 0 and
|
||||
exists(RegistryRequestMatchersCall registryRequestMatchersCall |
|
||||
registryRequestMatchersCall.getQualifier() = authorizeCall and
|
||||
permitAllCall.getQualifier() = registryRequestMatchersCall
|
||||
)
|
||||
or
|
||||
exists(Variable v, HttpSecurityMatcherCall matcherCall |
|
||||
// http.securityMatcher(EndpointRequest.toAnyEndpoint());
|
||||
// http.authorizeRequests([...].permitAll())
|
||||
v.getAnAccess() = authorizeCall.getQualifier() and
|
||||
v.getAnAccess() = matcherCall.getQualifier() and
|
||||
authorizeCall.getArgument(0).(LambdaExpr).getExprBody() = permitAllCall and
|
||||
permitAllCall.getQualifier() instanceof SpringAnyRequestCall
|
||||
)
|
||||
)
|
||||
}
|
||||
25
java/ql/src/Security/CWE/CWE-200/SpringBootActuators.java
Normal file
25
java/ql/src/Security/CWE/CWE-200/SpringBootActuators.java
Normal file
@@ -0,0 +1,25 @@
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class CustomSecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
// BAD: Unauthenticated access to Spring Boot actuator endpoints is allowed
|
||||
http.securityMatcher(EndpointRequest.toAnyEndpoint());
|
||||
http.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class CustomSecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
// GOOD: only users with ENDPOINT_ADMIN role are allowed to access the actuator endpoints
|
||||
http.securityMatcher(EndpointRequest.toAnyEndpoint());
|
||||
http.authorizeHttpRequests((requests) -> requests.anyRequest().hasRole("ENDPOINT_ADMIN"));
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
36
java/ql/src/Security/CWE/CWE-200/SpringBootActuators.qhelp
Normal file
36
java/ql/src/Security/CWE/CWE-200/SpringBootActuators.qhelp
Normal file
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Spring Boot includes features called actuators that let you monitor and interact with your
|
||||
web application. Exposing unprotected actuator endpoints can lead to information disclosure or
|
||||
even to remote code execution.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Since actuator endpoints may contain sensitive information, carefully consider when to expose them,
|
||||
and secure them as you would any sensitive URL. Actuators are secured by default when using Spring
|
||||
Security without a custom configuration. If you wish to define a custom security configuration,
|
||||
consider only allowing users with certain roles to access these endpoints.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>In the first example, the custom security configuration allows unauthenticated access to all
|
||||
actuator endpoints. This may lead to sensitive information disclosure and should be avoided.</p>
|
||||
|
||||
<p>In the second example, only users with <code>ENDPOINT_ADMIN</code> role are allowed to access
|
||||
the actuator endpoints.</p>
|
||||
|
||||
<sample src="SpringBootActuators.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
Spring Boot Reference Documentation:
|
||||
<a href="https://docs.spring.io/spring-boot/reference/actuator/endpoints.html">Endpoints</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
20
java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
Normal file
20
java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @name Exposed Spring Boot actuators
|
||||
* @description Exposing Spring Boot actuators may lead to information leak from the internal application,
|
||||
* or even to remote code execution.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @security-severity 6.5
|
||||
* @precision high
|
||||
* @id java/spring-boot-exposed-actuators
|
||||
* @tags security
|
||||
* external/cwe/cwe-200
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.frameworks.spring.SpringSecurity
|
||||
import semmle.code.java.security.SpringBootActuatorsQuery
|
||||
|
||||
from SpringPermitAllCall permitAllCall
|
||||
where permitsSpringBootActuators(permitAllCall)
|
||||
select permitAllCall, "Unauthenticated access to Spring Boot actuator is allowed."
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* The query `java/spring-boot-exposed-actuators` has been promoted from experimental to the main query pack. Its results will now appear by default, and the query itself will be removed from the [CodeQL Community Packs](https://github.com/GitHubSecurityLab/CodeQL-Community-Packs). This query was originally submitted as an experimental query [by @ggolawski](https://github.com/github/codeql/pull/2901).
|
||||
@@ -1,22 +0,0 @@
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class SpringBootActuators extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// BAD: Unauthenticated access to Spring Boot actuator endpoints is allowed
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) ->
|
||||
requests.anyRequest().permitAll());
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// GOOD: only users with ENDPOINT_ADMIN role are allowed to access the actuator endpoints
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) ->
|
||||
requests.anyRequest().hasRole("ENDPOINT_ADMIN"));
|
||||
http.httpBasic();
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Spring Boot includes a number of additional features called actuators that let you monitor
|
||||
and interact with your web application. Exposing unprotected actuator endpoints via JXM or HTTP
|
||||
can, however, lead to information disclosure or even to remote code execution vulnerability.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Since actuator endpoints may contain sensitive information, careful consideration should be
|
||||
given about when to expose them. You should take care to secure exposed HTTP endpoints in the same
|
||||
way that you would any other sensitive URL. If Spring Security is present, endpoints are secured by
|
||||
default using Spring Security’s content-negotiation strategy. If you wish to configure custom
|
||||
security for HTTP endpoints, for example, only allow users with a certain role to access them,
|
||||
Spring Boot provides some convenient <code>RequestMatcher</code> objects that can be used in
|
||||
combination with Spring Security.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>In the first example, the custom security configuration allows unauthenticated access to all
|
||||
actuator endpoints. This may lead to sensitive information disclosure and should be avoided.</p>
|
||||
<p>In the second example, only users with <code>ENDPOINT_ADMIN</code> role are allowed to access
|
||||
the actuator endpoints.</p>
|
||||
|
||||
<sample src="SpringBootActuators.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
Spring Boot documentation:
|
||||
<a href="https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html">Actuators</a>.
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.veracode.com/blog/research/exploiting-spring-boot-actuators">Exploiting Spring Boot Actuators</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* @name Exposed Spring Boot actuators
|
||||
* @description Exposing Spring Boot actuators may lead to internal application's information leak
|
||||
* or even to remote code execution.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id java/spring-boot-exposed-actuators
|
||||
* @tags security
|
||||
* experimental
|
||||
* external/cwe/cwe-16
|
||||
*/
|
||||
|
||||
import java
|
||||
deprecated import SpringBootActuators
|
||||
|
||||
deprecated query predicate problems(PermitAllCall permitAllCall, string message) {
|
||||
permitAllCall.permitsSpringBootActuators() and
|
||||
message = "Unauthenticated access to Spring Boot actuator is allowed."
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
deprecated module;
|
||||
|
||||
import java
|
||||
|
||||
/** The class `org.springframework.security.config.annotation.web.builders.HttpSecurity`. */
|
||||
class TypeHttpSecurity extends Class {
|
||||
TypeHttpSecurity() {
|
||||
this.hasQualifiedName("org.springframework.security.config.annotation.web.builders",
|
||||
"HttpSecurity")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The class
|
||||
* `org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer`.
|
||||
*/
|
||||
class TypeAuthorizedUrl extends Class {
|
||||
TypeAuthorizedUrl() {
|
||||
this.hasQualifiedName("org.springframework.security.config.annotation.web.configurers",
|
||||
"ExpressionUrlAuthorizationConfigurer<HttpSecurity>$AuthorizedUrl<>")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The class `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`.
|
||||
*/
|
||||
class TypeAbstractRequestMatcherRegistry extends Class {
|
||||
TypeAbstractRequestMatcherRegistry() {
|
||||
this.hasQualifiedName("org.springframework.security.config.annotation.web",
|
||||
"AbstractRequestMatcherRegistry<AuthorizedUrl<>>")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The class `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest`.
|
||||
*/
|
||||
class TypeEndpointRequest extends Class {
|
||||
TypeEndpointRequest() {
|
||||
this.hasQualifiedName("org.springframework.boot.actuate.autoconfigure.security.servlet",
|
||||
"EndpointRequest")
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to `EndpointRequest.toAnyEndpoint` method. */
|
||||
class ToAnyEndpointCall extends MethodCall {
|
||||
ToAnyEndpointCall() {
|
||||
this.getMethod().hasName("toAnyEndpoint") and
|
||||
this.getMethod().getDeclaringType() instanceof TypeEndpointRequest
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `HttpSecurity.requestMatcher` method with argument `RequestMatcher.toAnyEndpoint()`.
|
||||
*/
|
||||
class RequestMatcherCall extends MethodCall {
|
||||
RequestMatcherCall() {
|
||||
this.getMethod().hasName("requestMatcher") and
|
||||
this.getMethod().getDeclaringType() instanceof TypeHttpSecurity and
|
||||
this.getArgument(0) instanceof ToAnyEndpointCall
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `HttpSecurity.requestMatchers` method with lambda argument
|
||||
* `RequestMatcher.toAnyEndpoint()`.
|
||||
*/
|
||||
class RequestMatchersCall extends MethodCall {
|
||||
RequestMatchersCall() {
|
||||
this.getMethod().hasName("requestMatchers") and
|
||||
this.getMethod().getDeclaringType() instanceof TypeHttpSecurity and
|
||||
this.getArgument(0).(LambdaExpr).getExprBody() instanceof ToAnyEndpointCall
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to `HttpSecurity.authorizeRequests` method. */
|
||||
class AuthorizeRequestsCall extends MethodCall {
|
||||
AuthorizeRequestsCall() {
|
||||
this.getMethod().hasName("authorizeRequests") and
|
||||
this.getMethod().getDeclaringType() instanceof TypeHttpSecurity
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to `AuthorizedUrl.permitAll` method. */
|
||||
class PermitAllCall extends MethodCall {
|
||||
PermitAllCall() {
|
||||
this.getMethod().hasName("permitAll") and
|
||||
this.getMethod().getDeclaringType() instanceof TypeAuthorizedUrl
|
||||
}
|
||||
|
||||
/** Holds if `permitAll` is called on request(s) mapped to actuator endpoint(s). */
|
||||
predicate permitsSpringBootActuators() {
|
||||
exists(AuthorizeRequestsCall authorizeRequestsCall |
|
||||
// .requestMatcher(EndpointRequest).authorizeRequests([...]).[...]
|
||||
authorizeRequestsCall.getQualifier() instanceof RequestMatcherCall
|
||||
or
|
||||
// .requestMatchers(matcher -> EndpointRequest).authorizeRequests([...]).[...]
|
||||
authorizeRequestsCall.getQualifier() instanceof RequestMatchersCall
|
||||
|
|
||||
// [...].authorizeRequests(r -> r.anyRequest().permitAll()) or
|
||||
// [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll())
|
||||
authorizeRequestsCall.getArgument(0).(LambdaExpr).getExprBody() = this and
|
||||
(
|
||||
this.getQualifier() instanceof AnyRequestCall or
|
||||
this.getQualifier() instanceof RegistryRequestMatchersCall
|
||||
)
|
||||
or
|
||||
// [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or
|
||||
// [...].authorizeRequests().anyRequest().permitAll()
|
||||
authorizeRequestsCall.getNumArgument() = 0 and
|
||||
exists(RegistryRequestMatchersCall registryRequestMatchersCall |
|
||||
registryRequestMatchersCall.getQualifier() = authorizeRequestsCall and
|
||||
this.getQualifier() = registryRequestMatchersCall
|
||||
)
|
||||
or
|
||||
exists(AnyRequestCall anyRequestCall |
|
||||
anyRequestCall.getQualifier() = authorizeRequestsCall and
|
||||
this.getQualifier() = anyRequestCall
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(AuthorizeRequestsCall authorizeRequestsCall |
|
||||
// http.authorizeRequests([...]).[...]
|
||||
authorizeRequestsCall.getQualifier() instanceof VarAccess
|
||||
|
|
||||
// [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll())
|
||||
authorizeRequestsCall.getArgument(0).(LambdaExpr).getExprBody() = this and
|
||||
this.getQualifier() instanceof RegistryRequestMatchersCall
|
||||
or
|
||||
// [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or
|
||||
authorizeRequestsCall.getNumArgument() = 0 and
|
||||
exists(RegistryRequestMatchersCall registryRequestMatchersCall |
|
||||
registryRequestMatchersCall.getQualifier() = authorizeRequestsCall and
|
||||
this.getQualifier() = registryRequestMatchersCall
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to `AbstractRequestMatcherRegistry.anyRequest` method. */
|
||||
class AnyRequestCall extends MethodCall {
|
||||
AnyRequestCall() {
|
||||
this.getMethod().hasName("anyRequest") and
|
||||
this.getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `AbstractRequestMatcherRegistry.requestMatchers` method with an argument
|
||||
* `RequestMatcher.toAnyEndpoint()`.
|
||||
*/
|
||||
class RegistryRequestMatchersCall extends MethodCall {
|
||||
RegistryRequestMatchersCall() {
|
||||
this.getMethod().hasName("requestMatchers") and
|
||||
this.getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry and
|
||||
this.getAnArgument() instanceof ToAnyEndpointCall
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
| SpringBootActuators.java:6:88:6:120 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
|
||||
| SpringBootActuators.java:10:5:10:137 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
|
||||
| SpringBootActuators.java:14:5:14:149 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
|
||||
| SpringBootActuators.java:18:5:18:101 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
|
||||
| SpringBootActuators.java:22:5:22:89 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
|
||||
| SpringBootActuators.java:26:40:26:108 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
|
||||
| SpringBootActuators.java:30:5:30:113 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. |
|
||||
@@ -1,104 +0,0 @@
|
||||
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
|
||||
public class SpringBootActuators {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest().permitAll());
|
||||
}
|
||||
|
||||
protected void configure2(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll();
|
||||
}
|
||||
|
||||
protected void configure3(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll();
|
||||
}
|
||||
|
||||
protected void configure4(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest().permitAll();
|
||||
}
|
||||
|
||||
protected void configure5(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll();
|
||||
}
|
||||
|
||||
protected void configure6(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll());
|
||||
}
|
||||
|
||||
protected void configure7(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest().permitAll();
|
||||
}
|
||||
|
||||
protected void configureOk1(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOk2(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOk3(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().anyRequest().permitAll();
|
||||
}
|
||||
|
||||
protected void configureOk4(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests(authz -> authz.anyRequest().permitAll());
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints1(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests(requests -> requests.anyRequest().permitAll());
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints2(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.to("health")).authorizeRequests().requestMatchers(EndpointRequest.to("health")).permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints3(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints4(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints5(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints6(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.to("health", "info")).permitAll());
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints7(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll1(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll2(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll3(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll4(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest();
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll5(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll6(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint()));
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll7(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest();
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security/CWE/CWE-016/SpringBootActuators.ql
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/lingala-zip4j-2.11.5:${testdir}/../../../stubs/software-amazon-awssdk-crt-0.20.3:${testdir}/../../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/reactivestreams-1.0.4:${testdir}/../../../../stubs/slf4j-2.0.0
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/lingala-zip4j-2.11.5:${testdir}/../../../stubs/software-amazon-awssdk-crt-0.20.3:${testdir}/../../../../stubs/springframework-5.8.x:${testdir}/../../../stubs/reactivestreams-1.0.4:${testdir}/../../../../stubs/slf4j-2.0.0
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../../stubs/springframework-5.3.8/:${testdir}/../../../../../../stubs/org.mybatis-3.5.4/
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../../stubs/springframework-5.8.x/:${testdir}/../../../../../../stubs/org.mybatis-3.5.4/
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jython-2.7.2:${testdir}/../../../../experimental/stubs/rhino-1.7.13:${testdir}/../../../../stubs/bsh-2.0b5:${testdir}/../../../../experimental/stubs/jshell:${testdir}/../../../../experimental/stubs/apache-freemarker-2.3.31:${testdir}/../../../../experimental/stubs/jinjava-2.6.0:${testdir}/../../../../experimental/stubs/pebble-3.1.5:${testdir}/../../../../experimental/stubs/thymeleaf-3.0.14:${testdir}/../../../../experimental/stubs/apache-velocity-2.3
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jython-2.7.2:${testdir}/../../../../experimental/stubs/rhino-1.7.13:${testdir}/../../../../stubs/bsh-2.0b5:${testdir}/../../../../experimental/stubs/jshell:${testdir}/../../../../experimental/stubs/apache-freemarker-2.3.31:${testdir}/../../../../experimental/stubs/jinjava-2.6.0:${testdir}/../../../../experimental/stubs/pebble-3.1.5:${testdir}/../../../../experimental/stubs/thymeleaf-3.0.14:${testdir}/../../../../experimental/stubs/apache-velocity-2.3
|
||||
|
||||
@@ -1 +1 @@
|
||||
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jsr311-api-1.1.1:${testdir}/../../../../stubs/springframework-5.3.8
|
||||
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jsr311-api-1.1.1:${testdir}/../../../../stubs/springframework-5.8.x
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.3.8/:${testdir}/../../../../stubs/apache-commons-lang3-3.7/
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.8.x/:${testdir}/../../../../stubs/apache-commons-lang3-3.7/
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/apache-http-4.4.13/:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/fastjson-1.2.74/:${testdir}/../../../../stubs/gson-2.8.6/:${testdir}/../../../../stubs/jackson-databind-2.12/:${testdir}/../../../../stubs/jackson-core-2.12:${testdir}/../../../../stubs/springframework-5.3.8/
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/apache-http-4.4.13/:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/fastjson-1.2.74/:${testdir}/../../../../stubs/gson-2.8.6/:${testdir}/../../../../stubs/jackson-databind-2.12/:${testdir}/../../../../stubs/jackson-core-2.12:${testdir}/../../../../stubs/springframework-5.8.x/
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.3.8/:${testdir}/../../../../stubs/google-android-9.0.0
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.8.x/:${testdir}/../../../../stubs/google-android-9.0.0
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.3.8/
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.8.x/
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.3.8
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.8.x
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/apache-http-4.4.13/:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/saxon-xqj-9.x/:${testdir}/../../../../stubs/springframework-5.3.8/
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/apache-http-4.4.13/:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/saxon-xqj-9.x/:${testdir}/../../../../stubs/springframework-5.8.x/
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/akka-2.6.x:${testdir}/../../../stubs/jwtk-jjwt-0.11.2:${testdir}/../../../stubs/jenkins:${testdir}/../../../stubs/stapler-1.263
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.8.x:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/akka-2.6.x:${testdir}/../../../stubs/jwtk-jjwt-0.11.2:${testdir}/../../../stubs/jenkins:${testdir}/../../../stubs/stapler-1.263
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
//semmle-extractor-options: --javac-args -cp
|
||||
//semmle-extractor-options: ${testdir}/../../../../stubs/springframework-5.3.8/
|
||||
//semmle-extractor-options: ${testdir}/../../../../stubs/springframework-5.8.x/
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8:${testdir}/../../../../stubs/apache-commons-logging-1.2/
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x:${testdir}/../../../../stubs/apache-commons-logging-1.2/
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8:${testdir}/../../../../stubs/javax-servlet-2.5
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x:${testdir}/../../../../stubs/javax-servlet-2.5
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8:${testdir}/../../../../stubs/javax-servlet-2.5
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x:${testdir}/../../../../stubs/javax-servlet-2.5
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8:${testdir}/../../../../stubs/javax-servlet-2.5:${testdir}/../../../../stubs/apache-commons-logging-1.2
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x:${testdir}/../../../../stubs/javax-servlet-2.5:${testdir}/../../../../stubs/apache-commons-logging-1.2
|
||||
|
||||
@@ -1 +1 @@
|
||||
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/servlet-api-2.4:${testdir}/../../../../../stubs/apache-commons-io-2.6:${testdir}/../../../../../stubs/cargo:${testdir}/../../../../../stubs/apache-ant-1.10.13:${testdir}/../../../../../stubs/stapler-1.263:${testdir}/../../../../../stubs/javax-servlet-2.5:${testdir}/../../../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../../../stubs/saxon-xqj-9.x:${testdir}/../../../../../stubs/apache-commons-beanutils:${testdir}/../../../../../stubs/dom4j-2.1.1:${testdir}/../../../../../stubs/apache-commons-lang:${testdir}/../../../../../stubs/jaxen-1.2.0:${testdir}/../../../../../stubs/jmh-1.3.6:${testdir}/../../../../../stubs/springframework-5.3.8:${testdir}/../../../../../stubs/jaxws-api-2.0:${testdir}/../../../../../stubs/apache-cxf
|
||||
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/servlet-api-2.4:${testdir}/../../../../../stubs/apache-commons-io-2.6:${testdir}/../../../../../stubs/cargo:${testdir}/../../../../../stubs/apache-ant-1.10.13:${testdir}/../../../../../stubs/stapler-1.263:${testdir}/../../../../../stubs/javax-servlet-2.5:${testdir}/../../../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../../../stubs/saxon-xqj-9.x:${testdir}/../../../../../stubs/apache-commons-beanutils:${testdir}/../../../../../stubs/dom4j-2.1.1:${testdir}/../../../../../stubs/apache-commons-lang:${testdir}/../../../../../stubs/jaxen-1.2.0:${testdir}/../../../../../stubs/jmh-1.3.6:${testdir}/../../../../../stubs/springframework-5.8.x:${testdir}/../../../../../stubs/jaxws-api-2.0:${testdir}/../../../../../stubs/apache-cxf
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/shiro-core-1.5.2:${testdir}/../../../stubs/spring-ldap-2.3.2:${testdir}/../../../stubs/Saxon-HE-9.9.1-7:${testdir}/../../../stubs/apache-commons-logging-1.2
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.8.x:${testdir}/../../../stubs/shiro-core-1.5.2:${testdir}/../../../stubs/spring-ldap-2.3.2:${testdir}/../../../stubs/Saxon-HE-9.9.1-7:${testdir}/../../../stubs/apache-commons-logging-1.2
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/servlet-api-2.4:${testdir}/../../../../../stubs/javax-ws-rs-api-2.1.1/:${testdir}/../../../../../stubs/springframework-5.3.8:${testdir}/../../../../../stubs/javax-faces-2.3/:${testdir}/../../../../../stubs/google-android-9.0.0:${testdir}/../../../../../stubs/jenkins
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/servlet-api-2.4:${testdir}/../../../../../stubs/javax-ws-rs-api-2.1.1/:${testdir}/../../../../../stubs/springframework-5.8.x:${testdir}/../../../../../stubs/javax-faces-2.3/:${testdir}/../../../../../stubs/google-android-9.0.0:${testdir}/../../../../../stubs/jenkins
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/mongodbClient:${testdir}/../../../../../stubs/springframework-5.3.8:${testdir}/../../../../../stubs/apache-hive --release 21
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/mongodbClient:${testdir}/../../../../../stubs/springframework-5.8.x:${testdir}/../../../../../stubs/apache-hive --release 21
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/spring-ldap-2.3.2:${testdir}/../../../stubs/unboundid-ldap-4.0.14:${testdir}/../../../stubs/esapi-2.0.1:${testdir}/../../../stubs/apache-ldap-1.0.2
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.8.x:${testdir}/../../../stubs/spring-ldap-2.3.2:${testdir}/../../../stubs/unboundid-ldap-4.0.14:${testdir}/../../../stubs/esapi-2.0.1:${testdir}/../../../stubs/apache-ldap-1.0.2
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/validation-api-2.0.1.Final:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../stubs/apache-commons-logging-1.2:${testdir}/../../../stubs/mvel2-2.4.7:${testdir}/../../../stubs/groovy-all-3.0.7:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/scriptengine:${testdir}/../../../stubs/jsr223-api:${testdir}/../../../stubs/apache-freemarker-2.3.31:${testdir}/../../../stubs/jinjava-2.6.0:${testdir}/../../../stubs/pebble-3.1.5:${testdir}/../../../stubs/thymeleaf-3.0.14:${testdir}/../../../stubs/apache-velocity-2.3:${testdir}/../../..//stubs/google-android-9.0.0
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/validation-api-2.0.1.Final:${testdir}/../../../stubs/springframework-5.8.x:${testdir}/../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../stubs/apache-commons-logging-1.2:${testdir}/../../../stubs/mvel2-2.4.7:${testdir}/../../../stubs/groovy-all-3.0.7:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/scriptengine:${testdir}/../../../stubs/jsr223-api:${testdir}/../../../stubs/apache-freemarker-2.3.31:${testdir}/../../../stubs/jinjava-2.6.0:${testdir}/../../../stubs/pebble-3.1.5:${testdir}/../../../stubs/thymeleaf-3.0.14:${testdir}/../../../stubs/apache-velocity-2.3:${testdir}/../../..//stubs/google-android-9.0.0
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
|
||||
public class SpringBootActuatorsTest {
|
||||
// Spring security version 5.2.3 used `authorizeRequests` and `requestMatcher(s)`
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest().permitAll()); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure2(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure3(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure4(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest().permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure5(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure6(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure7(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest().permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configureOk1(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOk2(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOk3(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().anyRequest().permitAll();
|
||||
}
|
||||
|
||||
protected void configureOk4(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests(authz -> authz.anyRequest().permitAll());
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints1(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests(requests -> requests.anyRequest().permitAll());
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints2(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.to("health")).authorizeRequests().requestMatchers(EndpointRequest.to("health")).permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints3(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints4(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints5(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints6(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.to("health", "info")).permitAll());
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints7(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll1(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll2(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll3(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll4(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest();
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll5(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll6(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint()));
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll7(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest();
|
||||
}
|
||||
|
||||
// Spring security version 5.5.0 introduced `authorizeHttpRequests`
|
||||
protected void configure_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests(requests -> requests.anyRequest().permitAll()); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure2_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure3_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure4_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest().permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure5_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure6_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure7_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest().permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configureOk3_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests().anyRequest().permitAll();
|
||||
}
|
||||
|
||||
protected void configureOk4_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints1_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.to("health", "info")).authorizeHttpRequests(requests -> requests.anyRequest().permitAll());
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints2_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.to("health")).authorizeHttpRequests().requestMatchers(EndpointRequest.to("health")).permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints3_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeHttpRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints4_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.to("health", "info")).authorizeHttpRequests().anyRequest().permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints5_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints6_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests(requests -> requests.requestMatchers(EndpointRequest.to("health", "info")).permitAll());
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints7_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeHttpRequests().anyRequest().permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll1_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests(requests -> requests.anyRequest());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll2_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll3_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll4_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest();
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll5_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll6_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint()));
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll7_authorizeHttpRequests(HttpSecurity http) throws Exception {
|
||||
http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest();
|
||||
}
|
||||
|
||||
// Spring security version 5.8.0 introduced `securityMatcher(s)`
|
||||
protected void configure_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests(requests -> requests.anyRequest().permitAll()); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure2_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure3_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure4_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest().permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configure7_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest().permitAll(); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
protected void configureOk1_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatcher(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOk2_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatchers().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints1_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatcher(EndpointRequest.to("health", "info")).authorizeHttpRequests(requests -> requests.anyRequest().permitAll());
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints2_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatcher(EndpointRequest.to("health")).authorizeHttpRequests().requestMatchers(EndpointRequest.to("health")).permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints3_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeHttpRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints4_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatcher(EndpointRequest.to("health", "info")).authorizeHttpRequests().anyRequest().permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkSafeEndpoints7_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeHttpRequests().anyRequest().permitAll();
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll1_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests(requests -> requests.anyRequest());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll2_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll3_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint());
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll4_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest();
|
||||
}
|
||||
|
||||
protected void configureOkNoPermitAll7_securityMatchers(HttpSecurity http) throws Exception {
|
||||
http.securityMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest();
|
||||
}
|
||||
|
||||
// QHelp Bad example
|
||||
public void securityFilterChain1(HttpSecurity http) throws Exception {
|
||||
// BAD: Unauthenticated access to Spring Boot actuator endpoints is allowed
|
||||
http.securityMatcher(EndpointRequest.toAnyEndpoint());
|
||||
http.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll()); // $ hasExposedSpringBootActuator
|
||||
}
|
||||
|
||||
// QHelp Good example
|
||||
public void securityFilterChain2(HttpSecurity http) throws Exception {
|
||||
// GOOD: only users with ENDPOINT_ADMIN role are allowed to access the actuator endpoints
|
||||
http.securityMatcher(EndpointRequest.toAnyEndpoint());
|
||||
http.authorizeHttpRequests((requests) -> requests.anyRequest().hasRole("ENDPOINT_ADMIN"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import java
|
||||
import semmle.code.java.frameworks.spring.SpringSecurity
|
||||
import semmle.code.java.security.SpringBootActuatorsQuery
|
||||
import utils.test.InlineExpectationsTest
|
||||
|
||||
module SpringBootActuatorsTest implements TestSig {
|
||||
string getARelevantTag() { result = "hasExposedSpringBootActuator" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasExposedSpringBootActuator" and
|
||||
exists(SpringPermitAllCall permitAllCall | permitsSpringBootActuators(permitAllCall) |
|
||||
permitAllCall.getLocation() = location and
|
||||
element = permitAllCall.toString() and
|
||||
value = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<SpringBootActuatorsTest>
|
||||
@@ -0,0 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../../stubs/springframework-5.8.x
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.3.8/:${testdir}/../../../stubs/org.mybatis-3.5.4/:${testdir}/../../../stubs/stapler-1.263/:${testdir}/../../../stubs/javax-servlet-2.5:${testdir}/../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../stubs/saxon-xqj-9.x:${testdir}/../../../stubs/apache-commons-beanutils:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/apache-commons-lang:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/apache-commons-logging-1.2/
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.8.x/:${testdir}/../../../stubs/org.mybatis-3.5.4/:${testdir}/../../../stubs/stapler-1.263/:${testdir}/../../../stubs/javax-servlet-2.5:${testdir}/../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../stubs/saxon-xqj-9.x:${testdir}/../../../stubs/apache-commons-beanutils:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/apache-commons-lang:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/apache-commons-logging-1.2/
|
||||
|
||||
@@ -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:${testdir}/../../../stubs/springframework-5.3.8:${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:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/jabsorb-1.3.2:${testdir}/../../../stubs/json-java-20210307:${testdir}/../../../stubs/joddjson-6.0.3:${testdir}/../../../stubs/flexjson-2.1:${testdir}/../../../stubs/gson-2.8.6:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/serialkiller-4.0.0:${testdir}/../../../stubs/jms-api-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:${testdir}/../../../stubs/springframework-5.8.x:${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:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/jabsorb-1.3.2:${testdir}/../../../stubs/json-java-20210307:${testdir}/../../../stubs/joddjson-6.0.3:${testdir}/../../../stubs/flexjson-2.1:${testdir}/../../../stubs/gson-2.8.6:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/serialkiller-4.0.0:${testdir}/../../../stubs/jms-api-1
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.3.8/:${testdir}/../../../stubs/javax-faces-2.3/:${testdir}/../../../stubs/undertow-io-2.2/:${testdir}/../../../stubs/jboss-vfs-3.2/:${testdir}/../../../stubs/stapler-1.263/:${testdir}/../../../stubs/apache-commons-fileupload-1.4/:${testdir}/../../../stubs/apache-commons-beanutils/:${testdir}/../../../stubs/saxon-xqj-9.x/:${testdir}/../../../stubs/apache-commons-lang/:${testdir}/../../../stubs/javax-servlet-2.5/
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.8.x/:${testdir}/../../../stubs/javax-faces-2.3/:${testdir}/../../../stubs/undertow-io-2.2/:${testdir}/../../../stubs/jboss-vfs-3.2/:${testdir}/../../../stubs/stapler-1.263/:${testdir}/../../../stubs/apache-commons-fileupload-1.4/:${testdir}/../../../stubs/apache-commons-beanutils/:${testdir}/../../../stubs/saxon-xqj-9.x/:${testdir}/../../../stubs/apache-commons-lang/:${testdir}/../../../stubs/javax-servlet-2.5/
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/jdom-1.1.3:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/simple-xml-2.7.1:${testdir}/../../../stubs/jaxb-api-2.3.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/apache-commons-digester3-3.2:${testdir}/../../../stubs/servlet-api-2.4/:${testdir}/../../../stubs/rundeck-api-java-client-13.2:${testdir}/../../../stubs/springframework-5.3.8/:${testdir}/../../../stubs/mdht-1.2.0/
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/jdom-1.1.3:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/simple-xml-2.7.1:${testdir}/../../../stubs/jaxb-api-2.3.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/apache-commons-digester3-3.2:${testdir}/../../../stubs/servlet-api-2.4/:${testdir}/../../../stubs/rundeck-api-java-client-13.2:${testdir}/../../../stubs/springframework-5.8.x/:${testdir}/../../../stubs/mdht-1.2.0/
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/ognl-3.2.14:${testdir}/../../../stubs/struts2-core-2.5.22
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.8.x:${testdir}/../../../stubs/ognl-3.2.14:${testdir}/../../../stubs/struts2-core-2.5.22
|
||||
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../stubs/springframework-5.3.8:${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/projectreactor-3.4.3/:${testdir}/../../../stubs/postgresql-42.3.3/:${testdir}/../../../stubs/HikariCP-3.4.5/:${testdir}/../../../stubs/spring-jdbc-5.3.8/:${testdir}/../../../stubs/jdbi3-core-3.27.2/:${testdir}/../../../stubs/cargo:${testdir}/../../../stubs/javafx-web:${testdir}/../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/stapler-1.263:${testdir}/../../../stubs/javax-servlet-2.5:${testdir}/../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../stubs/saxon-xqj-9.x:${testdir}/../../../stubs/apache-commons-beanutils:${testdir}/../../../stubs/apache-commons-lang:${testdir}/../../../stubs/apache-http-5:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jaxws-api-2.0:${testdir}/../../../stubs/apache-cxf
|
||||
//semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../stubs/springframework-5.8.x:${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/projectreactor-3.4.3/:${testdir}/../../../stubs/postgresql-42.3.3/:${testdir}/../../../stubs/HikariCP-3.4.5/:${testdir}/../../../stubs/spring-jdbc-5.3.8/:${testdir}/../../../stubs/jdbi3-core-3.27.2/:${testdir}/../../../stubs/cargo:${testdir}/../../../stubs/javafx-web:${testdir}/../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/stapler-1.263:${testdir}/../../../stubs/javax-servlet-2.5:${testdir}/../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../stubs/saxon-xqj-9.x:${testdir}/../../../stubs/apache-commons-beanutils:${testdir}/../../../stubs/apache-commons-lang:${testdir}/../../../stubs/apache-http-5:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jaxws-api-2.0:${testdir}/../../../stubs/apache-cxf
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user