We will be undergoing planned maintenance on Oct 7th 6:00AM UTC / Oct 7th 2:00AM ET

Inspiration

A court message can look completely legitimate and still contain one instruction you should not trust.

SEAL started as a scam detector.

That approach broke quickly. A real court name does not authenticate a message, and a missing public record does not prove fraud.

So we changed the question:

What is this message asking me to do, and what can I independently verify before I do it?

That became SEAL.

What it does

SEAL checks court messages against information outside the message itself.

Upload a screenshot, image, PDF, or paste the message directly.

SEAL finds the details that could change what you do next:

  • court identity
  • phone numbers
  • URLs
  • reporting dates
  • payment instructions
  • contact requests
  • requests for personal information

Each claim is checked independently.

MATCH
An independent source supports it.

MISMATCH
Independent evidence directly contradicts it.

COULD_NOT_VERIFY
The evidence is not strong enough.

SEAL does not reduce the whole message to one legitimacy score.

A single notice can contain a real court name, a conflicting payment instruction, and a reporting date that cannot be independently confirmed.

The original message stays visible beside the evidence and the next step.

How we built it

We split SEAL into two systems:

understand the message

verify what it says

PDF.js reads text PDFs. Tesseract.js handles images and scanned documents in the browser. The recovered content is turned into structured claims and validated with Zod.

A language model can help structure messy text, but it does not decide whether a message is legitimate.

Those claims move into a separate resolver.

The uploaded message is never allowed to prove itself.

V(c) ∈ { MATCH, MISMATCH, COULD_NOT_VERIFY }

V(c) ∈ { MATCH, MISMATCH }
requires
|E(c)| ≥ 1

For a mismatch, the evidence must directly contradict the claim.

Otherwise the result stays unresolved.

No evidence, no verdict.

The resolver enforces that rule.

A failed search does not become proof of fraud.

An OCR guess is not promoted into a verified claim.

If official sources disagree, SEAL keeps the result unresolved and preserves the conflict.

The first fully reviewed flow covers jury-duty impersonation messages involving the U.S. District Court for the District of Connecticut.

We also kept Riverside Superior Court as regression coverage, including a real case where two official pages publish conflicting jury numbers.

SEAL returns COULD_NOT_VERIFY instead of choosing one.

The app is built with React and TypeScript, with unit tests, browser reliability tests, verification benchmarks, and live sanity checks around the core flow.

Challenges we ran into

The hardest part was not finding information.

It was knowing when we had enough evidence to make a conclusion.

Court systems are fragmented. Some publish clear records. Others expose very little.

OCR can change one digit in a phone number.

A source can disappear.

Two official pages can even disagree.

Our early versions were too eager to turn those situations into answers.

We kept tightening the resolver until uncertainty stayed uncertainty.

The interface was another challenge.

Our first result screens had the right information but made users work too hard to separate the original message from SEAL's interpretation and the outside evidence.

A lot of the final sprint became reliability work: stale state, document previews, parallel checks, mobile behavior, loading states, and evidence presentation.

Accomplishments that we're proud of

We are proud that SEAL can refuse to answer.

Always returning a confident result would have been easier.

Instead, MATCH and MISMATCH have to earn their way through the resolver.

Our current 15-case engineering benchmark includes:

  • public court documents
  • controlled single-field alterations
  • unsupported jurisdictions
  • degraded OCR
  • prompt injection
  • payment and URL changes
  • private identifiers
  • conflicting official sources

Current fixture-set results:

Metric Result
MISMATCH precision 1.00
False MISMATCH results 0
Full-flow success 0.933
Field extraction accuracy 0.933 to 1.00

These are engineering-fixture measurements, not claims of real-world accuracy.

The number we care about most is:

0 false MISMATCH results.

A false accusation can create its own harm.

What we learned

The biggest lesson was:

Verification is not classification.

"91% legitimate" looks simple, but it hides the facts a person actually needs.

A better result is:

  • the court name matches
  • the payment instruction conflicts with official guidance
  • the reporting date could not be independently confirmed

Those are separate facts, and each one can be inspected.

We also learned that provenance has to be visible.

The user should be able to tell:

what the message said

what the outside source said

what SEAL concluded

And sometimes the strongest result is simply:

We do not have enough evidence to establish this.

What's next for SEAL

The next challenge is coverage.

Courts are spread across thousands of jurisdictions, websites, languages, and record systems.

Expanding SEAL responsibly means adding reviewed source routes and claim-specific rules, not just searching more websites.

We also want stronger cross-language verification and portable verification records containing:

  • the claim
  • the verdict
  • the evidence
  • the source
  • the checked time
  • anything that remained unresolved

We started by asking:

Does this look real?

We ended with a better question:

What can we prove before someone acts?

Built With

Share this project:

Updates

Submission history