Lily Design System™ is a component library. It ships markup, ARIA, focus management, and keyboard behaviour — no server, no database, no network calls, and no data of its own. That shapes what a security report about Lily can be, and this document says so specifically rather than borrowing a policy written for software that holds data.
Only the most recent release is supported. There are no maintenance branches, no long-term-support line, and no backports. Lily is pre-1.0 and maintained by one unpaid person; a maintenance line is a commitment that needs people behind it, and GOVERNANCE.md and MAINTAINERS.md record honestly how many there currently are.
| Artifact | Version line | What is supported |
|---|---|---|
| The headless packages (npm) | 0.x |
the newest published version, and nothing older |
| The helper packages (npm, NuGet) | their own 0.x line per package |
the newest published version |
| The monorepo and example applications | 0.x |
the newest tag |
A fix lands on main and ships in the next published version. Nothing is
retro-fitted: a published npm version is immutable, so the only remedy for any
defect is a new version. If you are not on the newest release, you are receiving no
fixes, and the action is to upgrade.
Known-bad versions. Versions 0.2.0 of @lilydesignsystem/svelte-headless,
-react-headless, and -vue-headless are unusable — they declared an entry point
that was never built. Not a security defect, but recorded here because "upgrade" is
the answer to it too.
Please do not open a public issue for a suspected vulnerability.
Email joel@joelparkerhenderson.com with SECURITY in the subject line. There
is no security team; the maintainer is the whole path.
If GitHub private vulnerability reporting is enabled on the repository, that route works too — but email is the documented one, because it does not depend on a setting this document cannot verify for you.
Include what you can: the affected component or package, the version, reproduction steps or a proof of concept, an impact assessment, and any suggested fix.
- An acknowledgement within 5 working days. If you have not heard anything by then, the report has not reached me; escalate by opening a public issue saying only that a private report is awaiting acknowledgement, with no details.
- An assessment with a severity and an intended fix window within 10 working days of the acknowledgement.
- Coordinated disclosure: a date agreed with you rather than imposed on you, and word from me when the fix ships.
These are commitments to you, not conditions on you. If they are missed, publishing is your call.
I will not pursue or support legal action against anyone who reports a vulnerability in good faith and follows this policy. In practice that means you tested against your own deployment or a test instance you control, you did not access, modify, or retain anyone else's data, you did not degrade service for others, and you gave the window above before publishing. If you are unsure whether something is in scope, ask first; a question is always in good faith.
Reporters are named in the advisory and in CHANGELOG.md by default, using whatever name and link you give. Say so if you would rather not be named; declining credit costs you nothing and changes nothing about how the report is handled.
- Markup that enables injection. A component that interpolates a prop into
markup in a way that permits script execution, attribute injection, or
hrefscheme abuse. - ARIA or focus behaviour that can be weaponised — a focus trap that cannot be escaped, a live region an attacker can drive, a dialog that does not confine focus.
- Supply-chain problems in the published packages: an unexpected dependency, a
postinstall script, files in the tarball that should not be there. The
0.2.0packages shipped entire source trees by accident, so this class is real here. - The helper packages' DOM writes. They set
data-theme,lang,dir, anddata-text-sizeon the document root, swap a managed<link rel="stylesheet">href, and optionally writelocalStorage. Anything that makes one of those escape its intended shape is in scope. - The published documentation site,
lilydesignsystem.github.io.
Stated plainly so you do not waste effort:
- Consumer misuse of a documented prop.
theme-pickerbuilds its stylesheet URL by concatenation —normaliseThemesUrl(themesUrl) + slug + extension— and sets it on a<link>. Those props are developer-supplied configuration, not user input, and the component trusts them by design. A consumer who wires untrusted input intothemesUrlorthemeshas created a vector on their side of the boundary. That boundary is the design; if you think it is the wrong design, that is a valid RFC.md discussion rather than a vulnerability report. - The example applications' demo rendering. The
/components/{slug}pages inject demo markup through{@html},dangerouslySetInnerHTML,v-html,MarkupString, and| safe. The content is a static, in-repo map authored by the project — not user input — so it is safe there. It is not a pattern to copy with untrusted content, and that warning is the useful output of this scope note. A report that the demo map itself contains something harmful is in scope. - Missing security headers on the docs site. It is GitHub Pages; the headers are GitHub's.
- Vulnerabilities in a framework Lily targets — Svelte, React, Vue, Angular, Blazor, Nunjucks, or a bundler. Report those upstream.
- Automated scanner output with no analysis attached. A dependency listed in a lockfile is not necessarily reachable from a built artifact; say why it is.
These are claims a reader can check against the tree rather than take on trust, and they are why Lily's attack surface is small:
- The headless layer performs no data fetching, no network calls, and no persistence. This is a design rule, not an accident — AGENTS/headless.md § Behavior boundaries.
- No telemetry and no analytics anywhere. Nothing about your use of Lily reaches the project.
- No personal data in the repository — not in fixtures, not in demo content. The 164 national identifier components validate identifier formats; their test fixtures are synthetic values constructed to satisfy the algorithms, not real identifiers belonging to real people.
- No bundled fonts, images, or icon assets. The picker glyphs are Unicode characters, not files.
sideEffects: falseon the published packages: importing Lily runs nothing.
Settings live in GitHub, not in the tree, so they can be changed without a commit and
reset without anyone noticing. This table records what the posture is supposed to
be. Read it back with
gh api repos/LilyDesignSystem/lily-design-system --jq '.security_and_analysis' and
treat a divergence as a finding.
| Setting | Expected | Why |
|---|---|---|
| Secret scanning | enabled | the baseline detector |
| Push protection | enabled | refuses the commit rather than filing an alert afterwards |
| Private vulnerability reporting | enabled | the alternative reporting route named above |
| Dependabot security updates | enabled | advisory-driven bumps across many package manifests |
Branch protection on main |
active — no force-push, no deletion | |
| npm publishing | two-factor authentication required; publishes carry --provenance |
the publishing identity is one account; see MAINTAINERS.md |
Registry tokens (NPM_TOKEN) |
named CI secret only, real publishes gated on manual dispatch; slated for OIDC Trusted Publishing once it covers all three forges (not met as of 2026-09 — Codeberg unsupported) | a leaked long-lived token is the classic supply-chain path; the interim mitigation and the adoption trigger are written down |
| NuGet publishing | OIDC Trusted Publishing (adopted 2026-09): a NUGET_USER secret names the nuget.org profile, not a credential; the actual push key is a 1-hour token minted per run by NuGet/login@v1 and never stored |
no long-lived NuGet key exists to leak |
Note
Verified 2026-08-26 across all 23 repositories: secret scanning, push
protection, private vulnerability reporting, and Dependabot security updates
are enabled. Branch protection on main and npm 2FA are not readable
from the public API and remain intended-but-unconfirmed here. Two further
toggles — non-provider secret patterns and validity checks — are UI-only
(the API accepts and ignores them) and are still off; enabling them is an
open maintainer task.
Lily is one dependency in your stack. Using it does not make an application accessible, and it does not make one secure. In particular: Lily targets WCAG 2.2 AAA and has never been audited (AI_STATEMENT.md §12), so if your own compliance obligations require an assurance, that assurance does not currently exist and must be commissioned — the accessibility statement states exactly what is and is not verified, and docs/audit-readiness.md holds the scope an auditor would need. CONTRIBUTING.md names an independent accessibility audit as the highest-value thing sponsorship could fund.
Lily™ and Lily Design System™ are trademarks.