Skip to content

Security: raj-khan/flow

Security

SECURITY.md

Security notes

Flow has no accounts, no server and no secrets yet. The decisions below are the ones that will matter once it has them.

Trust boundaries

Input Where it enters Treated as
A document flowApi.ensureLoaded Untrusted: shape is normalised at the adapter, unknown node types fall back to a safe entry rather than rendering nothing
A shared link useOpenSharedLink Untrusted: the fragment is decompressed and read by parseFlow, like typed text; a damaged one is refused with a message, and opening one is an undoable change
Imported text The Import dialog and the text pane Untrusted: parsed by pure functions that never evaluate it; YAML is read as data only, with no custom tags; the result is rendered as text like any document
Form fields The drawer and create dialog Untrusted: validated before a mutation, capped in length
localStorage ensureLoaded Untrusted: parsed in a try, falls back to a sample when it holds anything unexpected

Cross-site scripting

Nothing in the app uses v-html. Every document string, shape title, description and edge label goes through Vue's text interpolation, which escapes it. Shape outlines are SVG path data computed from numbers in src/domain/shapes.js, never from document text.

The one thing to keep watching: if a future requirement asks for formatted labels, the answer is a sanitiser with an allowlist, not v-html.

Network

The app makes no requests of its own. The samples are bundled into the build and every edit is saved to localStorage, so there is no proxy, no CORS surface and nothing to configure. When a real backend lands (see BACKLOG.md), it replaces src/api/flowApi.js and this section returns.

Headers

docker/nginx.conf serves the production build. For a real deployment it should also carry:

Header Value Against
Content-Security-Policy default-src 'self'; img-src 'self' data: https:; style-src 'self' 'unsafe-inline' Injected scripts
X-Content-Type-Options nosniff MIME confusion
Referrer-Policy strict-origin-when-cross-origin Leaking URLs, which contain node ids
X-Frame-Options DENY Clickjacking

unsafe-inline for styles is what Vue's scoped styles and the canvas transforms need; scripts do not require it.

Secrets

There are none, and .env is gitignored so it stays that way. Note that VITE_* variables are inlined into the bundle at build time and are readable by anyone with the page, so nothing secret may ever be named with that prefix.

Dependencies

Seven runtime dependencies. npm audit is clean at the time of writing. CI installs with npm ci, which fails if package.json and the lockfile disagree, so a dependency cannot change without the lockfile change being in the diff.

There aren't any published security advisories