OpenClear

Home / Docs / Data and limits

Inputs, limits and outside connections

What OpenClear accepts, how it checks it, what limits protect it, and every outside system it talks to. It answers ASVS 5.0 2.1.1–2.1.3, 5.1.1, 13.1.1, 13.2.4, 14.1.1, 14.1.2, 15.1.1 and 15.1.3. How sensitive each kind of data is, and the protection each level needs, is in the risk profile.

Input validation

Everything is checked on the server: the browser's checks are only a convenience.

Input Checked by Rules
API requests Pydantic schemas per endpoint (schemas/) Types, required fields, lengths, enumerations; unknown fields can't set anything (ASVS 15.3.3). Invalid requests get 422 with the fields at fault.
Web forms The route's typed form fields and the service it calls As the API, plus a CSRF token on every change
Issued-check files: CSV, fixed width, Excel bulk_import/tabular.py, layouts.py, fields.py Each row on its own: an account that exists and is in scope, and a valid check number, amount, payee and issue date. A bad row is reported with its reason and the good rows still load (OC-SI-02).
X9.37 image cash letters bulk_import/x937.py Record structure and lengths, EBCDIC or ASCII, images read one check at a time
NACHA ACH files bulk_import/nacha.py, networks/ach/ Record types and lengths, batch and file control totals
Zip archives of images bulk_import/zip_import.py Declared and actual uncompressed size, names stripped of directories
Images (TIFF, JPEG, PNG) bulk_import/images.py Decoded with Pillow's decompression-bomb limit, then re-encoded to PNG; anything else refused
Markdown (banners, messages) web/templates.py Rendered, then sanitized with nh3 to an allowlist of tags
URLs for webhooks, SIEM and SSO auth/outbound_http.py https, no credentials, and only public addresses, checked again on each connection

Business rules and limits

  • Sequence: a decision applies only to an open exception before its return deadline; a decided exception can't be decided again; dual control and segregation of duties hold whatever the order of requests (services/, OC-AC-05, OC-AC-06).
  • Per person and system: 600 requests a minute; per IP address, 120 a minute; token requests and one-time links, 30 a minute (authentication).
  • Per request: 50 MB (max_request_body_bytes); a zip may expand to 200 MB (max_zip_uncompressed_bytes).

Files

Kind Types Largest
Issued checks, people, accounts, ACH CSV, fixed width, Excel (.xlsx) 50 MB a request
Presented checks with images X9.37 image cash letters, or a CSV with a zip of images 50 MB uploaded, 200 MB unzipped
Check images TIFF (one or two pages), JPEG, PNG 50 MB; stored as PNG
ACH NACHA 50 MB
Branding PNG, JPEG, ICO (no SVG) 50 MB a request

Uploaded files are stored under generated names, never served back except to people of the bank that uploaded them, and kept with their SHA-256 and a signature (OC-SC-03).

Malware. Every upload, through the web, the API or the drop folder, can be checked before anything reads it (services/malware_service.py; OWASP_PLAN.md OW-D34). Both checks are off until the service provider turns them on:

  • ClamAV: the file is streamed to clamd (malware_clamd_address). If clamd can't answer, the upload is refused (malware_clamd_on_error = "accept" lets it through instead).
  • VirusTotal: only the file's SHA-256 is looked up (malware_virustotal_api_key), never the file, since files sent there are shared with third parties (ADR 0007). If VirusTotal can't answer, the upload is accepted and the hash asked about again every hour for malware_recheck_days (7); malware_virustotal_on_error = "refuse" refuses it instead.

Malware is refused; a file found to be malware later is quarantined (never processed or downloaded again). Either way there's a high-severity file.malware_detected security event, an action-log entry and an email to the bank's administrators. The bank's own malware detection is a CUEC whether or not these are on (B-SI-3-01).

Outside connections

OpenClear connects only to these, and only to public addresses; each is off until configured, and each bank reviews the ones it uses (Settings → Outside services).

System Why Set by
The bank's identity provider(s) (OIDC discovery, token, JWKS; SAML metadata is uploaded) Single sign-on Bank
The bank's SIEM (Splunk HEC, syslog over TLS) Security events Bank or service provider
Webhook receivers Decisions and events to the bank's systems Bank
Email (SMTP) and SMS (Twilio) providers Notifications Service provider
Cloud OCR (Amazon Textract, Azure Document Intelligence) Reading check images, if chosen over the built-in Tesseract Service provider
Object storage (S3-compatible, Azure Blob) Files, if chosen over local disk Service provider
Redis Shared rate-limit counters across instances Service provider
GitHub's releases API Checking for a newer OpenClear (no data sent) Service provider (release_feed_url)
Have I Been Pwned's range API Breached-password check, if turned on (only 5 hash characters sent) Service provider
ClamAV (clamd, usually beside OpenClear) Malware scan of every upload, if turned on Service provider
VirusTotal's file API Malware verdict on each upload's SHA-256, if turned on (never the file) Service provider

Inbound, OpenClear is called by browsers, the bank's systems and customers' systems through the API, the bank's directory (SCIM), identity providers (SAML posts, back-channel logout), and online banking (embedded sessions).

Keeping dependencies current

A known vulnerability in a dependency with a fix available fails the build (pip-audit), unless waived in .pip-audit-waivers.toml with a reason and an expiry. Fixed releases follow the time frames in SECURITY.md: 7 days for critical, 30 for high, 90 for medium, the next release for low. Dependabot and a weekly lock refresh propose updates; every release publishes an SBOM.

Work that takes time

These are bounded so one request can't exhaust the server:

Work How it's bounded
Large uploads (X9.37, zips) Request size limit; images read one at a time; processed as background jobs
Data exports A background job with a time limit (data_export_timeout_seconds, default 3600)
Replay of a historical file through new rules A background job (OC-SI-04)
Action-log verification and archiving Background jobs, on a schedule
OCR of check images Background jobs; Tesseract has a per-image time limit
Model training A background job, only by the service provider's operators
Password hashing bcrypt's cost, behind the sign-in rate limits

Built from docs/security/data-and-limits.md in the OpenClear repository. Last changed October 18, 2026.

See positive pay from the bank's side

Start a free sandbox bank with sample checks, ACH debits and exceptions.

Start a sandbox bank