consolidate the tests locations

This commit is contained in:
StellaOps Bot
2025-12-26 01:48:24 +02:00
parent 17613acf57
commit 39359da171
2031 changed files with 2607 additions and 476 deletions

View File

@@ -1,48 +0,0 @@
id: "c-guarded-system:001"
language: c
project: guarded-system
version: "1.0.0"
description: "Command execution guarded by ALLOW_CMD flag (default unreachable)."
entrypoints:
- "main(argv)"
sinks:
- id: "GuardedSystem::main"
path: "src/main.c::main"
kind: "command"
location:
file: src/main.c
line: 26
notes: "system() only runs when ALLOW_CMD=1."
environment:
os_image: "gcc:13-bookworm"
runtime:
gcc: "13"
source_date_epoch: 1730000000
resource_limits:
cpu: "2"
memory: "4Gi"
build:
command: "./build/build.sh"
source_date_epoch: 1730000000
outputs:
artifact_path: outputs/binary.tar.gz
sbom_path: outputs/sbom.cdx.json
coverage_path: outputs/coverage.json
traces_dir: outputs/traces
attestation_path: outputs/attestation.json
test:
command: "./tests/run-tests.sh"
expected_coverage:
- outputs/coverage.json
expected_traces:
- outputs/traces/traces.json
ground_truth:
summary: "Without ALLOW_CMD, the system() sink remains unreachable; with ALLOW_CMD=1, it executes."
evidence_files:
- "../../../benchmark/truth/c-guarded-system.json"
sandbox:
network: loopback
privileges: rootless
redaction:
pii: false
policy: "benchmark-default/v1"

View File

@@ -1,7 +0,0 @@
case_id: "c-guarded-system:001"
entries:
cli:
- id: "main"
command: "./app"
args: ["<user_input>"]
description: "system() guarded by ALLOW_CMD flag"

View File

@@ -1,22 +0,0 @@
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicate": {
"buildType": "stub",
"builder": {
"id": "stub"
},
"metadata": {
"buildFinishedOn": "1970-01-01T00:00:00Z",
"buildStartedOn": "1970-01-01T00:00:00Z"
}
},
"predicateType": "https://slsa.dev/provenance/v0.2",
"subject": [
{
"digest": {
"sha256": "stub"
},
"name": "c-guarded-system:001"
}
]
}

View File

@@ -1,9 +0,0 @@
{
"files": [
{
"path": "src/main.c",
"functions": ["main", "run_guarded"],
"coverage": 1.0
}
]
}

View File

@@ -1,14 +0,0 @@
{
"bomFormat": "CycloneDX",
"components": [],
"metadata": {
"component": {
"name": "guarded-system",
"type": "application",
"version": "1.0.0"
},
"timestamp": "1970-01-01T00:00:00Z"
},
"specVersion": "1.5",
"version": 1
}

View File

@@ -1,6 +0,0 @@
{
"events": [
{"path": "src/main.c::main", "type": "entry"},
{"path": "src/main.c::run_guarded", "type": "call"}
]
}

View File

@@ -1,36 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int run_guarded(const char *user_cmd)
{
const char *allow = getenv("ALLOW_CMD");
if (allow == NULL || strcmp(allow, "1") != 0)
{
puts("command blocked (ALLOW_CMD not set)");
return 0;
}
char cmd[256];
snprintf(cmd, sizeof(cmd), "echo START && %s && echo END", user_cmd);
return system(cmd);
}
int main(int argc, char **argv)
{
if (argc < 2)
{
fprintf(stderr, "usage: %s <command>\n", argv[0]);
return 1;
}
int rc = run_guarded(argv[1]);
if (rc != 0)
{
fprintf(stderr, "command failed\n");
return 2;
}
puts("done");
return 0;
}

View File

@@ -1,32 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
OUT="${ROOT}/outputs"
APP="${OUT}/app"
if [[ ! -x "${APP}" ]]; then
echo "binary missing; run build first" >&2
exit 1
fi
tmp="$(mktemp -d)"
trap 'rm -rf "${tmp}"' EXIT
# Run without ALLOW_CMD: should be blocked
BLOCK_FILE="${tmp}/blocked.txt"
ALLOW_CMD=0 "${APP}" "echo SHOULD_NOT_RUN" > "${BLOCK_FILE}"
if grep -q "SHOULD_NOT_RUN" "${BLOCK_FILE}"; then
echo "command unexpectedly executed when ALLOW_CMD=0" >&2
exit 1
fi
# Run with ALLOW_CMD set: should execute
ALLOW_FILE="${tmp}/allow.txt"
ALLOW_CMD=1 "${APP}" "echo ALLOWED" > "${ALLOW_FILE}"
if ! grep -q "ALLOWED" "${ALLOW_FILE}"; then
echo "command did not execute when ALLOW_CMD=1" >&2
exit 1
fi
echo "tests passed"

View File

