Security posture
This page is the whole security model in one place, including the parts a marketing page would soften. Read it before exposing anything to the internet.
The headline: there is no authentication
Section titled “The headline: there is no authentication”Version 1 ships no auth of any kind. The system is split into a zone you must protect and a zone built to be exposed:
You protect: the editor and the management API
Section titled “You protect: the editor and the management API”Anyone who can reach the editor UI or /api/v1/** can read every
response, edit every questionnaire, download every file, and delete
anything. The management API even sends permissive CORS headers — it
fully assumes the network layer is the boundary.
Protect it with a reverse proxy that authenticates, a VPN, or network policy — concrete configs in Reverse proxy & exposure. This is the single most important operational fact about Forms-Engine.
Designed for exposure: the public runtime API
Section titled “Designed for exposure: the public runtime API”/public/v1/** is what embedded questionnaires call, and its defenses
are:
- Unguessable, non-enumerable ids. A
responseIdis 128 bits of randomness; nothing lists responses publicly, and the reference-status endpoint never returns one. - Per-questionnaire allowed origins, enforced server-side on mutating requests (403) and via withheld CORS headers on reads. Origin checks keep other websites from embedding your questionnaire; they are not authentication, and requests without an Origin header (curl) pass.
- Input caps everywhere: 500 answer keys / 256 KB per response, 10 KB per answer, 1 MB definitions, 128-char references.
- Per-IP rate limits on mutations, uploads, geocoding, and reference status.
The respondent credential: responseId
Section titled “The respondent credential: responseId”Holding a responseId is what it means to be a respondent session.
Anyone with the id can read that response’s answers, modify them, and
upload files to it — until completion freezes it. This is the accepted
posture, consistent with the no-auth model; the protection is that ids
are unguessable and never exposed anywhere except to the browser that
created the session (where it sits in sessionStorage, not cookies).
Consequences worth stating outright:
- Don’t log or forward response ids in your own systems more widely than you’d forward a session token.
- Completion is the freeze point: after it, all respondent-side mutation returns 409.
Uploads
Section titled “Uploads”Anyone holding a responseId can upload to that response, within the
category allowlist, server-side content verification (magic bytes —
the filename and claimed type are never trusted), per-file/per-response
size caps, and the upload rate limit. Executables, scripts, HTML, and SVG
are rejected in every category. Downloads exist only on the
(network-protected) management API, always as attachments with
nosniff — uploaded content is never served inline and never from a
public endpoint, so a malicious upload can’t become a stored-XSS page on
your domain. A no-op scanner hook exists for wiring in
ClamAV or similar.
External references are honor-system
Section titled “External references are honor-system”The external-ref mechanism deduplicates cooperative users and
correlates responses with your records. It is spoofable by construction —
the value comes from your page’s markup — and the reference-status
endpoint necessarily reveals a completed-yes/no boolean per reference.
The full analysis, including why cross-device resume deliberately doesn’t
exist yet, is on
External references.
Injection surfaces, handled
Section titled “Injection surfaces, handled”- Display text is sanitized by construction — author input is entity-escaped before a fixed safe tag set is generated; no raw HTML survives. Details.
- CSV export guards against formula injection: text cells starting
with
=,+,-, or@are quote-prefixed so respondent answers can’t execute in Excel. - Storage paths are server-generated ids only; no user string ever reaches a filesystem or object key.
Known gaps, stated plainly
Section titled “Known gaps, stated plainly”These are roadmap items, not surprises — details on Roadmap & limitations:
- No CAPTCHA / proof-of-work — rate limiting and origin checks are the current bot story.
- No server-side rule re-validation — the public API validates answer shape and size, not questionnaire logic; a hand-crafted client can submit answers a hidden question would have cleared.
- No signed references — hence the honor-system caveats above.
- In-progress responses accumulate until you clean them up.
Reporting a vulnerability
Section titled “Reporting a vulnerability”Report suspected vulnerabilities via GitHub issues on the tool repository — or, if the report is sensitive, use GitHub’s private “Report a vulnerability” flow on the repository’s Security tab if available rather than a public issue.