Description
The partner/org Website field accepts any string, including javascript: and data: URIs. There is no scheme validation and no URL validation of any kind:
// apps/api/src/routes/orgs.ts:482
website: z.string().optional()
Entered via Settings → Partner → Company. Saved and returned verbatim.
Exploitability today: none that I could find — but that is a property of the current UI, not of the data
The QA sweep looked for a renderer and found no <a href={...website}> consuming this field, so there is no live stored-XSS path right now. I am reporting it as a missing control, not a live vulnerability, and deliberately not claiming more than that.
Two reasons it still matters:
- The guard belongs at the boundary, not at each renderer. A field named
website is going to end up in an href eventually — that is what it is for. Whoever adds that link will reasonably assume the stored value is a URL, because the field is called Website. Note there is already an href={branding.websiteUrl} at apps/web/src/components/software/BuiltinPackageDetail.tsx:64; I did not confirm whether that value can trace back to this field, and that trace is worth doing as part of the fix.
- The repo already has the pattern.
packages/shared/src/validators/remoteAccessLauncherScheme.ts exists precisely to allowlist schemes, with tests. This field should use the same approach rather than inventing one.
The release checklist for this cycle explicitly asked that Partner settings reject javascript:/data:, which is how this surfaced.
Proposed fix
Validate as a URL with an http/https allowlist, in packages/shared/src/validators/ so both the API schema and the web form can share it, following the remoteAccessLauncherScheme precedent. Reject rather than silently strip — a silently-cleared field looks like a save failure.
Worth grepping for sibling fields while in there (supportUrl, logoUrl, documentationUrl, any other z.string() that names a URL) — this is likely a class, not a single field.
Affected files
apps/api/src/routes/orgs.ts:482
apps/web/src/components/settings/PartnerCompanyTab.tsx
- Precedent to follow:
packages/shared/src/validators/remoteAccessLauncherScheme.ts
Reported By: internal Playwright UI QA sweep 2026-08-11, evidence in docs/testing/FEATURE_TEST_LOG.md.
Description
The partner/org Website field accepts any string, including
javascript:anddata:URIs. There is no scheme validation and no URL validation of any kind:Entered via Settings → Partner → Company. Saved and returned verbatim.
Exploitability today: none that I could find — but that is a property of the current UI, not of the data
The QA sweep looked for a renderer and found no
<a href={...website}>consuming this field, so there is no live stored-XSS path right now. I am reporting it as a missing control, not a live vulnerability, and deliberately not claiming more than that.Two reasons it still matters:
websiteis going to end up in anhrefeventually — that is what it is for. Whoever adds that link will reasonably assume the stored value is a URL, because the field is called Website. Note there is already anhref={branding.websiteUrl}atapps/web/src/components/software/BuiltinPackageDetail.tsx:64; I did not confirm whether that value can trace back to this field, and that trace is worth doing as part of the fix.packages/shared/src/validators/remoteAccessLauncherScheme.tsexists precisely to allowlist schemes, with tests. This field should use the same approach rather than inventing one.The release checklist for this cycle explicitly asked that Partner settings reject
javascript:/data:, which is how this surfaced.Proposed fix
Validate as a URL with an
http/httpsallowlist, inpackages/shared/src/validators/so both the API schema and the web form can share it, following theremoteAccessLauncherSchemeprecedent. Reject rather than silently strip — a silently-cleared field looks like a save failure.Worth grepping for sibling fields while in there (
supportUrl,logoUrl,documentationUrl, any otherz.string()that names a URL) — this is likely a class, not a single field.Affected files
apps/api/src/routes/orgs.ts:482apps/web/src/components/settings/PartnerCompanyTab.tsxpackages/shared/src/validators/remoteAccessLauncherScheme.tsReported By: internal Playwright UI QA sweep 2026-08-11, evidence in
docs/testing/FEATURE_TEST_LOG.md.