diff --git a/.github/workflows/security-scan-full.yml b/.github/workflows/security-scan-full.yml new file mode 100644 index 0000000..d74498a --- /dev/null +++ b/.github/workflows/security-scan-full.yml @@ -0,0 +1,67 @@ +name: OpenTaint + ZAP Security Scan (Full Mode) + +on: + push + +permissions: + contents: read + security-events: write + +jobs: + security-scan: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + + - name: Build application + run: ./gradlew build -x test + + - name: Start Spring Boot application + run: | + ./gradlew bootRun > app.log 2>&1 & + echo $! > app.pid + + # Wait for application to be ready + echo "Waiting for application to start..." + for i in {1..30}; do + if curl -s http://localhost:8081/v3/api-docs > /dev/null; then + echo "Application is ready!" + break + fi + echo "Waiting... ($i/30)" + sleep 2 + done + + if ! curl -s http://localhost:8081/v3/api-docs > /dev/null; then + echo "Application failed to start" + cat app.log + exit 1 + fi + + - name: Run OpenTaint + ZAP security scan + uses: seqra/opentaint/github/zap@misonijnik/zap-action + with: + mode: 'full' + template: 'template.yaml' + target: 'http://localhost:8081' + artifact-name: 'seqra-zap-scan-results' + upload-sarif: 'false' + zap-cmd-options: '-addonupdate -addoninstall ascanrulesBeta -addoninstall pscanrulesBeta' + + - name: Stop application + if: always() + run: | + if [ -f app.pid ]; then + kill $(cat app.pid) || true + rm app.pid + fi diff --git a/.github/workflows/security-scan-pr.yml b/.github/workflows/security-scan-pr.yml new file mode 100644 index 0000000..5607a12 --- /dev/null +++ b/.github/workflows/security-scan-pr.yml @@ -0,0 +1,68 @@ +name: OpenTaint + ZAP Security Scan + +on: + pull_request + +permissions: + contents: read + pull-requests: write + security-events: write + +jobs: + security-scan: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + + - name: Build application + run: ./gradlew build -x test + + - name: Start Spring Boot application + run: | + ./gradlew bootRun > app.log 2>&1 & + echo $! > app.pid + + # Wait for application to be ready + echo "Waiting for application to start..." + for i in {1..30}; do + if curl -s http://localhost:8081/v3/api-docs > /dev/null; then + echo "Application is ready!" + break + fi + echo "Waiting... ($i/30)" + sleep 2 + done + + if ! curl -s http://localhost:8081/v3/api-docs > /dev/null; then + echo "Application failed to start" + cat app.log + exit 1 + fi + + - name: Run OpenTaint + ZAP security scan + uses: seqra/opentaint/github/zap@misonijnik/zap-action + with: + mode: 'differential' + template: 'template.yaml' + target: 'http://localhost:8081' + artifact-name: 'seqra-zap-scan-results' + upload-sarif: 'true' + zap-cmd-options: '-addonupdate -addoninstall ascanrulesBeta -addoninstall pscanrulesBeta' + + - name: Stop application + if: always() + run: | + if [ -f app.pid ]; then + kill $(cat app.pid) || true + rm app.pid + fi diff --git a/.github/workflows/zap-scan.yml b/.github/workflows/zap-scan.yml new file mode 100644 index 0000000..4f203ab --- /dev/null +++ b/.github/workflows/zap-scan.yml @@ -0,0 +1,78 @@ +name: ZAP Full Scan + +on: + pull_request + +permissions: + contents: read + pull-requests: write + +jobs: + zap-scan: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + + - name: Build application + run: ./gradlew build -x test + + - name: Start Spring Boot application + run: | + ./gradlew bootRun > app.log 2>&1 & + echo $! > app.pid + + echo "Waiting for application to start..." + for i in {1..30}; do + if curl -s http://localhost:8081/v3/api-docs > /dev/null; then + echo "Application is ready!" + break + fi + echo "Waiting... ($i/30)" + sleep 2 + done + + if ! curl -s http://localhost:8081/v3/api-docs > /dev/null; then + echo "Application failed to start" + cat app.log + exit 1 + fi + + - name: Create output directory + run: | + mkdir -p zap-output + chmod 777 zap-output + + - name: Run ZAP Automation Framework scan + uses: zaproxy/action-af@v0.2.0 + continue-on-error: true + with: + plan: 'full-scan.yaml' + docker_name: 'ghcr.io/zaproxy/zaproxy:stable' + cmd_options: '-addonupdate -addoninstall ascanrulesBeta -addoninstall pscanrulesBeta' + + - name: Stop application + if: always() + run: | + if [ -f app.pid ]; then + kill $(cat app.pid) || true + rm app.pid + fi + + - name: Upload ZAP scan results + uses: actions/upload-artifact@v4 + if: always() + with: + name: zap-full-scan-results + path: zap-output/ + retention-days: 30 diff --git a/.zap/rules.tsv b/.zap/rules.tsv new file mode 100644 index 0000000..17d471c --- /dev/null +++ b/.zap/rules.tsv @@ -0,0 +1,119 @@ +# ZAP API Scan Rules Configuration + +# CWE-22: Path Traversal +6 WARN (Path Traversal - Active/release) + +# CWE-78: OS Command Injection +10048 WARN (Remote Code Execution - Shell Shock - Active/beta) +40045 IGNORE (Spring4Shell - Active/beta) +40048 IGNORE (Remote Code Execution - CVE-2021-44228 - Active/beta) +90020 WARN (Remote OS Command Injection - Active/release) +90037 IGNORE (Server Side Template Injection - Active/beta) + +# CWE-79: Cross-Site Scripting (XSS) +40012 WARN (Cross Site Scripting (Reflected) - Active/release) +40026 IGNORE (Cross Site Scripting (DOM Based) - Active/release) +40031 IGNORE (Cross Site Scripting (Persistent) - Active/release) + +# CWE-89: SQL Injection +40018 WARN (SQL Injection - Active/release) +40019 WARN (SQL Injection - MySQL - Active/beta) +40020 WARN (SQL Injection - Hypersonic SQL - Active/beta) +40021 WARN (SQL Injection - Oracle - Active/beta) +40022 WARN (SQL Injection - PostgreSQL - Active/beta) +40027 IGNORE (SQL Injection - SQLite - Active/beta) + +# CWE-94: Code Injection +40028 WARN (ELMAH Information Leak - Active/beta) +40032 IGNORE (.htaccess Information Leak - Active/beta) +90019 WARN (Server Side Code Injection - Active/release) + +# CWE-113: CRLF Injection +40003 WARN (CRLF Injection - Active/release) + +# CWE-117: Log Injection +40043 IGNORE (Log4Shell - Active/beta) +40047 IGNORE (CORS Header - Active/beta) + +# CWE-352: CSRF +20012 WARN (Anti CSRF Tokens Scanner - Active/beta) + +# CWE-601: Open Redirect +20019 WARN (External Redirect - Active/release) + +# CWE-611: XXE +90023 WARN (XML External Entity Attack - Active/beta) + +# CWE-643: XPath Injection +90021 WARN (XPath Injection - Active/beta) + +# CWE-917: Expression Language Injection +90025 WARN (Expression Language Injection - Active/beta) + +# CWE-918: SSRF +40046 IGNORE (SSRF - Active/beta) + +# CWE-943: NoSQL Injection +40033 IGNORE (NoSQL Injection - MongoDB - Active/beta) +90039 IGNORE (NoSQL Injection - Active/beta) + +# CWE-1336: Prototype Pollution +90035 IGNORE (Prototype Pollution - Active/beta) +90036 IGNORE (Prototype Pollution (Client Side) - Active/beta) + +# Additional passive scan rules to ignore +90003 IGNORE (Sub Resource Integrity Attribute Missing - Passive/release) +90004 IGNORE (Insufficient Site Isolation Against Spectre Vulnerability - Passive/release) + +# Disable all other active scan rules not listed above +0 IGNORE (Directory Browsing - Active/release) +2 IGNORE (Private IP Disclosure - Passive/release) +3 IGNORE (Session ID in URL Rewrite - Passive/release) +7 IGNORE (Remote File Inclusion - Active/release) +10010 IGNORE (Cookie No HttpOnly Flag - Passive/release) +10011 IGNORE (Cookie Without Secure Flag - Passive/release) +10012 IGNORE (Password Autocomplete in Browser - Passive/release) +10015 IGNORE (Incomplete or No Cache-control and Pragma HTTP Header Set - Passive/release) +10016 IGNORE (Web Browser XSS Protection Not Enabled - Passive/release) +10017 IGNORE (Cross-Domain JavaScript Source File Inclusion - Passive/release) +10019 IGNORE (Content-Type Header Missing - Passive/release) +10020 IGNORE (X-Frame-Options Header Scanner - Passive/release) +10021 IGNORE (X-Content-Type-Options Header Missing - Passive/release) +10023 IGNORE (Information Disclosure - Debug Error Messages - Passive/beta) +10024 IGNORE (Information Disclosure - Sensitive Informations in URL - Passive/beta) +10025 IGNORE (Information Disclosure - Sensitive Information in HTTP Referrer Header - Passive/beta) +10026 IGNORE (HTTP Parameter Override - Passive/beta) +10027 IGNORE (Information Disclosure - Suspicious Comments - Passive/beta) +10032 IGNORE (Viewstate Scanner - Passive/beta) +10040 IGNORE (Secure Pages Include Mixed Content - Passive/release) +10045 IGNORE (Source Code Disclosure - /WEB-INF folder - Active/beta) +10095 IGNORE (Backup File Disclosure - Active/beta) +10105 IGNORE (Weak Authentication Method - Passive/beta) +10202 IGNORE (Absence of Anti-CSRF Tokens - Passive/beta) +20014 IGNORE (HTTP Parameter Pollution scanner - Active/beta) +20015 IGNORE (Heartbleed OpenSSL Vulnerability - Active/beta) +20016 IGNORE (Cross-Domain Misconfiguration - Active/beta) +20017 IGNORE (Source Code Disclosure - CVE-2012-1823 - Active/beta) +20018 IGNORE (Remote Code Execution - CVE-2012-1823 - Active/beta) +30001 IGNORE (Buffer Overflow - Active/release) +30002 IGNORE (Format String Error - Active/release) +30003 IGNORE (Integer Overflow Error - Active/beta) +40008 IGNORE (Parameter Tampering - Active/release) +40009 IGNORE (Server Side Include - Active/release) +40013 IGNORE (Session Fixation - Active/beta) +40014 IGNORE (Cross Site Scripting (Persistent) - Active/release) +40016 IGNORE (Cross Site Scripting (Persistent) - Prime - Active/release) +40017 IGNORE (Cross Site Scripting (Persistent) - Spider - Active/release) +40023 IGNORE (Possible Username Enumeration - Active/beta) +42 IGNORE (Source Code Disclosure - SVN - Active/beta) +50000 IGNORE (Script Active Scan Rules - Active/release) +50001 IGNORE (Script Passive Scan Rules - Passive/release) +90001 IGNORE (Insecure JSF ViewState - Passive/beta) +90011 IGNORE (Charset Mismatch - Passive/beta) +90022 IGNORE (Application Error Disclosure - Passive/release) +90024 IGNORE (Generic Padding Oracle - Active/beta) +90026 IGNORE (SOAP Action Spoofing - Active/alpha) +90028 IGNORE (Insecure HTTP Method - Active/beta) +90029 IGNORE (SOAP XML Injection - Active/alpha) +90030 IGNORE (WSDL File Passive Scanner - Passive/alpha) +90033 IGNORE (Loosely Scoped Cookie - Passive/beta) diff --git a/full-scan.yaml b/full-scan.yaml new file mode 100644 index 0000000..063eb12 --- /dev/null +++ b/full-scan.yaml @@ -0,0 +1,180 @@ +env: + contexts: + - name: openapi-import + urls: + - http://localhost:8081 + includePaths: [] + excludePaths: + - http://localhost:8081/api/redirect/external$ + parameters: + failOnError: false + failOnWarning: false + continueOnFailure: true + progressToStdout: true +jobs: + - type: openapi + parameters: + context: openapi-import + targetUrl: http://localhost:8081 + apiUrl: http://localhost:8081/v3/api-docs + - type: activeScan-config + parameters: + maxRuleDurationInMins: 0 + maxScanDurationInMins: 0 + maxAlertsPerRule: 0 + threadPerHost: 40 + handleAntiCSRFTokens: true + injectPluginIdInHeader: true + inputVectors: + urlQueryStringAndDataDrivenNodes: + enabled: true + addParam: false + odata: true + postData: + enabled: true + multiPartFormData: true + xml: true + json: + enabled: true + scanNullValues: false + googleWebToolkit: false + directWebRemoting: false + urlPath: true + httpHeaders: + enabled: true + allRequests: false + cookieData: + enabled: true + encodeCookieValues: false + scripts: true + - type: activeScan-policy + parameters: + name: full-scan-policy + policyDefinition: + defaultStrength: INSANE + defaultThreshold: OFF + rules: + - id: 6 + threshold: MEDIUM + strength: INSANE + - id: 10048 + threshold: MEDIUM + strength: INSANE + - id: 40045 + threshold: MEDIUM + strength: INSANE + - id: 40048 + threshold: MEDIUM + strength: INSANE + - id: 90020 + threshold: MEDIUM + strength: INSANE + - id: 90037 + threshold: MEDIUM + strength: INSANE + - id: 40012 + threshold: MEDIUM + strength: INSANE + - id: 40026 + threshold: MEDIUM + strength: INSANE + - id: 40031 + threshold: MEDIUM + strength: INSANE + - id: 40018 + threshold: MEDIUM + strength: INSANE + - id: 40019 + threshold: MEDIUM + strength: INSANE + - id: 40020 + threshold: MEDIUM + strength: INSANE + - id: 40021 + threshold: MEDIUM + strength: INSANE + - id: 40022 + threshold: MEDIUM + strength: INSANE + - id: 40027 + threshold: MEDIUM + strength: INSANE + - id: 40028 + threshold: MEDIUM + strength: INSANE + - id: 40032 + threshold: MEDIUM + strength: INSANE + - id: 90019 + threshold: MEDIUM + strength: INSANE + - id: 40003 + threshold: MEDIUM + strength: INSANE + - id: 40043 + threshold: MEDIUM + strength: INSANE + - id: 40047 + threshold: MEDIUM + strength: INSANE + - id: 20012 + threshold: MEDIUM + strength: INSANE + - id: 20019 + threshold: MEDIUM + strength: INSANE + - id: 90023 + threshold: MEDIUM + strength: INSANE + - id: 90021 + threshold: MEDIUM + strength: INSANE + - id: 90025 + threshold: MEDIUM + strength: INSANE + - id: 40046 + threshold: MEDIUM + strength: INSANE + - id: 40033 + threshold: MEDIUM + strength: INSANE + - id: 90039 + threshold: MEDIUM + strength: INSANE + - id: 90035 + threshold: MEDIUM + strength: INSANE + - id: 90036 + threshold: MEDIUM + strength: INSANE + - type: activeScan + parameters: + context: openapi-import + policy: full-scan-policy + - type: report + parameters: + template: traditional-json + reportDir: /zap/wrk/zap-output + reportFile: 'zap_scan_results' + reportTitle: ZAP Full Scan Report + reportDescription: Full ZAP scan results for all imported API endpoints + risks: + - high + - medium + confidences: + - high + - medium + - low + - type: report + parameters: + template: traditional-html + reportDir: /zap/wrk/zap-output + reportFile: '{{yyyy-MM-dd}}-ZAP-Full-Report-[[site]]' + reportTitle: ZAP Full Scan Results + risks: + - high + - medium + confidences: + - high + - medium + - low diff --git a/src/main/java/org/seqra/demo/controller/RedirectController.java b/src/main/java/org/seqra/demo/controller/RedirectController.java new file mode 100644 index 0000000..f76eb70 --- /dev/null +++ b/src/main/java/org/seqra/demo/controller/RedirectController.java @@ -0,0 +1,107 @@ +package org.seqra.demo.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.Map; + +@RestController +@RequestMapping("/api/redirect") +@Tag(name = "Redirect", description = "URL redirection and response management") +public class RedirectController { + + @GetMapping("/external") + @Operation(summary = "Redirect to external URL", description = "Redirects to an external URL with custom headers") + public void redirectExternal( + @Parameter(description = "Target URL") @RequestParam String url, + @Parameter(description = "Custom header value") @RequestParam(required = false) String headerValue, + HttpServletResponse response) throws IOException { + + if (headerValue != null && !headerValue.isEmpty()) { + response.setHeader("X-Custom-Header", headerValue); + } + + response.setHeader("Location", url); + response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + } + + @GetMapping("/tracking") + @Operation(summary = "Track and redirect", description = "Tracks click and redirects with tracking info") + public void trackAndRedirect( + @Parameter(description = "Destination URL") @RequestParam String destination, + @Parameter(description = "Tracking ID") @RequestParam(required = false) String trackingId, + @Parameter(description = "Campaign name") @RequestParam(required = false) String campaign, + HttpServletResponse response) throws IOException { + + if (trackingId != null) { + response.setHeader("X-Tracking-ID", trackingId); + } + + if (campaign != null) { + response.setHeader("X-Campaign", campaign); + } + + response.sendRedirect(destination); + } + + @PostMapping("/custom-response") + @Operation(summary = "Custom response headers", description = "Returns response with custom headers") + public ResponseEntity> customResponse( + @Parameter(description = "Custom header name") @RequestParam String headerName, + @Parameter(description = "Custom header value") @RequestParam String headerValue, + @RequestBody(required = false) Map body) { + + HttpHeaders headers = new HttpHeaders(); + headers.add(headerName, headerValue); + + Map responseBody = body != null ? body : Map.of( + "status", "success", + "message", "Custom headers applied" + ); + + return new ResponseEntity<>(responseBody, headers, HttpStatus.OK); + } + + @GetMapping("/cache-control") + @Operation(summary = "Set cache control", description = "Returns response with custom cache control headers") + public void setCacheControl( + @Parameter(description = "Cache control directive") @RequestParam String directive, + @Parameter(description = "Additional headers") @RequestParam(required = false) String additionalHeaders, + HttpServletResponse response) throws IOException { + + response.setHeader("Cache-Control", directive); + + if (additionalHeaders != null && !additionalHeaders.isEmpty()) { + String[] headers = additionalHeaders.split(";"); + for (String header : headers) { + String[] parts = header.split(":", 2); + if (parts.length == 2) { + response.setHeader(parts[0].trim(), parts[1].trim()); + } + } + } + + response.setContentType("application/json"); + response.getWriter().write("{\"status\":\"success\",\"cacheControl\":\"" + directive + "\"}"); + } + + @GetMapping("/content-disposition") + @Operation(summary = "Set content disposition", description = "Returns response with content disposition header") + public void setContentDisposition( + @Parameter(description = "Filename") @RequestParam String filename, + @Parameter(description = "Disposition type") @RequestParam(required = false, defaultValue = "attachment") String disposition, + HttpServletResponse response) throws IOException { + + String dispositionHeader = disposition + "; filename=" + filename; + response.setHeader("Content-Disposition", dispositionHeader); + response.setContentType("application/octet-stream"); + response.getWriter().write("File content for: " + filename); + } +} diff --git a/src/main/java/org/seqra/demo/controller/TemplateController.java b/src/main/java/org/seqra/demo/controller/TemplateController.java new file mode 100644 index 0000000..0a758fb --- /dev/null +++ b/src/main/java/org/seqra/demo/controller/TemplateController.java @@ -0,0 +1,131 @@ +package org.seqra.demo.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/api/templates") +@Tag(name = "Templates", description = "Template processing and evaluation") +public class TemplateController { + + private final ExpressionParser parser = new SpelExpressionParser(); + + @PostMapping("/evaluate") + @Operation(summary = "Evaluate template expression", description = "Evaluates a template expression with provided context") + public ResponseEntity> evaluateExpression( + @Parameter(description = "Expression to evaluate") @RequestParam String expression, + @RequestBody(required = false) Map context) { + + try { + StandardEvaluationContext evalContext = new StandardEvaluationContext(); + + if (context != null) { + context.forEach(evalContext::setVariable); + } + + Expression exp = parser.parseExpression(expression); + Object result = exp.getValue(evalContext); + + return ResponseEntity.ok(Map.of( + "expression", expression, + "result", result != null ? result : "null", + "type", result != null ? result.getClass().getSimpleName() : "null" + )); + } catch (Exception e) { + return ResponseEntity.badRequest().body(Map.of( + "error", "Evaluation failed", + "message", e.getMessage() + )); + } + } + + @GetMapping("/render") + @Operation(summary = "Render template", description = "Renders a template string with dynamic values") + public ResponseEntity> renderTemplate( + @Parameter(description = "Template string") @RequestParam String template, + @Parameter(description = "User name") @RequestParam(required = false, defaultValue = "Guest") String userName) { + + try { + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setVariable("userName", userName); + context.setVariable("timestamp", System.currentTimeMillis()); + + Expression exp = parser.parseExpression(template); + Object rendered = exp.getValue(context); + + return ResponseEntity.ok(Map.of( + "template", template, + "rendered", rendered != null ? rendered.toString() : "", + "userName", userName + )); + } catch (Exception e) { + return ResponseEntity.badRequest().body(Map.of( + "error", "Rendering failed", + "message", e.getMessage() + )); + } + } + + @PostMapping("/calculate") + @Operation(summary = "Calculate expression", description = "Calculates mathematical or logical expressions") + public ResponseEntity> calculate( + @Parameter(description = "Calculation expression") @RequestParam String expr) { + + try { + Expression expression = parser.parseExpression(expr); + Object result = expression.getValue(); + + return ResponseEntity.ok(Map.of( + "expression", expr, + "result", result != null ? result : 0, + "success", true + )); + } catch (Exception e) { + return ResponseEntity.badRequest().body(Map.of( + "error", "Calculation failed", + "message", e.getMessage(), + "success", false + )); + } + } + + @GetMapping("/preview") + @Operation(summary = "Preview template output", description = "Previews template with sample data") + public ResponseEntity> previewTemplate( + @Parameter(description = "Template expression") @RequestParam String template) { + + Map sampleData = new HashMap<>(); + sampleData.put("user", "John Doe"); + sampleData.put("count", 42); + sampleData.put("active", true); + + try { + StandardEvaluationContext context = new StandardEvaluationContext(); + sampleData.forEach(context::setVariable); + + Expression exp = parser.parseExpression(template); + Object preview = exp.getValue(context); + + return ResponseEntity.ok(Map.of( + "template", template, + "preview", preview != null ? preview.toString() : "", + "sampleData", sampleData + )); + } catch (Exception e) { + return ResponseEntity.badRequest().body(Map.of( + "error", "Preview failed", + "message", e.getMessage() + )); + } + } +} diff --git a/template.yaml b/template.yaml new file mode 100644 index 0000000..356209b --- /dev/null +++ b/template.yaml @@ -0,0 +1,279 @@ +env: + contexts: + - name: openapi-import + urls: + - http://localhost:8081 + includePaths: [ ] + excludePaths: + - http://localhost:8081/api/redirect/external$ + parameters: + failOnError: false + failOnWarning: false + continueOnFailure: true + progressToStdout: true +jobs: + - type: openapi + parameters: + context: openapi-import + targetUrl: http://localhost:8081 + apiUrl: http://localhost:8081/v3/api-docs + - type: activeScan-config + parameters: + maxRuleDurationInMins: 0 + maxScanDurationInMins: 0 + maxAlertsPerRule: 0 + threadPerHost: 40 + handleAntiCSRFTokens: true + injectPluginIdInHeader: true + inputVectors: + urlQueryStringAndDataDrivenNodes: + enabled: true + addParam: false + odata: true + postData: + enabled: true + multiPartFormData: true + xml: true + json: + enabled: true + scanNullValues: false + googleWebToolkit: false + directWebRemoting: false + urlPath: true + httpHeaders: + enabled: true + allRequests: false + cookieData: + enabled: true + encodeCookieValues: false + scripts: true + - type: activeScan-policy + parameters: + name: policy-CWE-22 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 6 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-78 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 10048 + threshold: MEDIUM + strength: INSANE + - id: 40045 + threshold: MEDIUM + strength: INSANE + - id: 40048 + threshold: MEDIUM + strength: INSANE + - id: 90020 + threshold: MEDIUM + strength: INSANE + - id: 90037 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-79 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40012 + threshold: MEDIUM + strength: INSANE + - id: 40026 + threshold: MEDIUM + strength: INSANE + - id: 40031 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-89 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40018 + threshold: MEDIUM + strength: INSANE + - id: 40019 + threshold: MEDIUM + strength: INSANE + - id: 40020 + threshold: MEDIUM + strength: INSANE + - id: 40021 + threshold: MEDIUM + strength: INSANE + - id: 40022 + threshold: MEDIUM + strength: INSANE + - id: 40027 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-94 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40028 + threshold: MEDIUM + strength: INSANE + - id: 40032 + threshold: MEDIUM + strength: INSANE + - id: 90019 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-113 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40003 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-117 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40043 + threshold: MEDIUM + strength: INSANE + - id: 40047 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-352 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 20012 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-601 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 20019 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-611 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 90023 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-643 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 90021 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-917 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 90025 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-918 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40046 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-943 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 40033 + threshold: MEDIUM + strength: INSANE + - id: 90039 + threshold: MEDIUM + strength: INSANE + - type: activeScan-policy + parameters: + name: policy-CWE-1336 + policyDefinition: + defaultStrength: INSANE + defaultThreshold: 'OFF' + rules: + - id: 90035 + threshold: MEDIUM + strength: INSANE + - id: 90036 + threshold: MEDIUM + strength: INSANE + - type: report + parameters: + template: traditional-json + reportDir: /zap/wrk/zap-output + reportFile: 'seqra_zap_scan_results' + reportTitle: OpenTaint + ZAP Scan Report + reportDescription: Automated security scan results for filtering sarif + risks: + - high + - medium + confidences: + - high + - medium + - low + - type: report + parameters: + template: traditional-html + reportDir: /zap/wrk/zap-output + reportFile: '{{yyyy-MM-dd}}-ZAP-Report-[[site]]' + reportTitle: OpenTaint + ZAP scan results + risks: + - high + - medium + confidences: + - high + - medium + - low + - type: exitStatus + parameters: + okExitValue: 0 + errorExitValue: 0 + warnExitValue: 0