Series MapLesson 30 / 35
Final StretchOrdered learning track

Learn Java Security Cryptography Integrity Part 030 Security Testing Sast Dast Iast Fuzzing And Misuse Tests

18 min read3596 words
PrevNext
Lesson 3035 lesson track3035 Final Stretch

title: Learn Java Security, Cryptography and Integrity - Part 030 description: Security testing untuk sistem Java: SAST, DAST, IAST, fuzzing, property-based abuse tests, crypto misuse tests, authz regression tests, dan CI security gates. series: learn-java-security-cryptography-integrity seriesTitle: Learn Java Security, Cryptography and Integrity order: 30 partTitle: Security Testing: SAST, DAST, IAST, Fuzzing & Misuse Tests tags:

  • java
  • security
  • security-testing
  • sast
  • dast
  • fuzzing
  • ci-cd
  • secure-engineering date: 2026-06-30

Part 030 — Security Testing: SAST, DAST, IAST, Fuzzing & Misuse Tests

Target part ini: kamu mampu membangun security testing strategy untuk sistem Java yang tidak hanya “menjalankan scanner”, tetapi benar-benar menguji security properties, misuse cases, boundary behavior, authorization invariants, crypto correctness, parser resilience, dan release gates.

Security testing yang matang bukan soal punya banyak tool. Tool penting, tetapi tool hanya bagian dari sistem. Tujuan kita adalah membuat bug keamanan:

  1. lebih cepat ditemukan,
  2. lebih murah diperbaiki,
  3. tidak mudah regresi,
  4. bisa dibuktikan tertutup,
  5. menjadi bagian normal dari engineering workflow.

OWASP Web Security Testing Guide menekankan perlunya balanced approach yang mencakup testing techniques, manual inspection/review, threat modeling, source code review, dan penetration testing. NIST SSDF juga menempatkan verification dan vulnerability response sebagai bagian dari secure software development practice.


1. Kaufman Deconstruction

Kita pecah security testing menjadi sub-skill yang bisa dilatih:

Minimum effective learning target

After this part, you should be able to:

  • turn a threat model into executable tests;
  • explain where SAST, DAST, IAST, fuzzing, and manual review fit;
  • write misuse tests for authz, replay, request signing, crypto, parser, and logging boundaries;
  • build CI gates that reduce risk without blocking engineering with noise;
  • evaluate scanner results using reachability, exploitability, and business impact.

2. Mental Model: Test Security Properties, Not Just Code Paths

Functional testing asks:

Does the system do what the user wants?

Security testing asks:

Does the system refuse what the attacker wants?

This difference matters. A happy-path test can prove login works. It does not prove:

  • bad password fails safely;
  • disabled account cannot login;
  • old session is invalidated after password reset;
  • MFA bypass is impossible;
  • authorization is checked per object;
  • replayed webhook is rejected;
  • invalid signature is rejected before business processing;
  • parser rejects malicious payload;
  • token audience/issuer is verified;
  • logs do not leak sensitive data.

Security test structure

A good security test usually states:

Given asset A and trust boundary B,
when actor X attempts action Y under condition Z,
then invariant I must hold,
and evidence E must be produced or absent.

Example:

Given case CASE-123 belongs to tenant T1,
when actor from tenant T2 requests GET /cases/CASE-123,
then access is denied,
and no case data is returned,
and a structured authorization.denied security event is emitted.

3. Security Testing Pyramid

Important principle

Do not outsource all security testing to late-stage DAST or penetration testing. The cheapest security test is usually a small regression test near the code that enforces the invariant.


4. Tool Categories and What They Actually See

TechniqueSeesFinds WellMisses OftenBest Used
SASTsource/bytecode/configinsecure APIs, dataflow, injection patterns, crypto misuseruntime auth context, business logic, environment configevery PR / CI
SCAdependency graph/SBOMknown vulnerable dependencies, license/policy riskvulnerable but unreachable code, custom bugsevery PR / scheduled
DASTrunning app over HTTPweb/API boundary issues, headers, basic injection, auth/session issuesdeep business logic, internal paths, unreachable statesnightly/release
IASTrunning app with instrumentationruntime dataflow, exercised vulnerabilitiespaths not executed, complex auth flowstest/staging with good coverage
Fuzzingtarget parser/function/APIcrashes, parser bugs, unexpected states, DoShigh-level business logic unless properties definedparsers, codecs, boundary components
Manual Reviewdesign/source/contextbusiness logic flaws, trust boundary issues, authorization mistakesscale, repeatabilityhigh-risk changes
Pen Testsystem from attacker perspectiveexploit chains, real-world bypassescomplete coverage, regressionsperiodic validation

5. Threat-to-Test Mapping

Security tests should start from threats and invariants.

Example:

ThreatRequirementInvariantTest
Cross-tenant case readTenant isolationActor from T2 cannot read object from T1integration authz test
Webhook replayFreshnessSame signed event cannot be processed twicereplay test
JWT confusionToken validationToken must match issuer/audience/alg/key typetoken negative tests
AES-GCM nonce reuseCrypto safetyIV unique per keyunit/property test around encryptor
Log leakageData minimizationPassword/token absent from logslog capture test
SSRFNetwork boundaryURL fetcher rejects internal IPs after DNS resolutionSSRF integration test
XML entity expansionParser safetyexternal entity disabled and payload boundedparser security test

6. Authorization Regression Tests

Authorization is often the most important custom security logic in enterprise Java systems.

Matrix thinking

For each protected object, test:

  • owner vs non-owner;
  • same tenant vs different tenant;
  • normal user vs admin;
  • active vs suspended account;
  • object state allowed vs blocked;
  • direct object access vs search/list/export;
  • read vs write vs approve vs delete;
  • UI route vs API route;
  • cached authorization vs fresh policy.

Java integration example

@Test
void userFromDifferentTenantCannotReadCaseByDirectId() throws Exception {
    var t1 = tenants.create("tenant-a");
    var t2 = tenants.create("tenant-b");
    var caseId = cases.createCase(t1, "sensitive-enforcement-case");
    var actorFromT2 = users.createUser(t2, "case-reader");

    mockMvc.perform(get("/cases/{id}", caseId)
            .with(jwtFor(actorFromT2).scope("case.read")))
        .andExpect(status().isForbidden())
        .andExpect(jsonPath("$.caseNumber").doesNotExist())
        .andExpect(jsonPath("$.details").doesNotExist());

    assertThat(securityEvents)
        .containsEvent("authorization.denied", event ->
            event.action().equals("case.read") &&
            event.objectRef().equals(caseId.toString()) &&
            event.reasonCode().equals("tenant_mismatch"));
}

Anti-pattern

Only testing missing role:

@Test
void requiresCaseReadRole() { ... }

This is not enough. Broken Object Level Authorization often happens when the user has the right role but targets the wrong object.


7. Authentication and Session Misuse Tests

Test cases:

ScenarioExpected
wrong passworddeny; generic error; failure event; no password in log
disabled accountdeny; no session; risk event
password reset completedold sessions invalidated if policy requires
MFA required but missingdeny; no partial privileged session
reused recovery tokendeny; replay event
refresh token rotation replayrevoke token family or risk response
logoutsession invalidated server-side where applicable
cookie missing SameSite/Secure/HttpOnlytest fails

Example cookie assertion:

@Test
void sessionCookieHasSecureFlags() throws Exception {
    MvcResult result = mockMvc.perform(post("/login")
            .contentType(MediaType.APPLICATION_JSON)
            .content(validLoginJson()))
        .andExpect(status().isOk())
        .andReturn();

    String setCookie = result.getResponse().getHeader("Set-Cookie");
    assertThat(setCookie).contains("HttpOnly");
    assertThat(setCookie).contains("Secure");
    assertThat(setCookie).contains("SameSite=");
}

8. Token Validation Negative Tests

For JWT/OIDC resource servers, test invalid tokens explicitly.

Negative TokenExpected
alg=nonereject
wrong issuerreject
wrong audiencereject
expired tokenreject
not-before in futurereject
unknown kidreject safely
mismatched key typereject
token signed by different tenant IdPreject
missing required scopeauthenticated but forbidden
malformed tokenreject without stacktrace leak

Example:

@ParameterizedTest
@MethodSource("invalidTokens")
void invalidJwtIsRejected(String token) throws Exception {
    mockMvc.perform(get("/cases")
            .header("Authorization", "Bearer " + token))
        .andExpect(status().isUnauthorized());
}

The important part is not just status code. Also verify no business logic executed and logs do not include the raw token.


9. Request Signing and Replay Tests

From Part 022, request signing requires canonicalization, timestamp, nonce/idempotency, and key identification.

Test matrix

MutationExpected
same body, valid signatureaccept once
same request replayedreject replay
body changed by one bytereject signature
header case/order changed but canonical equivalentaccept if canonicalization says equivalent
missing signed headerreject
timestamp outside windowreject
unknown key idreject
disabled key idreject
duplicate noncereject

