mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-12 19:55:14 +02:00
refactor(dynamic): replace Spring annotation stubs with real dependencies, integrate MockMvc-based invocation for Spring controllers, and enhance runtime classpath logic
This commit is contained in:
parent
c57cd233fc
commit
61bfc0cf96
16 changed files with 214 additions and 98 deletions
|
|
@ -57,7 +57,7 @@ Real disclosed CVEs reduced to minimal reproducers, vulnerable + patched pair pe
|
|||
| CVE-2019-18634 | C | sudo (pwfeedback) | ISC | memory_safety | detected |
|
||||
| CVE-2019-13132 | C++ | ZeroMQ libzmq | MPL-2.0 | memory_safety | detected |
|
||||
| CVE-2022-1941 | C++ | Protocol Buffers | BSD-3-Clause | memory_safety | detected |
|
||||
| CVE-2026-25544 | TypeScript | Payload (Drizzle adapter) | MIT | sql_injection | deferred |
|
||||
| CVE-2026-25544 | TypeScript | Payload (Drizzle adapter) | MIT | sql_injection | detected |
|
||||
| CVE-2026-42353 | JavaScript | i18next-http-middleware | MIT | path_traversal | detected |
|
||||
|
||||
Deferred entries are real bugs Nyx can't yet detect. The fixture stays committed with `disabled: true` in ground truth so the gap remains visible.
|
||||
|
|
@ -83,6 +83,7 @@ Most recent first. Metrics are rule-level on the corpus size at that point.
|
|||
|
||||
| Date | Change | Corpus | P | R | F1 |
|
||||
|------------|------------------------------------------------------------------------------|--------|-------|-------|-------|
|
||||
| 2026-05-26 | Benchmark docs corrected for CVE-2026-25544: the Payload Drizzle SQL injection fixture is enabled and detected in `ground_truth.json`; only CVE-2017-1000117 remains deferred in the real-CVE table | 565 | 1.000 | 1.000 | 1.000 |
|
||||
| 2026-05-04 | C cvehunt session-0014: CVE-2017-1000117 (git ssh:// hostname-as-argv injection) added in corpus disabled — three-layer C engine gap: (a) array-element taint propagation through `args[i] = ssh_host;` writes, (b) missing `c.cmdi.exec*` AST patterns in `src/patterns/c.rs`, (c) sanitizer recognition of the upstream `if (ssh_host[0] == '-') die(...)` dash-prefix guard | 565 | 1.000 | 1.000 | 1.000 |
|
||||
| 2026-05-04 | JS/TS array-method validator-callback narrowing (`try_array_method_validator_callback_narrowing` in `src/taint/ssa_transfer/mod.rs`) — `<arr>.filter(<isSafeXxx>)` / `.find` / `.findLast` strips `Cap::all()` from the call result when the callback resolves to a `BooleanTrueIsValid` validator; CVE-2026-42353 (i18next-http-middleware path traversal) re-enabled in ground truth, deferred queue cleared | 563 | 1.000 | 1.000 | 1.000 |
|
||||
| 2026-05-04 | JS/TS ternary-RHS source-classification fix in `src/cfg/conditions.rs::lower_ternary_branch` (segment-strip first_member_label on the branch AST) — `let arr = cond ? req.query.lng : "";` now propagates taint through the diamond's join phi instead of lowering both branches to labelless Assign-with-empty-uses; CVE-2026-42353 (i18next-http-middleware path traversal / SSRF) added in corpus disabled — needs Array.prototype.filter(known_validator_callback) precision bridge | 561 | 1.000 | 1.000 | 1.000 |
|
||||
|
|
|
|||
|
|
@ -495,8 +495,8 @@ pub fn run_shape_fixture_lang(
|
|||
java_toolchain: nyx_scanner::dynamic::spec::JavaToolchain::default(),
|
||||
};
|
||||
|
||||
// Phase 14: Java shape fixtures bundle annotation / type stubs as
|
||||
// sibling `*.java` files alongside `Vuln.java` / `Benign.java`.
|
||||
// Phase 14: Java shape fixtures bundle helper sources and sometimes a
|
||||
// Maven manifest alongside `Vuln.java` / `Benign.java`.
|
||||
// Stage those sidecars next to the temp-copied entry file so the
|
||||
// harness builder can copy them into its per-run workdir. Skip the
|
||||
// alternate Vuln/Benign file to keep public class declarations from
|
||||
|
|
@ -519,7 +519,7 @@ pub fn run_shape_fixture_lang(
|
|||
if name == file || name == alt_file {
|
||||
continue;
|
||||
}
|
||||
if p.extension().map(|e| e == "java").unwrap_or(false) {
|
||||
if name == "pom.xml" || p.extension().map(|e| e == "java").unwrap_or(false) {
|
||||
let _ = std::fs::copy(&p, tmp.path().join(&name));
|
||||
}
|
||||
}
|
||||
|
|
@ -539,6 +539,26 @@ pub fn run_shape_fixture_lang(
|
|||
// [`VerifyStatus`] directly without learning the runner's API.
|
||||
match outcome {
|
||||
Ok(run) => {
|
||||
let detail = if run.triggered_by.is_none() {
|
||||
Some(format!(
|
||||
"attempts={:?}",
|
||||
run.attempts
|
||||
.iter()
|
||||
.map(|a| format!(
|
||||
"{} fired={} triggered={} sink_hit={} exit={:?} stdout={:?} stderr={:?}",
|
||||
a.payload_label,
|
||||
a.oracle_fired,
|
||||
a.triggered,
|
||||
a.outcome.sink_hit,
|
||||
a.outcome.exit_code,
|
||||
String::from_utf8_lossy(&a.outcome.stdout),
|
||||
String::from_utf8_lossy(&a.outcome.stderr)
|
||||
))
|
||||
.collect::<Vec<_>>()
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let (status, inconclusive_reason) = if run.triggered_by.is_some() {
|
||||
(VerifyStatus::Confirmed, None)
|
||||
} else if run.oracle_collision {
|
||||
|
|
@ -569,7 +589,7 @@ pub fn run_shape_fixture_lang(
|
|||
.map(|a| a.payload_label.to_owned()),
|
||||
reason: None,
|
||||
inconclusive_reason,
|
||||
detail: None,
|
||||
detail,
|
||||
attempts: vec![],
|
||||
toolchain_match: None,
|
||||
differential: None,
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
// Phase 14 fixture stub — minimal `@Autowired` annotation.
|
||||
// Lives in the default package so the fixture's @Autowired field
|
||||
// compiles under plain javac (no Spring Maven dep required).
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
|
||||
public @interface Autowired {
|
||||
}
|
||||
|
|
@ -1,15 +1,22 @@
|
|||
// Phase 14 — Spring `@RestController`, benign.
|
||||
// Spring `@RestController`, benign.
|
||||
//
|
||||
// Same shape as the vuln but the controller runs a fixed echo and
|
||||
// drops `payload`.
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/run")
|
||||
public class Benign {
|
||||
@Autowired
|
||||
private CommandRunner runner;
|
||||
|
||||
public String run(String payload) throws Exception {
|
||||
@GetMapping
|
||||
public String run(@RequestParam("payload") String payload) throws Exception {
|
||||
System.out.print("__NYX_SINK_HIT__\n");
|
||||
CommandRunner r = (runner != null) ? runner : new CommandRunner();
|
||||
String out = r.run("echo hello");
|
||||
|
|
|
|||
|
|
@ -1,11 +1,4 @@
|
|||
// Phase 14 fixture stub — Spring-injected helper service.
|
||||
// The fixture's controller declares `@Autowired CommandRunner runner;`
|
||||
// so the harness exercises the Phase 09 import-extraction path
|
||||
// (`@Autowired` is the marker that flags `org.springframework` as a
|
||||
// transitive dep). At runtime the harness instantiates the controller
|
||||
// via reflection's default ctor — the @Autowired field stays null
|
||||
// because there is no Spring container; the controller's handler
|
||||
// guards against null and constructs a fresh CommandRunner on demand.
|
||||
// Spring-injected helper service used by the controller fixtures.
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
// Phase 14 fixture stub — minimal Spring `@RequestMapping`.
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
public @interface RequestMapping {
|
||||
String value() default "";
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
// Phase 14 fixture stub — minimal Spring `@RestController`.
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface RestController {
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
// Phase 14 — Spring `@RestController`, vulnerable.
|
||||
//
|
||||
// Controller declares an `@Autowired CommandRunner` field so the
|
||||
// Phase 09 Java import-extractor sees the Spring annotation surface.
|
||||
// The harness instantiates the controller via reflection and invokes
|
||||
// `run(payload)`; the field stays null at runtime (no Spring DI), so
|
||||
// the handler constructs the helper on demand.
|
||||
// Spring `@RestController`, vulnerable.
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/run")
|
||||
|
|
@ -12,7 +12,8 @@ public class Vuln {
|
|||
@Autowired
|
||||
private CommandRunner runner;
|
||||
|
||||
public String run(String payload) throws Exception {
|
||||
@GetMapping
|
||||
public String run(@RequestParam("payload") String payload) throws Exception {
|
||||
System.out.print("__NYX_SINK_HIT__\n");
|
||||
CommandRunner r = (runner != null) ? runner : new CommandRunner();
|
||||
String out = r.run("echo hello " + payload);
|
||||
|
|
|
|||
|
|
@ -14,10 +14,26 @@
|
|||
<artifactId>spring-web</artifactId>
|
||||
<version>6.1.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>6.1.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>6.1.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>6.1.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<version>6.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -674,7 +674,7 @@ mod phase14_shape_tests {
|
|||
"Vuln.java",
|
||||
"run",
|
||||
Cap::CODE_EXEC,
|
||||
16,
|
||||
19,
|
||||
EntryKind::HttpRoute,
|
||||
PayloadSlot::Param(0),
|
||||
) else {
|
||||
|
|
@ -690,7 +690,7 @@ mod phase14_shape_tests {
|
|||
"Benign.java",
|
||||
"run",
|
||||
Cap::CODE_EXEC,
|
||||
14,
|
||||
22,
|
||||
EntryKind::HttpRoute,
|
||||
PayloadSlot::Param(0),
|
||||
) else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue