diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..39ab8696 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: maven + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..e185d674 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,36 @@ +name: CodeQL + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: '41 3 * * 1' + +permissions: + contents: read + security-events: write + actions: read + +jobs: + analyze: + name: Analyze Java + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 + - name: Set up JDK 21 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 + with: + distribution: temurin + java-version: '21' + cache: maven + - uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 + with: + languages: java-kotlin + build-mode: manual + - name: Build for CodeQL + run: mvn -B -ntp -DskipTests package + - uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 + with: + category: /language:java-kotlin diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml new file mode 100644 index 00000000..36221b66 --- /dev/null +++ b/.github/workflows/fuzz.yml @@ -0,0 +1,77 @@ +name: fuzz + +# Coverage-guided fuzzing of the untrusted-input parsers (Jazzer, Apache-2.0). +# +# - Pull requests / pushes: run each Jazzer @FuzzTest in fuzzing mode for a +# short, bounded budget (maxDuration = 60s per target, set on the annotation) +# so the job stays cheap. Newly discovered crashers fail the build. +# - Nightly (cron): a longer budget for deeper exploration. +# +# Regression replay of the seed corpus also runs as part of the normal +# `mvn test` build (JAZZER_FUZZ unset) and needs no libFuzzer driver. + +on: + pull_request: + paths: + - 'src/**' + - 'pom.xml' + - '.github/workflows/fuzz.yml' + push: + branches: [ main ] + paths: + - 'src/**' + - 'pom.xml' + - '.github/workflows/fuzz.yml' + schedule: + - cron: '0 3 * * *' # nightly deep run + workflow_dispatch: {} + +permissions: + contents: read + +concurrency: + group: fuzz-${{ github.ref }} + cancel-in-progress: true + +jobs: + fuzz: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + target: + - ArtifactTokenParserFuzzTest + - DocumentValidationFuzzTest + - TenantClaimsFuzzTest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 + + - name: Set up JDK 21 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 + with: + distribution: temurin + java-version: '21' + cache: maven + + # Nightly scheduled runs fuzz longer; PR/push runs use the 60s annotation budget. + - name: Fuzz ${{ matrix.target }} + env: + JAZZER_FUZZ: '1' + run: | + EXTRA="" + if [ "${{ github.event_name }}" = "schedule" ]; then + # Deeper nightly exploration (10 min per target). + EXTRA="-Djazzer.max_total_time=600" + fi + mvn -B -ntp -Dtest='${{ matrix.target }}' $EXTRA test + + - name: Upload crash reproducers + if: failure() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 + with: + name: fuzz-findings-${{ matrix.target }} + path: | + **/crash-* + **/timeout-* + **/oom-* + if-no-files-found: ignore diff --git a/.gitignore b/.gitignore index 761b4af6..8b41596b 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,9 @@ certs/ *.crt *.cer *.jks + +# Jazzer generated corpus +.cifuzz-corpus/ + +# CodeGraph local index +.codegraph/ diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..bd252911 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,11 @@ +# Security Policy + +## Supported Versions + +Security updates are applied to the current `main` branch and the latest deployable Clearfolio Viewer release. + +## Reporting a Vulnerability + +Please report suspected vulnerabilities by opening a private vulnerability report in this repository's Security tab. If private reporting is unavailable, email the maintainers listed in the organization profile with a minimal reproduction, affected version, and impact summary. + +We aim to acknowledge reports within 3 business days, provide a remediation plan after triage, and publish fixes before disclosing detailed exploit information. diff --git a/docs/fuzzing.md b/docs/fuzzing.md new file mode 100644 index 00000000..4e29a72e --- /dev/null +++ b/docs/fuzzing.md @@ -0,0 +1,55 @@ +# Fuzzing + +Coverage-guided fuzzing of the viewer's untrusted-input parsers, using +[Jazzer](https://github.com/CodeIntelligenceTesting/jazzer) (Apache-2.0) +integrated with JUnit 5 (`jazzer-junit`). + +## Targets + +The surfaces were selected with CodeGraph as the highest-value untrusted-input +boundaries (attacker-controlled tokens, filenames, and request headers). Each +harness asserts that arbitrary input only ever produces the *documented* +failure mode -- never an unhandled runtime exception. + +| Harness | Surface under test | Invariant | +| --- | --- | --- | +| `ArtifactTokenParserFuzzTest` | `ArtifactLinkService.verifyReadToken` -- splits, HMAC-verifies, Base64URL-decodes and parses 10 token fields (UUID, epoch `Instant`s). Forges valid signatures to reach the deep parse path. | Only `ArtifactTokenException` (a mapped 4xx) escapes. | +| `DocumentValidationFuzzTest` | `DefaultDocumentValidationService.validateOrThrow` -- filename/extension parsing + policy-override headers. | Only `IllegalArgumentException` (incl. `UnsupportedDocumentFormatException`) escapes. | +| `TenantClaimsFuzzTest` | `TenantContext.fromHeaders` + `TenantAccessService.require` -- tenant/subject/permission headers and the signed-claims timestamp/signature. | `fromHeaders` never throws; `require` only fails with `ResponseStatusException`. | + +Seed corpora live under +`src/test/resources/com/clearfolio/viewer/fuzz/Inputs//`. + +## How it runs + +- **Normal build (`mvn test`)**: the `@FuzzTest` methods run in *regression* + mode -- they replay the seed corpus (and any committed crash reproducers) as + fast, deterministic unit tests. No libFuzzer driver required, so this works on + every developer platform and keeps the default build cheap. + +- **Fuzzing mode (`JAZZER_FUZZ=1`)**: libFuzzer drives each target for the + bounded budget declared on its `@FuzzTest(maxDuration = "60s")` annotation. + +```bash +# Regression replay of all fuzz seeds (part of the normal suite): +mvn test -Dtest='*FuzzTest' + +# Actively fuzz a single target for its bounded budget: +JAZZER_FUZZ=1 mvn test -Dtest='ArtifactTokenParserFuzzTest' +``` + +## CI + +`.github/workflows/fuzz.yml` fuzzes each target for 60s on pull requests and +pushes to `main`, and for 10 minutes per target nightly. A newly discovered +crasher fails the job; the reproducer is uploaded as a build artifact. Commit +the reproducer into the harness's `Inputs//` directory to turn it into a +permanent regression test. + +## Findings + +The initial harness immediately surfaced an unhandled `java.time.DateTimeException` +in the artifact-token parser: `Instant.ofEpochSecond(Long.parseLong(...))` threw +on an out-of-range (but syntactically valid) epoch second, escaping the +`catch (IllegalArgumentException)` block and turning a would-be 401 into a 500. +Fixed by also catching `DateTimeException` in `ArtifactLinkService.parseAndVerify`. diff --git a/docs/papers/boehme-2016-coverage-based-greybox-fuzzing-as-markov-chain.pdf b/docs/papers/boehme-2016-coverage-based-greybox-fuzzing-as-markov-chain.pdf new file mode 100644 index 00000000..a5500493 Binary files /dev/null and b/docs/papers/boehme-2016-coverage-based-greybox-fuzzing-as-markov-chain.pdf differ diff --git a/pom.xml b/pom.xml index 6b7e40df..f035aab8 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,8 @@ 3.0.3 4.10.38 + 0.30.0 + 2.21.5 @@ -66,6 +68,19 @@ test + + + com.code-intelligence + jazzer-junit + ${jazzer.version} + test + + diff --git a/src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java b/src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java index 454b0448..333bbadc 100644 --- a/src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java +++ b/src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java @@ -6,6 +6,7 @@ import java.security.MessageDigest; import java.security.SecureRandom; import java.time.Clock; +import java.time.DateTimeException; import java.time.Instant; import java.util.Arrays; import java.util.Base64; @@ -357,7 +358,9 @@ private ArtifactTokenClaims parseAndVerify(String token) { Instant.ofEpochSecond(Long.parseLong(decode(parts[8]))), Instant.ofEpochSecond(Long.parseLong(decode(parts[9]))) ); - } catch (IllegalArgumentException ex) { + } catch (IllegalArgumentException | DateTimeException ex) { + // IllegalArgumentException: malformed Base64URL, UUID, or numeric fields. + // DateTimeException: epoch-second value outside the supported Instant range. throw new ArtifactTokenException(HttpStatus.UNAUTHORIZED, "artifact token invalid"); } } diff --git a/src/test/java/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTest.java b/src/test/java/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTest.java new file mode 100644 index 00000000..af09b162 --- /dev/null +++ b/src/test/java/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTest.java @@ -0,0 +1,99 @@ +package com.clearfolio.viewer.fuzz; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.UUID; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.junit.FuzzTest; + +import com.clearfolio.viewer.artifact.ArtifactLinkService; +import com.clearfolio.viewer.artifact.ArtifactTokenException; +import com.clearfolio.viewer.artifact.InMemoryArtifactStore; + +/** + * Fuzzes {@link ArtifactLinkService}'s artifact-token verification path. + * + *

The token string is fully attacker-controlled (query parameter or bearer + * header). {@link ArtifactLinkService#verifyReadToken} splits it, HMAC-verifies + * it, then Base64URL-decodes and parses ten fields (including a {@link UUID}, + * two {@code Long}s and two {@link java.time.Instant}s). The invariant under + * test: for any input the method must fail with the controlled + * {@link ArtifactTokenException} (mapped to a 4xx) and never leak an + * unhandled runtime exception (which would surface as a 500). + * + *

To exercise the deep decode/parse path -- not just the signature gate -- + * the harness forges structurally valid, correctly-signed tokens using a known + * secret, mirroring {@code ArtifactLinkService.sign}. This is what surfaced the + * previously uncaught {@link java.time.DateTimeException} thrown by + * {@code Instant.ofEpochSecond} on out-of-range epoch seconds. + */ +final class ArtifactTokenParserFuzzTest { + + private static final String SECRET = "clearfolio-fuzz-artifact-secret"; + private static final Base64.Encoder ENCODER = Base64.getUrlEncoder().withoutPadding(); + + private final ArtifactLinkService service = + new ArtifactLinkService(new InMemoryArtifactStore(), SECRET); + + @FuzzTest(maxDuration = "60s") + void verifyReadTokenNeverThrowsUnhandled(FuzzedDataProvider data) { + boolean forgeSignature = data.consumeBoolean(); + UUID routeDocId = new UUID(data.consumeLong(), data.consumeLong()); + + String token; + if (forgeSignature) { + // Build a token with a valid HMAC so parsing runs to completion. + String version = data.consumeBoolean() ? "v1" : data.consumeString(8); + UUID docId = new UUID(data.consumeLong(), data.consumeLong()); + String[] fields = { + version, + data.consumeString(24), // tokenId + data.consumeString(24), // tenantId + data.consumeString(24), // subjectId + data.consumeBoolean() ? docId.toString() + : data.consumeString(40), // docId (valid UUID or garbage) + data.consumeString(24), // scope + data.consumeString(24), // purpose + data.consumeString(64), // artifactChecksum + Long.toString(data.consumeLong()), // issuedAt epoch seconds + Long.toString(data.consumeLong()), // expiresAt epoch seconds + }; + token = sign(fields); + } else { + // Fully arbitrary token: exercises the split + signature-gate path. + token = data.consumeRemainingAsString(); + } + + try { + service.verifyReadToken(routeDocId, null, new byte[0], token); + } catch (ArtifactTokenException expected) { + // Controlled failure -> 4xx. Correct behavior for hostile input. + } + } + + private static String sign(String[] fields) { + StringBuilder payload = new StringBuilder(); + for (int i = 0; i < fields.length; i++) { + if (i > 0) { + payload.append('.'); + } + payload.append(ENCODER.encodeToString(fields[i].getBytes(StandardCharsets.UTF_8))); + } + String signature = hmac(payload.toString()); + return payload + "." + signature; + } + + private static String hmac(String payload) { + try { + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(SECRET.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); + return ENCODER.encodeToString(mac.doFinal(payload.getBytes(StandardCharsets.UTF_8))); + } catch (java.security.GeneralSecurityException ex) { + throw new IllegalStateException("test HMAC failed", ex); + } + } +} diff --git a/src/test/java/com/clearfolio/viewer/fuzz/DocumentValidationFuzzTest.java b/src/test/java/com/clearfolio/viewer/fuzz/DocumentValidationFuzzTest.java new file mode 100644 index 00000000..89bb0dd3 --- /dev/null +++ b/src/test/java/com/clearfolio/viewer/fuzz/DocumentValidationFuzzTest.java @@ -0,0 +1,48 @@ +package com.clearfolio.viewer.fuzz; + +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.junit.FuzzTest; + +import com.clearfolio.viewer.config.ConversionProperties; +import com.clearfolio.viewer.controller.InMemoryMultipartFile; +import com.clearfolio.viewer.service.DefaultDocumentValidationService; +import com.clearfolio.viewer.service.PolicyOverrideRequest; + +/** + * Fuzzes {@link DefaultDocumentValidationService#validateOrThrow}, the upload + * gate that runs before any conversion work. + * + *

Every input is untrusted: the original filename (parsed for its + * extension), the raw file bytes, and the three policy-override HTTP headers. + * The documented contract is that invalid uploads are rejected with an + * {@link IllegalArgumentException} (its subclass + * {@code UnsupportedDocumentFormatException} included) -- so the invariant is + * that no other throwable ever escapes for arbitrary input. + */ +final class DocumentValidationFuzzTest { + + private final DefaultDocumentValidationService validator = + new DefaultDocumentValidationService(new ConversionProperties()); + + @FuzzTest(maxDuration = "60s") + void validateOrThrowOnlyRejectsWithIllegalArgument(FuzzedDataProvider data) { + String filename = data.consumeBoolean() ? null : data.consumeString(64); + String contentType = data.consumeBoolean() ? null : data.consumeString(32); + byte[] content = data.consumeBytes(data.consumeInt(0, 4096)); + + String policyOverride = data.consumeBoolean() ? null : data.consumeString(16); + String approvalToken = data.consumeBoolean() ? null : data.consumeString(32); + String approverId = data.consumeRemainingAsString(); + + InMemoryMultipartFile file = + new InMemoryMultipartFile("file", filename, contentType, content); + PolicyOverrideRequest override = + PolicyOverrideRequest.of(policyOverride, approvalToken, approverId); + + try { + validator.validateOrThrow(file, override); + } catch (IllegalArgumentException expected) { + // Documented rejection path (covers UnsupportedDocumentFormatException). + } + } +} diff --git a/src/test/java/com/clearfolio/viewer/fuzz/TenantClaimsFuzzTest.java b/src/test/java/com/clearfolio/viewer/fuzz/TenantClaimsFuzzTest.java new file mode 100644 index 00000000..c44c6e0a --- /dev/null +++ b/src/test/java/com/clearfolio/viewer/fuzz/TenantClaimsFuzzTest.java @@ -0,0 +1,61 @@ +package com.clearfolio.viewer.fuzz; + +import java.util.Optional; + +import org.springframework.http.HttpHeaders; +import org.springframework.web.server.ResponseStatusException; + +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.junit.FuzzTest; + +import com.clearfolio.viewer.auth.TenantAccessService; +import com.clearfolio.viewer.auth.TenantContext; +import com.clearfolio.viewer.auth.TenantPermissions; + +/** + * Fuzzes tenant-claim parsing from untrusted request headers. + * + *

{@link TenantContext#fromHeaders} normalizes the tenant/subject/permission + * headers, and {@link TenantAccessService#require} additionally parses the + * signed-claims {@code Issued-At} timestamp and compares an HMAC signature. + * Invariants under test: + *

    + *
  • {@code fromHeaders} never throws for any header combination; and
  • + *
  • {@code require} only ever fails with {@link ResponseStatusException} + * (never an unhandled {@link NumberFormatException} from the timestamp or + * any other runtime exception).
  • + *
+ */ +final class TenantClaimsFuzzTest { + + private final TenantAccessService accessService = + new TenantAccessService("clearfolio-fuzz-claims-secret", 300L); + + @FuzzTest(maxDuration = "60s") + void headerClaimsParsingIsRobust(FuzzedDataProvider data) { + HttpHeaders headers = new HttpHeaders(); + addFuzzedHeader(headers, TenantContext.TENANT_ID_HEADER, data); + addFuzzedHeader(headers, TenantContext.SUBJECT_ID_HEADER, data); + addFuzzedHeader(headers, TenantContext.PERMISSIONS_HEADER, data); + addFuzzedHeader(headers, TenantContext.CLAIMS_ISSUED_AT_HEADER, data); + addFuzzedHeader(headers, TenantContext.CLAIMS_SIGNATURE_HEADER, data); + + // Must never throw: pure normalization of arbitrary header values. + Optional context = TenantContext.fromHeaders(headers); + if (context.isPresent()) { + context.get().canonicalPermissions(); + } + + try { + accessService.require(headers, TenantPermissions.JOB_CREATE); + } catch (ResponseStatusException expected) { + // Controlled 4xx rejection for missing/invalid/forged claims. + } + } + + private static void addFuzzedHeader(HttpHeaders headers, String name, FuzzedDataProvider data) { + if (data.consumeBoolean()) { + headers.add(name, data.consumeString(48)); + } + } +} diff --git a/src/test/resources/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTestInputs/verifyReadTokenNeverThrowsUnhandled/regression-datetime-epoch-overflow b/src/test/resources/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTestInputs/verifyReadTokenNeverThrowsUnhandled/regression-datetime-epoch-overflow new file mode 100644 index 00000000..61a3f411 Binary files /dev/null and b/src/test/resources/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTestInputs/verifyReadTokenNeverThrowsUnhandled/regression-datetime-epoch-overflow differ diff --git a/src/test/resources/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTestInputs/verifyReadTokenNeverThrowsUnhandled/seed-forged b/src/test/resources/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTestInputs/verifyReadTokenNeverThrowsUnhandled/seed-forged new file mode 100644 index 00000000..b0bf93df Binary files /dev/null and b/src/test/resources/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTestInputs/verifyReadTokenNeverThrowsUnhandled/seed-forged differ diff --git a/src/test/resources/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTestInputs/verifyReadTokenNeverThrowsUnhandled/seed-garbage b/src/test/resources/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTestInputs/verifyReadTokenNeverThrowsUnhandled/seed-garbage new file mode 100644 index 00000000..2d089b5a --- /dev/null +++ b/src/test/resources/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTestInputs/verifyReadTokenNeverThrowsUnhandled/seed-garbage @@ -0,0 +1 @@ +not-a-token \ No newline at end of file diff --git a/src/test/resources/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTestInputs/verifyReadTokenNeverThrowsUnhandled/seed-raw-tenparts b/src/test/resources/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTestInputs/verifyReadTokenNeverThrowsUnhandled/seed-raw-tenparts new file mode 100644 index 00000000..7869c541 --- /dev/null +++ b/src/test/resources/com/clearfolio/viewer/fuzz/ArtifactTokenParserFuzzTestInputs/verifyReadTokenNeverThrowsUnhandled/seed-raw-tenparts @@ -0,0 +1 @@ +v1.aaa.bbb.ccc.ddd.eee.fff.ggg.hhh.iii.sig \ No newline at end of file diff --git a/src/test/resources/com/clearfolio/viewer/fuzz/DocumentValidationFuzzTestInputs/validateOrThrowOnlyRejectsWithIllegalArgument/seed-blocked-override b/src/test/resources/com/clearfolio/viewer/fuzz/DocumentValidationFuzzTestInputs/validateOrThrowOnlyRejectsWithIllegalArgument/seed-blocked-override new file mode 100644 index 00000000..b63f2fae Binary files /dev/null and b/src/test/resources/com/clearfolio/viewer/fuzz/DocumentValidationFuzzTestInputs/validateOrThrowOnlyRejectsWithIllegalArgument/seed-blocked-override differ diff --git a/src/test/resources/com/clearfolio/viewer/fuzz/DocumentValidationFuzzTestInputs/validateOrThrowOnlyRejectsWithIllegalArgument/seed-noext b/src/test/resources/com/clearfolio/viewer/fuzz/DocumentValidationFuzzTestInputs/validateOrThrowOnlyRejectsWithIllegalArgument/seed-noext new file mode 100644 index 00000000..34dea4fb --- /dev/null +++ b/src/test/resources/com/clearfolio/viewer/fuzz/DocumentValidationFuzzTestInputs/validateOrThrowOnlyRejectsWithIllegalArgument/seed-noext @@ -0,0 +1 @@ +noext \ No newline at end of file diff --git a/src/test/resources/com/clearfolio/viewer/fuzz/DocumentValidationFuzzTestInputs/validateOrThrowOnlyRejectsWithIllegalArgument/seed-pdf b/src/test/resources/com/clearfolio/viewer/fuzz/DocumentValidationFuzzTestInputs/validateOrThrowOnlyRejectsWithIllegalArgument/seed-pdf new file mode 100644 index 00000000..20673280 Binary files /dev/null and b/src/test/resources/com/clearfolio/viewer/fuzz/DocumentValidationFuzzTestInputs/validateOrThrowOnlyRejectsWithIllegalArgument/seed-pdf differ diff --git a/src/test/resources/com/clearfolio/viewer/fuzz/TenantClaimsFuzzTestInputs/headerClaimsParsingIsRobust/seed-bad-timestamp b/src/test/resources/com/clearfolio/viewer/fuzz/TenantClaimsFuzzTestInputs/headerClaimsParsingIsRobust/seed-bad-timestamp new file mode 100644 index 00000000..f15c2c7e Binary files /dev/null and b/src/test/resources/com/clearfolio/viewer/fuzz/TenantClaimsFuzzTestInputs/headerClaimsParsingIsRobust/seed-bad-timestamp differ diff --git a/src/test/resources/com/clearfolio/viewer/fuzz/TenantClaimsFuzzTestInputs/headerClaimsParsingIsRobust/seed-empty b/src/test/resources/com/clearfolio/viewer/fuzz/TenantClaimsFuzzTestInputs/headerClaimsParsingIsRobust/seed-empty new file mode 100644 index 00000000..40b450dd Binary files /dev/null and b/src/test/resources/com/clearfolio/viewer/fuzz/TenantClaimsFuzzTestInputs/headerClaimsParsingIsRobust/seed-empty differ diff --git a/src/test/resources/com/clearfolio/viewer/fuzz/TenantClaimsFuzzTestInputs/headerClaimsParsingIsRobust/seed-full b/src/test/resources/com/clearfolio/viewer/fuzz/TenantClaimsFuzzTestInputs/headerClaimsParsingIsRobust/seed-full new file mode 100644 index 00000000..31446a75 --- /dev/null +++ b/src/test/resources/com/clearfolio/viewer/fuzz/TenantClaimsFuzzTestInputs/headerClaimsParsingIsRobust/seed-full @@ -0,0 +1 @@ +acmealicejob:create100sig \ No newline at end of file