@@ -1,48 +0,0 @@
id: "c-memcpy-overflow:001"
language: c
project: memcpy-overflow
version: "1.0.0"
description: "Potential overflow: user-controlled length passed to memcpy without bounds."
entrypoints:
- "process_buffer(len)"
sinks:
- id: "Overflow::process"
path: "src/main.c::process"
kind: "memory"
location:
file: src/main.c
line: 23
notes: "memcpy uses attacker-controlled length; reachable via process_buffer."
environment:
os_image: "gcc:13-bookworm"
runtime:
gcc: "13"
source_date_epoch: 1730000000
resource_limits:
cpu: "2"
memory: "4Gi"
build:
command: "./build/build.sh"
source_date_epoch: 1730000000
outputs:
artifact_path: outputs/binary.tar.gz
sbom_path: outputs/sbom.cdx.json
coverage_path: outputs/coverage.json
traces_dir: outputs/traces
attestation_path: outputs/attestation.json
test:
command: "./tests/run-tests.sh"
expected_coverage:
- outputs/coverage.json
expected_traces:
- outputs/traces/traces.json
ground_truth:
summary: "Calling process_buffer with len>256 drives memcpy with attacker length (reachable)."
evidence_files:
- "../../../benchmark/truth/c-memcpy-overflow.json"
sandbox:
network: loopback
privileges: rootless
redaction:
pii: false
policy: "benchmark-default/v1"

View File

@@ -1,7 +0,0 @@
case_id: "c-memcpy-overflow:001"
entries:
cli:
- id: "process_buffer"
command: "./app"
args: ["<length>"]
description: "User length forwarded to memcpy without bounds"

View File

@@ -1,22 +0,0 @@
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicate": {
"buildType": "stub",
"builder": {
"id": "stub"
},
"metadata": {
"buildFinishedOn": "1970-01-01T00:00:00Z",
"buildStartedOn": "1970-01-01T00:00:00Z"
}
},
"predicateType": "https://slsa.dev/provenance/v0.2",
"subject": [
{
"digest": {
"sha256": "stub"
},
"name": "c-memcpy-overflow:001"
}
]
}

View File

@@ -1,9 +0,0 @@
{
"files": [
{
"path": "src/main.c",
"functions": ["main", "process"],
"coverage": 1.0
}
]
}

View File

@@ -1,14 +0,0 @@
{
"bomFormat": "CycloneDX",
"components": [],
"metadata": {
"component": {
"name": "memcpy-overflow",
"type": "application",
"version": "1.0.0"
},
"timestamp": "1970-01-01T00:00:00Z"
},
"specVersion": "1.5",
"version": 1
}

View File

@@ -1,6 +0,0 @@
{
"events": [
{"path": "src/main.c::main", "type": "entry"},
{"path": "src/main.c::process", "type": "call"}
]
}

View File

@@ -1,38 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int process(size_t len)
{
char src[512];
char dst[128];
memset(src, 'A', sizeof(src));
memset(dst, 0, sizeof(dst));
// Attacker-controlled length; no bounds check.
memcpy(dst, src, len);
// Return first byte to keep optimizer from removing the copy.
return dst[0];
}
int main(int argc, char **argv)
{
if (argc < 2)
{
fprintf(stderr, "usage: %s <len>\n", argv[0]);
return 1;
}
char *end = NULL;
long len = strtol(argv[1], &end, 10);
if (end == argv[1] || len < 0)
{
fprintf(stderr, "invalid length\n");
return 1;
}
int r = process((size_t)len);
printf("result=%d\n", r);
return 0;
}

View File

@@ -1,25 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
OUT="${ROOT}/outputs"
APP="${OUT}/app"
if [[ ! -x "${APP}" ]]; then
echo "binary missing; run build first" >&2
exit 1
fi
tmp="$(mktemp -d)"
trap 'rm -rf "${tmp}"' EXIT
# Trigger overflow-prone copy with large length; expect exit code 0
RUN_OUT="${tmp}/run.out"
"${APP}" "300" > "${RUN_OUT}"
if ! grep -q "result=" "${RUN_OUT}"; then
echo "expected output missing" >&2
exit 1
fi
echo "tests passed"

View File

@@ -1,48 +0,0 @@
id: "c-unsafe-system:001"
language: c
project: unsafe-system
version: "1.0.0"
description: "Command injection sink: user input passed directly to system()."
entrypoints:
- "main(argv)"
sinks:
- id: "UnsafeSystem::main"
path: "src/main.c::main"
kind: "command"
location:
file: src/main.c
line: 21
notes: "Untrusted input concatenated into shell command and executed."
environment:
os_image: "gcc:13-bookworm"
runtime:
gcc: "13"
source_date_epoch: 1730000000
resource_limits:
cpu: "2"
memory: "4Gi"
build:
command: "./build/build.sh"
source_date_epoch: 1730000000
outputs:
artifact_path: outputs/binary.tar.gz
sbom_path: outputs/sbom.cdx.json
coverage_path: outputs/coverage.json
traces_dir: outputs/traces
attestation_path: outputs/attestation.json
test:
command: "./tests/run-tests.sh"
expected_coverage:
- outputs/coverage.json
expected_traces:
- outputs/traces/traces.json
ground_truth:
summary: "Running with argument 'echo OK' executes system() with user-controlled payload."
evidence_files:
- "../../../benchmark/truth/c-unsafe-system.json"
sandbox:
network: loopback
privileges: rootless
redaction:
pii: false
policy: "benchmark-default/v1"