Example:

@Test
void replayedWebhookIsRejected() throws Exception {
    var webhook = signedWebhook("evt-001", "{\"status\":\"paid\"}");

    mockMvc.perform(webhook.toRequest()).andExpect(status().isAccepted());
    mockMvc.perform(webhook.toRequest()).andExpect(status().isConflict());

    assertThat(processedEvents.count("evt-001")).isEqualTo(1);
    assertThat(securityEvents).containsEvent("webhook.replay_detected");
}

10. Crypto Misuse Tests

Crypto tests are not mainly “encrypt then decrypt works”. That is only a functional smoke test.

What to test

ComponentRequired Security Test
AEAD encryptortampered ciphertext rejected
AEAD encryptortampered AAD rejected
AEAD encryptorIV uniqueness under same key
password hashingunique salt per password
MAC verifiermodified body rejected
signature verifierwrong key rejected
key rotationold ciphertext decrypts while new encrypt uses active key
KMS envelopeplaintext DEK not logged or persisted
random tokenenough length and no predictable source

AEAD tamper test

@Test
void aesGcmRejectsTamperedCiphertext() {
    byte[] plaintext = "case decision approved".getBytes(StandardCharsets.UTF_8);
    byte[] aad = "case:123".getBytes(StandardCharsets.UTF_8);

    EncryptedBlob blob = encryptor.encrypt(plaintext, aad);
    byte[] tampered = blob.ciphertext().clone();
    tampered[tampered.length - 1] ^= 0x01;

    assertThatThrownBy(() -> encryptor.decrypt(blob.withCiphertext(tampered), aad))
        .isInstanceOf(SecurityException.class);
}

IV uniqueness property

@Test
void encryptionUsesDifferentNonceForEachMessage() {
    Set<String> ivs = new HashSet<>();

    for (int i = 0; i < 10_000; i++) {
        EncryptedBlob blob = encryptor.encrypt(("msg-" + i).getBytes(UTF_8), new byte[0]);
        assertThat(ivs.add(Base64.getEncoder().encodeToString(blob.iv())))
            .as("duplicate IV at iteration " + i)
            .isTrue();
    }
}

This does not mathematically prove uniqueness forever, but it catches catastrophic deterministic/reused IV bugs.


11. Parser and Deserialization Tests

Parser boundaries are high-value fuzzing targets.

XML parser security tests

Test payloads:

  • external entity;
  • billion laughs/entity expansion;
  • huge document;
  • deeply nested elements;
  • unexpected namespace;
  • duplicate IDs if signature verification uses IDs;
  • signature wrapping variants.

Example:

@Test
void xmlParserRejectsExternalEntity() {
    String payload = """
        <?xml version="1.0"?>
        <!DOCTYPE data [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
        <data>&xxe;</data>
        """;

    assertThatThrownBy(() -> secureXmlParser.parse(payload))
        .isInstanceOf(SecurityException.class);
}

Java deserialization rule

For untrusted input, the best test is often that Java native deserialization is not reachable at all. If legacy constraints require it, test ObjectInputFilter, allowlist, size/depth/reference limits, and rejection behavior.

@Test
void objectInputFilterRejectsUnexpectedClass() {
    byte[] serialized = serialize(new UnexpectedGadgetLikeType());

    assertThatThrownBy(() -> legacyDecoder.decode(serialized))
        .isInstanceOf(InvalidClassException.class);
}

12. Fuzzing for Java

Fuzzing feeds many generated inputs to a target and watches for crashes, hangs, assertion failures, or security property violations. OWASP describes fuzzing as a technique for identifying bugs, vulnerabilities, or unexpected behavior by automatically providing unexpected, malformed, or semi-malformed inputs.

Good Java fuzzing targets:

  • canonical request parser;
  • URL/SSRF allowlist parser;
  • JSON/XML canonicalizer;
  • webhook verifier;
  • JWT parser wrapper;
  • file metadata parser;
  • custom binary protocol parser;
  • authorization expression parser;
  • template/rule parser;
  • import/export parser.

Fuzz target shape

A fuzz target should be small and deterministic:

public final class UrlPolicyFuzzTest {
    public static void fuzzerTestOneInput(String input) {
        try {
            UrlDecision decision = UrlPolicy.evaluate(input);

            if (decision.allowed()) {
                URI uri = URI.create(input);
                if (isPrivateOrLoopback(uri)) {
                    throw new AssertionError("private address allowed: " + input);
                }
            }
        } catch (IllegalArgumentException | SecurityException expected) {
            // Rejection is acceptable.
        }
    }
}

Fuzzing rule

Do not fuzz the whole application first. Fuzz the smallest boundary component that makes a security decision.


13. Property-Based Abuse Testing

Property-based testing generates many cases and checks invariants.

Example invariant:

No actor can read an object from another tenant, regardless of object ID shape.

Pseudo-example with jqwik-style notation:

@Property
void crossTenantReadIsAlwaysDenied(
    @ForAll("tenantRefs") String tenantA,
    @ForAll("tenantRefs") String tenantB,
    @ForAll("caseIds") String caseId
) {
    Assume.that(!tenantA.equals(tenantB));

    cases.insert(caseId, tenantA);
    Actor actor = actorInTenant(tenantB, Set.of("case.read"));

    assertThatThrownBy(() -> caseService.read(actor, caseId))
        .isInstanceOf(AccessDeniedException.class);
}

Property tests are useful for:

  • authorization matrices;
  • canonicalization equivalence;
  • replay/idempotency behavior;
  • parser boundaries;
  • state-machine constraints;
  • workflow escalation rules.

14. SAST in Java

SAST scans source or bytecode/config without running the application.

Useful finding categories

  • unsafe deserialization;
  • SQL/LDAP/command injection patterns;
  • path traversal;
  • hardcoded secrets;
  • weak cryptography;
  • bad random source;
  • missing TLS verification;
  • XML external entity risk;
  • insecure temporary file usage;
  • logging sensitive data;
  • Spring security misconfiguration;
  • unsafe reflection/expression evaluation.

Common tools/categories

  • Semgrep custom rules;
  • CodeQL queries;
  • SpotBugs + FindSecBugs;
  • Checkstyle/ArchUnit custom guardrails;
  • IDE inspections;
  • secret scanners.

This part does not repeat dependency scanning from Part 026, but SAST and SCA should be wired together in CI.

Custom Semgrep-like rule idea

Policy: no direct Cipher.getInstance("AES").

Bad:

Cipher cipher = Cipher.getInstance("AES");

Better:

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

But the stronger approach is to ban direct crypto construction outside approved crypto wrapper packages.

Architecture guard with ArchUnit

@AnalyzeClasses(packages = "com.example")
class SecurityArchitectureTest {

    @ArchTest
    static final ArchRule cryptoOnlyInSecurityPackage = noClasses()
        .that().resideOutsideOfPackage("..security.crypto..")
        .should().accessClassesThat().resideInAnyPackage("javax.crypto..", "java.security..")
        .because("application code should use reviewed crypto boundary abstractions");
}

This is often more effective than hoping every developer remembers crypto pitfalls.


15. DAST and API Security Testing

DAST tests a running application externally.

What DAST is good at

  • missing security headers;
  • reflected/stored XSS candidates;
  • basic injection;
  • exposed admin paths;
  • cookie flags;
  • CORS misconfiguration;
  • TLS/header hygiene;
  • authentication/session behavior;
  • API discovery drift.

What DAST often misses

  • business authorization;
  • tenant isolation;
  • workflow state constraints;
  • event integrity;
  • hidden internal APIs;
  • complex asynchronous processing;
  • crypto misuse behind API;
  • data leakage visible only to specific roles.

DAST must be authenticated

Unauthenticated scanning is useful but shallow. For enterprise APIs, run scans with controlled test accounts:

  • anonymous;
  • normal user tenant A;
  • normal user tenant B;
  • admin tenant A;
  • suspended/disabled user;
  • service account with limited scope.

API DAST preconditions

  • deterministic test environment;
  • seeded test data;
  • safe test credentials;
  • rate limits configured for scanner;
  • destructive actions isolated;
  • scanner cannot hit production data;
  • findings mapped to route templates and build SHA.

16. IAST: Runtime-Aware Testing

IAST instruments the application while tests run. It can observe runtime dataflow and exercised paths.

Good use cases

  • detecting injection in paths hit by integration tests;
  • identifying unsafe library calls at runtime;
  • correlating HTTP request to code path;
  • reducing SAST false positives with runtime evidence.

Limitations

IAST only sees what tests execute. Poor functional/integration coverage means poor IAST coverage.

Practical model

Use IAST in staging or dedicated test environment with realistic integration tests. Do not treat it as replacement for threat modeling or code review.


17. Misuse Test Catalog

Use this catalog as starting point.

Identity and access

  • token with wrong issuer rejected;
  • token with wrong audience rejected;
  • expired token rejected;
  • missing scope forbidden;
  • same role but different tenant forbidden;
  • object state prevents forbidden transition;
  • admin action requires admin authority and audit/security event;
  • disabled user cannot use existing session if policy requires.

Crypto and integrity

  • tampered ciphertext rejected;
  • tampered AAD rejected;
  • wrong key rejected;
  • duplicate nonce not generated in test run;
  • invalid signature rejected;
  • replayed signed request rejected;
  • key rotation preserves decrypt for old data;
  • retired key no longer encrypts new data.

Parser and boundary

  • XXE payload rejected;
  • huge payload rejected;
  • deep nesting rejected;
  • path traversal rejected after normalization;
  • SSRF to loopback/private/metadata rejected;
  • duplicate JSON keys handled safely;
  • content type mismatch rejected;
  • dangerous file extension rejected.

Observability

  • password/token absent from logs;
  • authorization denied event emitted;
  • log injection payload cannot forge event;
  • metric labels do not include user/object raw IDs;
  • trace attributes do not include request body/headers.

18. Security Test Data Management

Security tests need intentionally malicious data.

Test corpus examples

../etc/passwd
..%2f..%2fetc%2fpasswd
http://127.0.0.1/admin
http://169.254.169.254/latest/meta-data/
${jndi:ldap://example.invalid/a}
<script>alert(1)</script>
' OR '1'='1
alice@example.com\n{"event_type":"admin.role_granted"}

Rules

  • Store malicious corpus in test resources.
  • Label it clearly as test data.
  • Ensure scanners/secret detectors do not mistake fake secrets for real secrets, or mark them with approved test prefixes.
  • Never use real user data in security tests.
  • Version regression payloads from fixed vulnerabilities.

19. CI/CD Security Gates

A security gate should reduce risk without becoming theater.

Good gates

  • deterministic;
  • fast enough for PR if PR gate;
  • severity policy clear;
  • allow baseline for legacy issues but block new critical issues;
  • exception workflow audited;
  • owner assigned;
  • findings deduplicated;
  • regression tests required for fixed high-risk bugs.

Bad gates

  • fail randomly;
  • produce thousands of untriaged findings;
  • block on old accepted risks with no path to remediation;
  • depend on external service instability;
  • do not distinguish test code from production code;
  • treat every scanner finding as equal.

20. Triage: From Finding to Decision

A scanner finding is not automatically a vulnerability, and a false positive is not automatically harmless.

Triage dimensions

DimensionQuestion
ReachabilityCan attacker-controlled input reach it?
ExploitabilityCan it be exploited under real constraints?
ImpactWhat asset is affected?
Existing controlsIs there compensating validation/authz/sandbox?
EnvironmentIs it production, admin-only, internal, test-only?
Blast radiusSingle tenant, all tenants, infrastructure, supply chain?
DetectabilityWould we know if it happened?
Fix riskCould fix break critical behavior?
Regression testCan we encode the issue permanently?

Triage outcome types

  • fix immediately;
  • fix before release;
  • accept temporarily with owner/date/control;
  • false positive with evidence;
  • needs design review;
  • needs pen-test validation;
  • convert to backlog hardening.

21. Security Regression Rule

Every serious vulnerability fix should add one of:

  • unit misuse test;
  • integration security test;
  • fuzz corpus entry;
  • SAST custom rule;
  • DAST assertion;
  • architecture rule;
  • CI policy check;
  • documentation/design invariant.

A fix without regression evidence is fragile.


22. Example: Building a Security Test Suite for Case Management

Assets

  • enforcement case;
  • evidence file;
  • decision record;
  • audit event;
  • user/session;
  • service integration webhook;
  • signing key.

Threats

  • cross-tenant access;
  • unauthorized decision approval;
  • replayed webhook updates payment/evidence state;
  • tampered evidence file accepted;
  • audit log missing for privileged action;
  • malicious file upload;
  • SSRF through evidence import URL;
  • token with wrong audience accepted.

Tests

ThreatTest Type
cross-tenant readintegration authz matrix
unauthorized approvalstate-machine misuse test
webhook replayrequest signing replay test
tampered evidencecontent hash/signature test
missing privileged auditevent assertion test
malicious uploadfile upload corpus test
SSRF import URLboundary unit + integration test
wrong token audienceJWT negative test

23. Example CI Policy

security:
  pull_request:
    block_on:
      - new_critical_sast
      - new_high_secret_leak
      - failed_authz_regression
      - failed_crypto_misuse_test
      - failed_log_leak_test
    warn_on:
      - medium_sast
      - low_security_header
  nightly:
    run:
      - authenticated_dast
      - parser_fuzzing_30m
      - iast_integration_suite
      - dependency_policy_scan
  release:
    require:
      - no_open_critical
      - high_findings_triaged
      - security_exception_expiry_checked
      - penetration_test_for_high_risk_release

This is conceptual, not tied to one vendor.


24. Common Anti-Patterns

Anti-pattern 1 — “We have SAST, therefore secure”

SAST does not understand all business logic. It will not reliably prove tenant isolation or workflow authorization.

Anti-pattern 2 — Scanner-only security testing

A scanner cannot know your domain invariants unless you encode them.

Anti-pattern 3 — Only testing unauthorized anonymous users

Many real authorization failures happen with authenticated users who have some permissions but target the wrong object or state.

Anti-pattern 4 — Testing only encrypt/decrypt happy path

Crypto happy-path tests miss tamper rejection, AAD binding, nonce uniqueness, key rotation, and algorithm metadata.

Anti-pattern 5 — Running DAST only unauthenticated

This misses authenticated attack surface.

Anti-pattern 6 — No regression test after vulnerability fix

The same bug class often returns later in a new endpoint.

Anti-pattern 7 — Treating false positives as purely tool problem

False positives may indicate missing architecture boundaries, unclear ownership, or poor scanner configuration.


25. Design Review Checklist

Strategy

  • Are security properties explicitly listed?
  • Are tests mapped to threat model entries?
  • Are authz tests object-level and tenant-aware?
  • Are parser boundaries tested with malicious corpus?
  • Are crypto wrappers tested for misuse, not only happy path?
  • Are replay/freshness tests present where signatures/tokens/webhooks exist?

Tooling

  • SAST is configured for Java/framework stack.
  • Secret scanning covers source, config, build logs, and test fixtures.
  • DAST uses authenticated roles where safe.
  • Fuzzing targets small boundary components.
  • CI gates distinguish new findings from legacy baseline.
  • Findings have owner, severity, and remediation evidence.

Quality

  • Tests are deterministic.
  • Test data is synthetic.
  • Malicious corpus is versioned.
  • Security tests run at appropriate cadence.
  • High-risk fixes add regression evidence.
  • Exceptions are time-bound and auditable.

26. Lab: Security Testing Workbench

Scenario

You maintain a Java service case-api with:

  • OAuth2/OIDC resource server;
  • case CRUD;
  • evidence upload;
  • webhook receiver;
  • XML import;
  • admin role management;
  • encrypted sensitive fields;
  • structured security events.

Task A — Threat-to-test table

Create table with 20 threats and map each to:

  • unit test;
  • integration test;
  • SAST rule;
  • DAST check;
  • fuzz target;
  • manual review.

Task B — Write 8 negative tests

At minimum:

  1. wrong JWT audience;
  2. cross-tenant object read;
  3. missing scope;
  4. replayed webhook;
  5. tampered encrypted blob;
  6. XXE payload;
  7. SSRF private IP;
  8. password/token absent from logs.

Task C — Build fuzz target

Pick one:

  • URL allowlist parser;
  • canonical request parser;
  • XML import pre-parser;
  • JSON canonicalizer;
  • file extension/content-type classifier.

Define assertion properties.

Task D — CI gate design

Define:

  • PR checks;
  • nightly checks;
  • release checks;
  • severity policy;
  • exception workflow;
  • evidence artifacts.

27. Production Readiness Rubric

LevelDescription
L1Basic unit tests and occasional scanner runs.
L2SAST/SCA in CI, some auth tests, manual DAST before release.
L3Threat-to-test mapping, authz matrix, crypto misuse tests, parser corpus, authenticated DAST.
L4Security regression policy, fuzzing for risky parsers, CI gates with triage workflow, evidence artifacts.
L5Continuous security testing program with custom rules, production-like test environments, measurable coverage of security properties, and mature exception governance.

Aim for L4 for high-risk Java enterprise systems. L5 is justified for regulated, critical, multi-tenant, or safety-sensitive platforms.


28. What to Remember

Security testing is not a tool category. It is the practice of making security assumptions executable.

The best teams encode their security model into:

  • tests,
  • scanners,
  • fuzz targets,
  • architecture rules,
  • release gates,
  • and review checklists.

A scanner finding may start a conversation. A security invariant ends ambiguity.


References

Lesson Recap

You just completed lesson 30 in final stretch. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.