diff --git a/public/de-AT/email_verification_link_expired.html b/public/de-AT/email_verification_link_expired.html index cae39c7a46..6a664c48cd 100644 --- a/public/de-AT/email_verification_link_expired.html +++ b/public/de-AT/email_verification_link_expired.html @@ -14,9 +14,9 @@

{{appName}}

Expired verification link!

-
- - + + +
diff --git a/public/de-AT/password_reset.html b/public/de-AT/password_reset.html index 49cb65b1aa..73cb1e3d52 100644 --- a/public/de-AT/password_reset.html +++ b/public/de-AT/password_reset.html @@ -23,11 +23,11 @@

Reset Your Password

You can set a new Password for your account: {{username}}


{{error}}

-
+ - - - + + +

New Password

diff --git a/public/de/email_verification_link_expired.html b/public/de/email_verification_link_expired.html index cae39c7a46..6a664c48cd 100644 --- a/public/de/email_verification_link_expired.html +++ b/public/de/email_verification_link_expired.html @@ -14,9 +14,9 @@

{{appName}}

Expired verification link!

- - - + + +
diff --git a/public/de/password_reset.html b/public/de/password_reset.html index 49cb65b1aa..73cb1e3d52 100644 --- a/public/de/password_reset.html +++ b/public/de/password_reset.html @@ -23,11 +23,11 @@

Reset Your Password

You can set a new Password for your account: {{username}}


{{error}}

-
+ - - - + + +

New Password

diff --git a/public/email_verification_link_expired.html b/public/email_verification_link_expired.html index cae39c7a46..6a664c48cd 100644 --- a/public/email_verification_link_expired.html +++ b/public/email_verification_link_expired.html @@ -14,9 +14,9 @@

{{appName}}

Expired verification link!

- - - + + +
diff --git a/public/password_reset.html b/public/password_reset.html index 49cb65b1aa..73cb1e3d52 100644 --- a/public/password_reset.html +++ b/public/password_reset.html @@ -23,11 +23,11 @@

Reset Your Password

You can set a new Password for your account: {{username}}


{{error}}

-
+ - - - + + +

New Password

diff --git a/spec/PagesRouter.spec.js b/spec/PagesRouter.spec.js index 0aa5bb357b..009254dfcc 100644 --- a/spec/PagesRouter.spec.js +++ b/spec/PagesRouter.spec.js @@ -1180,4 +1180,72 @@ describe('Pages Router', () => { }); }); }); + + describe('XSS Protection', () => { + beforeEach(async () => { + await reconfigureServer({ + appId: 'test', + appName: 'exampleAppname', + publicServerURL: 'http://localhost:8378/1', + pages: { enableRouter: true }, + }); + }); + + it('should escape XSS payloads in token parameter', async () => { + const xssPayload = '">'; + const response = await request({ + url: `http://localhost:8378/1/apps/choose_password?token=${encodeURIComponent(xssPayload)}&username=test&appId=test`, + }); + + expect(response.status).toBe(200); + expect(response.text).not.toContain(''); + expect(response.text).toContain('"><script>'); + }); + + it('should escape XSS in username parameter', async () => { + const xssUsername = ''; + const response = await request({ + url: `http://localhost:8378/1/apps/choose_password?username=${encodeURIComponent(xssUsername)}&appId=test`, + }); + + expect(response.status).toBe(200); + expect(response.text).not.toContain(''); + expect(response.text).toContain('<img'); + }); + + it('should escape XSS in locale parameter', async () => { + const xssLocale = '">'; + const response = await request({ + url: `http://localhost:8378/1/apps/choose_password?locale=${encodeURIComponent(xssLocale)}&appId=test`, + }); + + expect(response.status).toBe(200); + expect(response.text).not.toContain(''); + expect(response.text).toContain('"><svg'); + }); + + it('should handle legitimate usernames with quotes correctly', async () => { + const username = "O'Brien"; + const response = await request({ + url: `http://localhost:8378/1/apps/choose_password?username=${encodeURIComponent(username)}&appId=test`, + }); + + expect(response.status).toBe(200); + // Should be properly escaped as HTML entity + expect(response.text).toContain('O'Brien'); + // Should NOT contain unescaped quote that breaks HTML + expect(response.text).not.toContain('value="O\'Brien"'); + }); + + it('should handle legitimate usernames with ampersands correctly', async () => { + const username = 'Smith & Co'; + const response = await request({ + url: `http://localhost:8378/1/apps/choose_password?username=${encodeURIComponent(username)}&appId=test`, + }); + + expect(response.status).toBe(200); + // Should be properly escaped + expect(response.text).toContain('Smith & Co'); + }); + }); });