View File

@@ -1,7 +0,0 @@
case_id: "c-unsafe-system:001"
entries:
cli:
- id: "main"
command: "./app"
args: ["<user_input>"]
description: "Passes argv directly into system()"

View File

@@ -1,22 +0,0 @@
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicate": {
"buildType": "stub",
"builder": {
"id": "stub"
},
"metadata": {
"buildFinishedOn": "1970-01-01T00:00:00Z",
"buildStartedOn": "1970-01-01T00:00:00Z"
}
},
"predicateType": "https://slsa.dev/provenance/v0.2",
"subject": [
{
"digest": {
"sha256": "stub"
},
"name": "c-unsafe-system:001"
}
]
}

View File

@@ -1,9 +0,0 @@
{
"files": [
{
"path": "src/main.c",
"functions": ["main", "run_command"],
"coverage": 1.0
}
]
}

View File

@@ -1,14 +0,0 @@
{
"bomFormat": "CycloneDX",
"components": [],
"metadata": {
"component": {
"name": "unsafe-system",
"type": "application",
"version": "1.0.0"
},
"timestamp": "1970-01-01T00:00:00Z"
},
"specVersion": "1.5",
"version": 1
}

View File

@@ -1,6 +0,0 @@
{
"events": [
{"path": "src/main.c::main", "type": "entry"},
{"path": "src/main.c::run_command", "type": "call"}
]
}

View File

@@ -1,30 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int run_command(const char *user_cmd)
{
char cmd[256];
// Deliberately unsafe: user input embedded directly.
snprintf(cmd, sizeof(cmd), "echo START && %s && echo END", user_cmd);
return system(cmd);
}
int main(int argc, char **argv)
{
if (argc < 2)
{
fprintf(stderr, "usage: %s <command>\n", argv[0]);
return 1;
}
int rc = run_command(argv[1]);
if (rc != 0)
{
fprintf(stderr, "command failed\n");
return 2;
}
puts("done");
return 0;
}

View File

@@ -1,26 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
OUT="${ROOT}/outputs"
APP="${OUT}/app"
if [[ ! -x "${APP}" ]]; then
echo "binary missing; run build first" >&2
exit 1
fi
tmp="$(mktemp -d)"
trap 'rm -rf "${tmp}"' EXIT
# Run command and capture output deterministically
pushd "${tmp}" >/dev/null
"${APP}" "echo OK" > "${tmp}/run.out"
popd >/dev/null
if ! grep -q "OK" "${tmp}/run.out"; then
echo "expected command output not found" >&2
exit 1
fi
echo "tests passed"

View File

@@ -1,46 +0,0 @@
id: "go-gin-exec:301"
language: go
project: gin-exec
version: "1.0.0"
description: "Command injection sink reachable via GET /run in Gin handler"
entrypoints:
- "GET /run"
sinks:
- id: "CommandInjection::handleRun"
path: "main.handleRun"
kind: "custom"
location:
file: main.go
line: 22
notes: "os/exec.Command with user-controlled input"
environment:
os_image: "golang:1.22-alpine"
runtime:
go: "1.22"
source_date_epoch: 1730000000
resource_limits:
cpu: "2"
memory: "2Gi"
build:
command: "go build -o outputs/app ."
source_date_epoch: 1730000000
outputs:
artifact_path: outputs/app
sbom_path: outputs/sbom.cdx.json
coverage_path: outputs/coverage.json
traces_dir: outputs/traces
attestation_path: outputs/attestation.json
test:
command: "go test -v ./..."
expected_coverage: []
expected_traces: []
ground_truth:
summary: "Command injection reachable"
evidence_files:
- "../benchmark/truth/go-gin-exec.json"
sandbox:
network: loopback
privileges: rootless
redaction:
pii: false
policy: "benchmark-default/v1"

View File

@@ -1,8 +0,0 @@
case_id: "go-gin-exec:301"
entries:
http:
- id: "GET /run"
route: "/run"
method: "GET"
handler: "main.handleRun"
description: "Executes shell command from query parameter"

View File

@@ -1,5 +0,0 @@
module gin-exec
go 1.22
require github.com/gin-gonic/gin v1.10.0

View File

@@ -1,41 +0,0 @@
// gin-exec benchmark case
// Demonstrates command injection sink reachable via Gin HTTP handler
package main
import (
"net/http"
"os/exec"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/run", handleRun)
r.GET("/health", handleHealth)
r.Run(":8080")
}
// handleRun - VULNERABLE: command injection sink
// User-controlled input passed directly to exec.Command
func handleRun(c *gin.Context) {
cmd := c.Query("cmd")
if cmd == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "missing cmd parameter"})
return
}
// SINK: os/exec.Command with user-controlled input
output, err := exec.Command("sh", "-c", cmd).Output()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"output": string(output)})
}
// handleHealth - safe endpoint, no sinks
func handleHealth(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "ok"})
}

View File

@@ -1,37 +0,0 @@
package main
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
)
func TestHandleHealth(t *testing.T) {
gin.SetMode(gin.TestMode)
r := gin.Default()
r.GET("/health", handleHealth)
req, _ := http.NewRequest("GET", "/health", nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Errorf("Expected status 200, got %d", w.Code)
}
}
func TestHandleRunMissingCmd(t *testing.T) {
gin.SetMode(gin.TestMode)
r := gin.Default()
r.GET("/run", handleRun)
req, _ := http.NewRequest("GET", "/run", nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("Expected status 400, got %d", w.Code)
}
}

View File

@@ -1 +0,0 @@
# Keep this directory for build outputs

View File

@@ -1,46 +0,0 @@
id: "go-grpc-sql:302"
language: go
project: grpc-sql
version: "1.0.0"
description: "SQL injection sink reachable via gRPC GetUser method"
entrypoints:
- "grpc:UserService.GetUser"
sinks:
- id: "SqlInjection::GetUser"
path: "main.(*userServer).GetUser"
kind: "custom"
location:
file: main.go
line: 35
notes: "database/sql.Query with string concatenation"
environment:
os_image: "golang:1.22-alpine"
runtime:
go: "1.22"
source_date_epoch: 1730000000
resource_limits:
cpu: "2"
memory: "2Gi"
build:
command: "go build -o outputs/app ."
source_date_epoch: 1730000000
outputs:
artifact_path: outputs/app
sbom_path: outputs/sbom.cdx.json
coverage_path: outputs/coverage.json
traces_dir: outputs/traces
attestation_path: outputs/attestation.json
test:
command: "go test -v ./..."
expected_coverage: []
expected_traces: []
ground_truth:
summary: "SQL injection reachable"
evidence_files:
- "../benchmark/truth/go-grpc-sql.json"
sandbox:
network: loopback
privileges: rootless
redaction:
pii: false
policy: "benchmark-default/v1"

View File

@@ -1,8 +0,0 @@
case_id: "go-grpc-sql:302"
entries:
grpc:
- id: "grpc:UserService.GetUser"
service: "UserService"
method: "GetUser"
handler: "main.(*userServer).GetUser"
description: "Fetches user by ID with SQL injection vulnerability"

View File

@@ -1,8 +0,0 @@
module grpc-sql
go 1.22
require (
google.golang.org/grpc v1.64.0
google.golang.org/protobuf v1.34.2
)

View File

@@ -1,86 +0,0 @@
// grpc-sql benchmark case
// Demonstrates SQL injection sink reachable via gRPC handler
package main
import (
"context"
"database/sql"
"fmt"
"log"
"net"
_ "github.com/mattn/go-sqlite3"
"google.golang.org/grpc"
)
// User represents a user record
type User struct {
ID string
Name string
Email string
}
// userServer implements the gRPC UserService
type userServer struct {
db *sql.DB
}
// GetUser - VULNERABLE: SQL injection sink
// User ID is concatenated directly into SQL query
func (s *userServer) GetUser(ctx context.Context, userID string) (*User, error) {
// SINK: database/sql.Query with string concatenation
query := fmt.Sprintf("SELECT id, name, email FROM users WHERE id = '%s'", userID)
row := s.db.QueryRow(query)
var user User
if err := row.Scan(&user.ID, &user.Name, &user.Email); err != nil {
return nil, fmt.Errorf("user not found: %w", err)
}
return &user, nil
}
// GetUserSafe - SAFE: uses parameterized query
func (s *userServer) GetUserSafe(ctx context.Context, userID string) (*User, error) {
query := "SELECT id, name, email FROM users WHERE id = ?"
row := s.db.QueryRow(query, userID)
var user User
if err := row.Scan(&user.ID, &user.Name, &user.Email); err != nil {
return nil, fmt.Errorf("user not found: %w", err)
}
return &user, nil
}
func main() {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
log.Fatalf("failed to open database: %v", err)
}
defer db.Close()
// Initialize schema
_, err = db.Exec(`
CREATE TABLE users (
id TEXT PRIMARY KEY,
name TEXT,
email TEXT
)
`)
if err != nil {
log.Fatalf("failed to create table: %v", err)
}
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
// Register service here (simplified for benchmark)
log.Printf("gRPC server listening on %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}

View File

@@ -1,56 +0,0 @@
package main
import (
"context"
"database/sql"
"testing"
_ "github.com/mattn/go-sqlite3"
)
func setupTestDB(t *testing.T) *sql.DB {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
t.Fatalf("failed to open database: %v", err)
}
_, err = db.Exec(`
CREATE TABLE users (
id TEXT PRIMARY KEY,
name TEXT,
email TEXT
);
INSERT INTO users (id, name, email) VALUES ('1', 'Alice', 'alice@example.com');
`)
if err != nil {
t.Fatalf("failed to setup test data: %v", err)
}
return db
}
func TestGetUserSafe(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
server := &userServer{db: db}
user, err := server.GetUserSafe(context.Background(), "1")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if user.Name != "Alice" {
t.Errorf("expected Alice, got %s", user.Name)
}
}
func TestGetUserNotFound(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
server := &userServer{db: db}
_, err := server.GetUserSafe(context.Background(), "999")
if err == nil {
t.Error("expected error for non-existent user")
}
}

View File

@@ -1 +0,0 @@
# Keep this directory for build outputs

View File

@@ -1,48 +0,0 @@
id: "java-micronaut-deserialize:203"
language: java
project: micronaut-deserialize
version: "1.0.0"
description: "Micronaut-style controller performs unsafe deserialization on request payload"
entrypoints:
- "POST /mn/upload"
sinks:
- id: "MicronautDeserialize::handleUpload"
path: "bench.reachability.micronaut.Controller.handleUpload"
kind: "custom"
location:
file: src/Controller.java
line: 10
notes: "ObjectInputStream on user-controlled payload"
environment:
os_image: "eclipse-temurin:21-jdk"
runtime:
java: "21"
source_date_epoch: 1730000000
resource_limits:
cpu: "2"
memory: "4Gi"
build:
command: "./build/build.sh"
source_date_epoch: 1730000000
outputs:
artifact_path: outputs/binary.tar.gz
sbom_path: outputs/sbom.cdx.json
coverage_path: outputs/coverage.json
traces_dir: outputs/traces
attestation_path: outputs/attestation.json
test:
command: "./build/build.sh"
expected_coverage: []
expected_traces: []
env:
JAVA_TOOL_OPTIONS: "-ea"
ground_truth:
summary: "Deserialization reachable"
evidence_files:
- "../benchmark/truth/java-micronaut-deserialize.json"
sandbox:
network: loopback
privileges: rootless
redaction:
pii: false
policy: "benchmark-default/v1"

View File

@@ -1,8 +0,0 @@
case_id: "java-micronaut-deserialize:203"
entries:
http:
- id: "POST /mn/upload"
route: "/mn/upload"
method: "POST"
handler: "Controller.handleUpload"
description: "Binary payload base64-deserialized"

View File

@@ -1,22 +0,0 @@
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicate": {
"buildType": "stub",
"builder": {
"id": "stub"
},
"metadata": {
"buildFinishedOn": "1970-01-01T00:00:00Z",
"buildStartedOn": "1970-01-01T00:00:00Z"
}
},
"predicateType": "https://slsa.dev/provenance/v0.2",
"subject": [
{
"digest": {
"sha256": "stub"
},
"name": "java-micronaut-deserialize:203"
}
]
}

View File

@@ -1,13 +0,0 @@
{
"files": {
"src/Controller.java": {
"lines_covered": [
11,
14,
15,
17
],
"lines_total": 40
}
}
}

View File

@@ -1,14 +0,0 @@
{
"bomFormat": "CycloneDX",
"components": [],
"metadata": {
"component": {
"name": "micronaut-deserialize",
"type": "application",
"version": "1.0.0"
},
"timestamp": "1970-01-01T00:00:00Z"
},
"specVersion": "1.5",
"version": 1
}

View File

@@ -1,9 +0,0 @@
{
"entry": "POST /mn/upload",
"notes": "Base64 payload flows into ObjectInputStream without guard",
"path": [
"Controller.handleUpload",
"ObjectInputStream.readObject"
],
"sink": "MicronautDeserialize::handleUpload"
}

View File

@@ -1,12 +0,0 @@
<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>org.stellaops.bench</groupId>
<artifactId>micronaut-deserialize</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
</project>

View File

@@ -1,24 +0,0 @@
package bench.reachability.micronaut;
import java.util.Map;
import java.util.Base64;
import java.io.*;
public class Controller {
// Unsafe deserialization sink (reachable)
public static Response handleUpload(Map<String, String> body) {
String payload = body.get("payload");
if (payload == null) {
return new Response(400, "bad request");
}
try (ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(Base64.getDecoder().decode(payload)))) {
Object obj = ois.readObject();
return new Response(200, obj.toString());
} catch (Exception ex) {
return new Response(500, ex.getClass().getSimpleName());
}
}
public record Response(int status, String body) {}
}

View File

@@ -1,29 +0,0 @@
package bench.reachability.micronaut;
import java.io.*;
import java.util.*;
import java.util.Base64;
// Simple assertion-based oracle (JUnit-free for offline determinism)
public class ControllerTest {
private static String serialize(Object obj) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(obj);
}
return Base64.getEncoder().encodeToString(bos.toByteArray());
}
public static void main(String[] args) throws Exception {
Map<String, String> body = Map.of("payload", serialize("micronaut"));
var res = Controller.handleUpload(body);
assert res.status() == 200 : "status";
assert res.body().equals("micronaut") : "body";
File outDir = new File("outputs");
outDir.mkdirs();
try (FileWriter fw = new FileWriter(new File(outDir, "SINK_REACHED"))) {
fw.write("true");
}
}
}

View File

