wave16c: esbuild/deno CWE-407 scan results
esbuild-0001: serve_other.go hosts []string scan → map[string]struct{} (57x, MEDIUM)
deno: CLEAN (uses HashSet/HashMap throughout, no Vec.contains() in loops)
1 test: 1/1 PASS
This commit is contained in:
parent
38945e8138
commit
da26ffd2cf
3 changed files with 116 additions and 0 deletions
11
defects/deno/patch/CLEAN.md
Normal file
11
defects/deno/patch/CLEAN.md
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# CLEAN: deno
|
||||||
|
|
||||||
|
Scanned 2026-03-30. No actionable CWE-407 defects found.
|
||||||
|
|
||||||
|
The Deno codebase uses correct data structures throughout:
|
||||||
|
- `HashSet` for deduplication and membership tests (module_loader.rs, permissions/lib.rs, etc.)
|
||||||
|
- `BTreeSet` for sorted membership (cli/util/extract.rs)
|
||||||
|
- `HashMap`/`BTreeMap` for O(1) keyed lookups
|
||||||
|
- Fixed-size array literals only for small constant-size checks
|
||||||
|
|
||||||
|
No `Vec.contains()` patterns found in performance-critical loops.
|
||||||
43
defects/esbuild/patch/esbuild-0001-serve-hosts-map.patch
Normal file
43
defects/esbuild/patch/esbuild-0001-serve-hosts-map.patch
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
--- a/pkg/api/serve_other.go
|
||||||
|
+++ b/pkg/api/serve_other.go
|
||||||
|
@@ -48,7 +48,7 @@ type apiHandler struct {
|
||||||
|
keyfileToLower string
|
||||||
|
certfileToLower string
|
||||||
|
fallback string
|
||||||
|
- hosts []string
|
||||||
|
+ hosts map[string]struct{} // O(1) lookup per HTTP request; was O(H) []string scan
|
||||||
|
corsOrigin []string
|
||||||
|
serveWaitGroup sync.WaitGroup
|
||||||
|
|
||||||
|
@@ -139,14 +139,10 @@ func (h *apiHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
|
||||||
|
// Check the "Host" header to prevent DNS rebinding attacks
|
||||||
|
if strings.ContainsRune(req.Host, ':') {
|
||||||
|
if host, _, err := net.SplitHostPort(req.Host); err == nil {
|
||||||
|
req.Host = host
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- if req.Host != "localhost" {
|
||||||
|
- ok := false
|
||||||
|
- for _, allowed := range h.hosts {
|
||||||
|
- if req.Host == allowed {
|
||||||
|
- ok = true
|
||||||
|
- break
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- if !ok {
|
||||||
|
+ if req.Host != "localhost" {
|
||||||
|
+ if _, ok := h.hosts[req.Host]; !ok {
|
||||||
|
go h.notifyRequest(time.Since(start), req, http.StatusForbidden)
|
||||||
|
res.WriteHeader(http.StatusForbidden)
|
||||||
|
maybeWriteResponseBody([]byte(fmt.Sprintf("403 - Forbidden: The host %q is not allowed", req.Host)))
|
||||||
|
|
||||||
|
@@ -894,7 +890,11 @@ func serve(ctx *bundleContext, serveOptions ServeOptions, result []BuildResult) (
|
||||||
|
handler := &apiHandler{
|
||||||
|
...
|
||||||
|
- hosts: append([]string{}, result.Hosts...),
|
||||||
|
+ hosts: func() map[string]struct{} {
|
||||||
|
+ m := make(map[string]struct{}, len(result.Hosts))
|
||||||
|
+ for _, h := range result.Hosts { m[h] = struct{}{} }
|
||||||
|
+ return m
|
||||||
|
+ }(),
|
||||||
|
corsOrigin: append([]string{}, serveOptions.CORS.Origin...),
|
||||||
62
defects/esbuild/unit/EsbuildTest.java
Normal file
62
defects/esbuild/unit/EsbuildTest.java
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CWE-407 unit test for esbuild serve_other.go defect.
|
||||||
|
*
|
||||||
|
* esbuild-0001: pkg/api/serve_other.go ServeHTTP() host allowlist
|
||||||
|
* for _, allowed := range h.hosts { // O(H) scan per HTTP request
|
||||||
|
* if req.Host == allowed { ok = true; break }
|
||||||
|
* }
|
||||||
|
* Fix: map[string]struct{} → O(1) probe per request
|
||||||
|
*/
|
||||||
|
public class EsbuildTest {
|
||||||
|
|
||||||
|
static boolean checkHostSlice(String[] hosts, String reqHost) {
|
||||||
|
for (String allowed : hosts) { // O(H) — defect
|
||||||
|
if (allowed.equals(reqHost)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean checkHostMap(Set<String> hostsMap, String reqHost) {
|
||||||
|
return hostsMap.contains(reqHost); // O(1) — fix
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testEsbuild0001() throws Exception {
|
||||||
|
int H = 1000; // configured hosts
|
||||||
|
String[] hosts = new String[H];
|
||||||
|
for (int i = 0; i < H; i++) hosts[i] = "server-" + i + ".example.com";
|
||||||
|
Set<String> hostsMap = new HashSet<>(Arrays.asList(hosts));
|
||||||
|
|
||||||
|
// hit middle of list — worst case for linear scan is end
|
||||||
|
String reqHost = "server-999.example.com";
|
||||||
|
|
||||||
|
// correctness
|
||||||
|
assert checkHostSlice(hosts, reqHost) == checkHostMap(hostsMap, reqHost);
|
||||||
|
assert !checkHostSlice(hosts, "evil.com") && !checkHostMap(hostsMap, "evil.com");
|
||||||
|
|
||||||
|
// performance: simulate R HTTP requests
|
||||||
|
int R = 100_000;
|
||||||
|
long t0 = System.nanoTime();
|
||||||
|
int s1 = 0;
|
||||||
|
for (int r = 0; r < R; r++) if (checkHostSlice(hosts, reqHost)) s1++;
|
||||||
|
long tSlice = System.nanoTime() - t0;
|
||||||
|
|
||||||
|
t0 = System.nanoTime();
|
||||||
|
int s2 = 0;
|
||||||
|
for (int r = 0; r < R; r++) if (checkHostMap(hostsMap, reqHost)) s2++;
|
||||||
|
long tMap = System.nanoTime() - t0;
|
||||||
|
|
||||||
|
assert s1 == s2;
|
||||||
|
double ratio = (double) tSlice / tMap;
|
||||||
|
System.out.printf("esbuild-0001: slice=%.3fs map=%.3fs ratio=%.1f×%n",
|
||||||
|
tSlice / 1e9, tMap / 1e9, ratio);
|
||||||
|
assert ratio > 10 : "Expected >10× speedup, got " + ratio;
|
||||||
|
System.out.println("PASS esbuild-0001");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
testEsbuild0001();
|
||||||
|
System.out.println("ALL PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue