Summary
The companionUrl field in NewPreset and UpdatePreset schemas accepts any arbitrary string with no URL format validation. An attacker could inject javascript: URIs, data: URLs, or internal network addresses (SSRF) that get stored and later rendered as links.
Affected Files
src/models.ts — NewPreset (~line 412) and UpdatePreset (~line 425)
Vulnerable Code
// models.ts
companionUrl: Type.Optional(Type.String()) // no constraints
companionUrl: Type.Optional(Type.Union([Type.String(), Type.Null()])) // no constraints
Recommendation
Add URI format and pattern constraints at the TypeBox schema level:
companionUrl: Type.Optional(
Type.String({
format: 'uri',
pattern: '^https?://',
maxLength: 2048,
})
)
Also add server-side validation using new URL() before persisting:
if (body.companionUrl) {
try {
const u = new URL(body.companionUrl);
if (!['http:', 'https:'].includes(u.protocol)) throw new Error();
} catch {
reply.code(400).send({ error: 'companionUrl must be a valid http/https URL' });
return;
}
}
Severity
High — Stored SSRF / URL injection in preset management.
Found by automated security audit.
Summary
The
companionUrlfield inNewPresetandUpdatePresetschemas accepts any arbitrary string with no URL format validation. An attacker could injectjavascript:URIs,data:URLs, or internal network addresses (SSRF) that get stored and later rendered as links.Affected Files
src/models.ts—NewPreset(~line 412) andUpdatePreset(~line 425)Vulnerable Code
Recommendation
Add URI format and pattern constraints at the TypeBox schema level:
Also add server-side validation using
new URL()before persisting:Severity
High — Stored SSRF / URL injection in preset management.
Found by automated security audit.