@@ -1,48 +0,0 @@
id: "java-micronaut-guarded:204"
language: java
project: micronaut-guarded
version: "1.0.0"
description: "Micronaut-style controller guards deserialization behind ALLOW_MN_DESER flag (unreachable by default)"
entrypoints:
- "POST /mn/upload"
sinks:
- id: "MicronautDeserializeGuarded::handleUpload"
path: "bench.reachability.micronautguard.Controller.handleUpload"
kind: "custom"
location:
file: src/Controller.java
line: 11
notes: "ObjectInputStream gated by ALLOW_MN_DESER"
environment:
os_image: "eclipse-temurin:21-jdk"
runtime:
java: "21"
source_date_epoch: 1730000000
resource_limits:
cpu: "2"
memory: "4Gi"
build:
command: "./build/build.sh"
source_date_epoch: 1730000000
outputs:
artifact_path: outputs/binary.tar.gz
sbom_path: outputs/sbom.cdx.json
coverage_path: outputs/coverage.json
traces_dir: outputs/traces
attestation_path: outputs/attestation.json
test:
command: "./build/build.sh"
expected_coverage: []
expected_traces: []
env:
JAVA_TOOL_OPTIONS: "-ea"
ground_truth:
summary: "Guard blocks deserialization unless ALLOW_MN_DESER=true"
evidence_files:
- "../benchmark/truth/java-micronaut-guarded.json"
sandbox:
network: loopback
privileges: rootless
redaction:
pii: false
policy: "benchmark-default/v1"

View File

@@ -1,8 +0,0 @@
case_id: "java-micronaut-guarded:204"
entries:
http:
- id: "POST /mn/upload"
route: "/mn/upload"
method: "POST"
handler: "Controller.handleUpload"
description: "Deserialization guarded by ALLOW_MN_DESER flag"

View File

@@ -1,22 +0,0 @@
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicate": {
"buildType": "stub",
"builder": {
"id": "stub"
},
"metadata": {
"buildFinishedOn": "1970-01-01T00:00:00Z",
"buildStartedOn": "1970-01-01T00:00:00Z"
}
},
"predicateType": "https://slsa.dev/provenance/v0.2",
"subject": [
{
"digest": {
"sha256": "stub"
},
"name": "java-micronaut-guarded:204"
}
]
}

View File

@@ -1,13 +0,0 @@
{
"files": {
"src/Controller.java": {
"lines_covered": [
12,
13,
15,
17
],
"lines_total": 42
}
}
}

View File

@@ -1,14 +0,0 @@
{
"bomFormat": "CycloneDX",
"components": [],
"metadata": {
"component": {
"name": "micronaut-guarded",
"type": "application",
"version": "1.0.0"
},
"timestamp": "1970-01-01T00:00:00Z"
},
"specVersion": "1.5",
"version": 1
}

View File

@@ -1,8 +0,0 @@
{
"entry": "POST /mn/upload",
"notes": "Guard enforces ALLOW_MN_DESER feature flag; sink not reached by default",
"path": [
"Controller.handleUpload"
],
"sink": "MicronautDeserializeGuarded::handleUpload"
}

View File

@@ -1,12 +0,0 @@
<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>org.stellaops.bench</groupId>
<artifactId>micronaut-guarded</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
</project>

View File

@@ -1,27 +0,0 @@
package bench.reachability.micronautguard;
import java.util.Map;
import java.util.Base64;
import java.io.*;
public class Controller {
// Deserialization behind feature flag; unreachable unless ALLOW_MN_DESER=true
public static Response handleUpload(Map<String, String> body, Map<String, String> env) {
if (!"true".equals(env.getOrDefault("ALLOW_MN_DESER", "false"))) {
return new Response(403, "forbidden");
}
String payload = body.get("payload");
if (payload == null) {
return new Response(400, "bad request");
}
try (ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(Base64.getDecoder().decode(payload)))) {
Object obj = ois.readObject();
return new Response(200, obj.toString());
} catch (Exception ex) {
return new Response(500, ex.getClass().getSimpleName());
}
}
public record Response(int status, String body) {}
}

View File

@@ -1,29 +0,0 @@
package bench.reachability.micronautguard;
import java.io.*;
import java.util.*;
import java.util.Base64;
public class ControllerTest {
private static String serialize(Object obj) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(obj);
}
return Base64.getEncoder().encodeToString(bos.toByteArray());
}
public static void main(String[] args) throws Exception {
Map<String, String> body = Map.of("payload", serialize("blocked"));
Map<String, String> env = Map.of("ALLOW_MN_DESER", "false");
var res = Controller.handleUpload(body, env);
assert res.status() == 403 : "status";
assert res.body().equals("forbidden") : "body";
File outDir = new File("outputs");
outDir.mkdirs();
try (FileWriter fw = new FileWriter(new File(outDir, "SINK_BLOCKED"))) {
fw.write("true");
}
}
}

View File

@@ -1,48 +0,0 @@
id: "java-spring-deserialize:201"
language: java
project: spring-deserialize
version: "1.0.0"
description: "Java deserialization sink reachable via POST /api/upload"
entrypoints:
- "POST /api/upload"
sinks:
- id: "JavaDeserialize::handleRequest"
path: "bench.reachability.App.handleRequest"
kind: "custom"
location:
file: src/App.java
line: 9
notes: "java.io.ObjectInputStream on user-controlled payload"
environment:
os_image: "eclipse-temurin:21-jdk"
runtime:
java: "21"
source_date_epoch: 1730000000
resource_limits:
cpu: "2"
memory: "4Gi"
build:
command: "./build/build.sh"
source_date_epoch: 1730000000
outputs:
artifact_path: outputs/binary.tar.gz
sbom_path: outputs/sbom.cdx.json
coverage_path: outputs/coverage.json
traces_dir: outputs/traces
attestation_path: outputs/attestation.json
test:
command: "./build/build.sh"
expected_coverage: []
expected_traces: []
env:
JAVA_TOOL_OPTIONS: "-ea"
ground_truth:
summary: "Deserialization reachable"
evidence_files:
- "../benchmark/truth/java-spring-deserialize.json"
sandbox:
network: loopback
privileges: rootless
redaction:
pii: false
policy: "benchmark-default/v1"

View File

@@ -1,8 +0,0 @@
case_id: "java-spring-deserialize:201"
entries:
http:
- id: "POST /api/upload"
route: "/api/upload"
method: "POST"
handler: "App.handleRequest"
description: "Binary payload base64-deserialized"

View File

@@ -1,22 +0,0 @@
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicate": {
"buildType": "stub",
"builder": {
"id": "stub"
},
"metadata": {
"buildFinishedOn": "1970-01-01T00:00:00Z",
"buildStartedOn": "1970-01-01T00:00:00Z"
}
},
"predicateType": "https://slsa.dev/provenance/v0.2",
"subject": [
{
"digest": {
"sha256": "stub"
},
"name": "java-spring-deserialize:201"
}
]
}

View File

@@ -1,14 +0,0 @@
{
"files": {
"src/App.java": {
"lines_covered": [
9,
15,
16,
17,
19
],
"lines_total": 26
}
}
}

View File

@@ -1,14 +0,0 @@
{
"bomFormat": "CycloneDX",
"components": [],
"metadata": {
"component": {
"name": "spring-deserialize",
"type": "application",
"version": "1.0.0"
},
"timestamp": "1970-01-01T00:00:00Z"
},
"specVersion": "1.5",
"version": 1
}

View File

@@ -1,9 +0,0 @@
{
"entry": "POST /api/upload",
"notes": "No guard; base64 payload deserialized",
"path": [
"App.handleRequest",
"ObjectInputStream.readObject"
],
"sink": "JavaDeserialize::handleRequest"
}

View File

@@ -1,12 +0,0 @@
<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>org.stellaops.bench</groupId>
<artifactId>spring-deserialize</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
</project>

View File

@@ -1,26 +0,0 @@
package bench.reachability;
import java.util.Map;
import java.util.Base64;
import java.io.*;
public class App {
// Unsafe Java deserialization sink (reachable)
public static Response handleRequest(Map<String, String> body) {
String payload = body.get("payload");
if (payload == null) {
return new Response(400, "bad request");
}
try {
byte[] data = Base64.getDecoder().decode(payload);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
Object obj = ois.readObject();
ois.close();
return new Response(200, obj.toString());
} catch (Exception ex) {
return new Response(500, ex.getClass().getSimpleName());
}
}
public record Response(int status, String body) {}
}

View File

@@ -1,30 +0,0 @@
package bench.reachability;
import java.io.*;
import java.util.*;
import java.util.Base64;
// Simple hand-rolled test harness (no external deps) using Java assertions.
public class AppTest {
private static String serialize(Object obj) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.close();
return Base64.getEncoder().encodeToString(bos.toByteArray());
}
public static void main(String[] args) throws Exception {
String payload = serialize("hello");
Map<String, String> body = Map.of("payload", payload);
var res = App.handleRequest(body);
assert res.status() == 200 : "status";
assert res.body().equals("hello") : "body";
// Emit a simple marker file for trace/coverage stand-ins
File outDir = new File("outputs");
outDir.mkdirs();
try (FileWriter fw = new FileWriter(new File(outDir, "SINK_REACHED"))) {
fw.write("true");
}
}
}

View File

@@ -1,48 +0,0 @@
id: "java-spring-guarded:202"
language: java
project: spring-guarded
version: "1.0.0"
description: "Java deserialization guarded by ALLOW_DESER flag (unreachable by default)"
entrypoints:
- "POST /api/upload"
sinks:
- id: "JavaDeserializeGuarded::handleRequest"
path: "bench.reachability.App.handleRequest"
kind: "custom"
location:
file: src/App.java
line: 9
notes: "ObjectInputStream gated by ALLOW_DESER"
environment:
os_image: "eclipse-temurin:21-jdk"
runtime:
java: "21"
source_date_epoch: 1730000000
resource_limits:
cpu: "2"
memory: "4Gi"
build:
command: "./build/build.sh"
source_date_epoch: 1730000000
outputs:
artifact_path: outputs/binary.tar.gz
sbom_path: outputs/sbom.cdx.json
coverage_path: outputs/coverage.json
traces_dir: outputs/traces
attestation_path: outputs/attestation.json
test:
command: "./build/build.sh"
expected_coverage: []
expected_traces: []
env:
JAVA_TOOL_OPTIONS: "-ea"
ground_truth:
summary: "Guard blocks deserialization unless ALLOW_DESER=true"
evidence_files:
- "../benchmark/truth/java-spring-guarded.json"
sandbox:
network: loopback
privileges: rootless
redaction:
pii: false
policy: "benchmark-default/v1"

