Skip to content

Commit e21401a

Browse files
committed
feat: SSRF env var to allow all connections before it's configured
In some projects, network requests can happen after the fuzz test has started, but before the user had a chance to configure allowed/denied connections. Now the user can start Jazzer with the environmental variable JAZZER_SSRF_PERMISSIVE_UNTIL_CONFIGURED set to a truthy value and all network requests will be allowed, until the user specifies otherwise in the fuzz test using BugDetectors.allowNetworkConnections(...)
1 parent 068587e commit e21401a

File tree

4 files changed

+89
-3
lines changed

4 files changed

+89
-3
lines changed

docs/arguments-and-configuration-options.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ Some parameters only have an effect when used with standalone Jazzer binary (mar
125125
- In regression mode, controls which folders are used for coverage computation.
126126
- `false` (default): Use only thej crash file folder.
127127
- `true`: Use both the crash file folder and the corpus folder.
128+
- **JAZZER_SSRF_PERMISSIVE_UNTIL_CONFIGURED** [bool, default=""] (*environment variable only*)
129+
- When set to a truthy value, the ServerSideRequestForgery sanitizer will allow all outgoing requests until it is explicitly configured with allowed hosts in the fuzz test.
130+
This is useful to avoid false positives in multithreaded applications that make network requests during initialization.
128131

129132
- **keep_going** [uint64, default="1"]
130133
- Number of distinct findings after which the fuzzer should stop.

sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/ServerSideRequestForgery.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,14 @@ public class ServerSideRequestForgery {
3434
public static final AtomicReference<BiPredicate<String, Integer>> connectionPermitted =
3535
new AtomicReference<>((host, port) -> true);
3636

37-
// Disallow all connections right before the first fuzz target is executed.
3837
static {
39-
Jazzer.onFuzzTargetReady(() -> connectionPermitted.set((host, port) -> false));
38+
// Disallow all connections right before the first fuzz target is executed, if the user has not
39+
// specifically opted into permissive behavior.
40+
// In multithreaded fuzzing scenarios, a network request can be made after the fuzzing has
41+
// started but before a user had a chance to call BugDetectors.allowNetworkConnections().
42+
if (System.getenv("JAZZER_SSRF_PERMISSIVE_UNTIL_CONFIGURED") == null) {
43+
Jazzer.onFuzzTargetReady(() -> connectionPermitted.set((host, port) -> false));
44+
}
4045
}
4146

4247
/**
@@ -132,7 +137,10 @@ private static void checkSsrf(Object[] arguments) {
132137
+ "If the fuzz test is expected to perform network connections, call"
133138
+ " com.code_intelligence.jazzer.api.BugDetectors#allowNetworkConnections at"
134139
+ " the beginning of your fuzz test and optionally provide a predicate"
135-
+ " matching the expected hosts.",
140+
+ " matching the expected hosts.\n\n"
141+
+ "In multithreaded fuzzing scenarios consider using the environment variable"
142+
+ " JAZZER_SSRF_PERMISSIVE_UNTIL_CONFIGURED to allow all connections until"
143+
+ " the fuzz test has been configured to allow specific connections.",
136144
host, port)));
137145
}
138146
}

sanitizers/src/test/java/com/example/BUILD.bazel

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,23 @@ java_fuzz_target_test(
594594
verify_crash_reproducer = False,
595595
)
596596

597+
java_fuzz_target_test(
598+
name = "SsrfAllowUntilConfigured",
599+
srcs = [
600+
"SsrfAllowUntilConfigured.java",
601+
],
602+
env = {
603+
"JAZZER_SSRF_PERMISSIVE_UNTIL_CONFIGURED": "1",
604+
},
605+
fuzzer_args = [
606+
"-runs=1",
607+
"-print_final_stats=1",
608+
],
609+
# tags = ["dangerous"],
610+
target_class = "com.example.SsrfAllowUntilConfigured",
611+
verify_crash_reproducer = False,
612+
)
613+
597614
java_fuzz_target_test(
598615
name = "ScriptEngineInjection",
599616
srcs = [
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright 2024 Code Intelligence GmbH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example;
18+
19+
import com.code_intelligence.jazzer.api.BugDetectors;
20+
import java.net.HttpURLConnection;
21+
import java.net.URL;
22+
import java.util.concurrent.CountDownLatch;
23+
24+
public class SsrfAllowUntilConfigured {
25+
26+
private static final CountDownLatch fuzzTestStarted = new CountDownLatch(1);
27+
28+
static {
29+
// Simulate a background thread that starts before fuzz test configuration
30+
Thread backgroundThread =
31+
new Thread(
32+
() -> {
33+
try {
34+
// Wait for fuzz test to start but before it configures SSRF
35+
fuzzTestStarted.await();
36+
System.out.println("Background thread making early request...");
37+
38+
URL url = new URL("https://localhost:8080");
39+
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
40+
conn.setRequestMethod("GET");
41+
conn.setConnectTimeout(1000);
42+
conn.setReadTimeout(1000);
43+
conn.getResponseCode();
44+
conn.disconnect();
45+
} catch (Exception ignored) {
46+
}
47+
});
48+
backgroundThread.setDaemon(true);
49+
backgroundThread.start();
50+
}
51+
52+
public static void fuzzerTestOneInput(boolean ignored) throws Exception {
53+
fuzzTestStarted.countDown();
54+
Thread.sleep(500); // Ensure background thread has time to run
55+
56+
BugDetectors.allowNetworkConnections((host, port) -> host.equals("localhost"));
57+
}
58+
}

0 commit comments

Comments
 (0)