View File

@@ -1,8 +0,0 @@
case_id: "java-spring-guarded:202"
entries:
http:
- id: "POST /api/upload"
route: "/api/upload"
method: "POST"
handler: "App.handleRequest"
description: "Base64 payload deserialization guarded by ALLOW_DESER"

View File

@@ -1,22 +0,0 @@
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicate": {
"buildType": "stub",
"builder": {
"id": "stub"
},
"metadata": {
"buildFinishedOn": "1970-01-01T00:00:00Z",
"buildStartedOn": "1970-01-01T00:00:00Z"
}
},
"predicateType": "https://slsa.dev/provenance/v0.2",
"subject": [
{
"digest": {
"sha256": "stub"
},
"name": "java-spring-guarded:202"
}
]
}

View File

@@ -1,13 +0,0 @@
{
"files": {
"src/App.java": {
"lines_covered": [
10,
11,
13,
15
],
"lines_total": 29
}
}
}

View File

@@ -1,14 +0,0 @@
{
"bomFormat": "CycloneDX",
"components": [],
"metadata": {
"component": {
"name": "spring-guarded",
"type": "application",
"version": "1.0.0"
},
"timestamp": "1970-01-01T00:00:00Z"
},
"specVersion": "1.5",
"version": 1
}

View File

@@ -1,8 +0,0 @@
{
"entry": "POST /api/upload",
"notes": "Guard requires ALLOW_DESER=true; sink not executed by default",
"path": [
"App.handleRequest"
],
"sink": "JavaDeserializeGuarded::handleRequest"
}

View File

@@ -1,12 +0,0 @@
<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>org.stellaops.bench</groupId>
<artifactId>spring-guarded</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
</project>

View File

@@ -1,29 +0,0 @@
package bench.reachability;
import java.util.Map;
import java.util.Base64;
import java.io.*;
public class App {
// Deserialization sink guarded by feature flag
public static Response handleRequest(Map<String, String> body, Map<String, String> env) {
if (!"true".equals(env.getOrDefault("ALLOW_DESER", "false"))) {
return new Response(403, "forbidden");
}
String payload = body.get("payload");
if (payload == null) {
return new Response(400, "bad request");
}
try {
byte[] data = Base64.getDecoder().decode(payload);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
Object obj = ois.readObject();
ois.close();
return new Response(200, obj.toString());
} catch (Exception ex) {
return new Response(500, ex.getClass().getSimpleName());
}
}
public record Response(int status, String body) {}
}

View File

@@ -1,29 +0,0 @@
package bench.reachability;
import java.io.*;
import java.util.*;
import java.util.Base64;
public class AppTest {
private static String serialize(Object obj) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.close();
return Base64.getEncoder().encodeToString(bos.toByteArray());
}
public static void main(String[] args) throws Exception {
String payload = serialize("hi");
Map<String, String> body = Map.of("payload", payload);
Map<String, String> env = Map.of("ALLOW_DESER", "false");
var res = App.handleRequest(body, env);
assert res.status() == 403 : "status";
assert res.body().equals("forbidden") : "body";
File outDir = new File("outputs");
outDir.mkdirs();
try (FileWriter fw = new FileWriter(new File(outDir, "SINK_BLOCKED"))) {
fw.write("true");
}
}
}

View File

@@ -1,48 +0,0 @@
id: "java-spring-reflection:205"
language: java
project: spring-reflection
version: "1.0.0"
description: "Spring-style controller exposes reflection endpoint that loads arbitrary classes"
entrypoints:
- "POST /api/reflect"
sinks:
- id: "SpringReflection::run"
path: "bench.reachability.springreflection.ReflectController.run"
kind: "custom"
location:
file: src/ReflectController.java
line: 7
notes: "User-controlled Class.forName + newInstance"
environment:
os_image: "eclipse-temurin:21-jdk"
runtime:
java: "21"
source_date_epoch: 1730000000
resource_limits:
cpu: "2"
memory: "4Gi"
build:
command: "./build/build.sh"
source_date_epoch: 1730000000
outputs:
artifact_path: outputs/binary.tar.gz
sbom_path: outputs/sbom.cdx.json
coverage_path: outputs/coverage.json
traces_dir: outputs/traces
attestation_path: outputs/attestation.json
test:
command: "./build/build.sh"
expected_coverage: []
expected_traces: []
env:
JAVA_TOOL_OPTIONS: "-ea"
ground_truth:
summary: "Reflection sink reachable with user-controlled class name"
evidence_files:
- "../benchmark/truth/java-spring-reflection.json"
sandbox:
network: loopback
privileges: rootless
redaction:
pii: false
policy: "benchmark-default/v1"

View File

@@ -1,8 +0,0 @@
case_id: "java-spring-reflection:205"
entries:
http:
- id: "POST /api/reflect"
route: "/api/reflect"
method: "POST"
handler: "ReflectController.run"
description: "Reflection endpoint loads arbitrary classes"

Some files were not shown because too many files have changed in this diff Show More