feat: Status Page Custom CSS/JS/HTML overrides (Fixes #2863)
Describe your changes
I have implemented the ability for admins to customize their Status Pages with custom CSS, JavaScript, and HTML overrides for the Header and Footer. This allows teams to brand their status pages without forking the source code.
Backend Changes:
- Updated
StatusPageMongoose schema to includecustomJavaScript,headerHTML, andfooterHTML(added to existingcustomCSS). - Updated Joi validation (
server/validation/joi.js) to allow these string fields during creation and updates.
Frontend Changes:
- Updated
Settings.jsxto include input fields for these new options, ensuring correct name attributes for form saving. - Added translation keys to
en.jsonto ensure no hardcoded strings are used in the UI. - Updated
Settings.jsxto inject the custom CSS/JS viauseEffectand conditionally render the custom HTML Header/Footer if they exist in the database.
Write your issue number after "Fixes "
Fixes #2863
Please ensure all items are checked off before requesting a review. "Checked off" means you need to add an "x" character between brackets so they turn into checkmarks.
- [x] (Do not skip this or your PR will be closed) I deployed the application locally.
- [x] (Do not skip this or your PR will be closed) I have performed a self-review and testing of my code.
- [x] I have included the issue # in the PR.
- [x] I have added i18n support to visible strings (instead of
<div>Add</div>, use):
const { t } = useTranslation();
<div>{t('add')}</div>
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
* **New Features**
* Add fields to enter custom CSS, header HTML, footer HTML, and custom JavaScript for Status Pages; these are applied to the public status page with proper lifecycle handling.
* **Documentation**
* New UI labels, descriptions, placeholders and a JavaScript warning helper for customization fields.
* **Validation**
* Server-side validation enforces optional fields with length limits for CSS, header/footer HTML, and custom JavaScript.
<sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
[!NOTE]
.coderabbit.ymlhas unrecognized propertiesCodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.
⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'release_notes'⚙️ Configuration instructions
- Please see the configuration documentation for more information.
- You can also validate your configuration using the online YAML validator.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation:
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
Walkthrough
Adds customizable fields (Custom CSS, Header HTML, Footer HTML, Custom JavaScript) to the admin UI, schema, validation, and public API; injects and sanitizes CSS/HTML/JS on the public status page client; adds i18n keys and a dompurify dependency.
Changes
| Cohort / File(s) | Change Summary |
|---|---|
Admin UI — Settings form client/src/Pages/v1/StatusPage/Create/Components/Tabs/Settings.jsx |
Added multiline TextFields bound to form.customCSS, form.headerHTML, form.footerHTML, form.customJavaScript; added riskAccepted checkbox gating JS field and an effect that checks it when JS exists; wired to existing handleFormChange. |
Status page rendering (client) client/src/Pages/v1/StatusPage/Status/index.jsx |
Added DOMPurify and useEffect to sanitize and render headerHTML/footerHTML; injects <style> with customCSS into document.head; injects/executed customJavaScript inside an IIFE with try/catch into document.body; cleans up injected nodes on unmount. |
Localization client/src/locales/en.json |
Added i18n keys for customCSS, customHeaderHTML, customFooterHTML, customJavaScript plus descriptions, placeholders, and a JS warning string. |
Client dependencies / build client/package.json |
Added dompurify (^3.3.0) and bumped vite to ^6.4.1. |
Database schema (server) server/src/db/v1/models/StatusPage.js |
Added optional string fields customJavaScript (maxLength 5000), headerHTML (maxLength 10000), and footerHTML (maxLength 10000) with default "". |
Request validation (server) server/src/validation/joi.js |
Extended createStatusPageBodyValidation with optional customCSS (max 10000), customJavaScript (max 5000), headerHTML (max 5000), and footerHTML (max 5000). |
StatusPage module — public API shape server/src/db/v1/modules/statusPageModule.js |
Included customCSS, customJavaScript, headerHTML, and footerHTML in early-return and aggregation projection so public GET returns these fields. |
Sequence Diagram(s)
sequenceDiagram
actor Admin
participant SettingsUI as Admin Settings (client)
participant API as Backend API
participant DB as Database
participant Browser as Public Status Page (browser)
Admin->>SettingsUI: Edit CSS / HeaderHTML / FooterHTML / JS
SettingsUI->>SettingsUI: Update form state
Admin->>SettingsUI: Save
SettingsUI->>API: POST status page payload (includes new fields)
API->>API: Validate with Joi (new fields)
API->>DB: Persist StatusPage document
DB-->>API: OK
API-->>SettingsUI: Success
Browser->>API: GET statusPage config
API->>DB: Query status page (projection includes new fields)
DB-->>API: Config
API-->>Browser: Config
Browser->>Browser: Sanitize headerHTML/footerHTML (DOMPurify)
Browser->>Browser: Inject <style> with customCSS into document.head
Browser->>Browser: Inject/evaluate customJavaScript in IIFE (try/catch) into document.body
Browser->>Browser: Render sanitized header/footer or fallback components
Browser->>Browser: Cleanup injected nodes on unmount
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~30 minutes
- Inspect client-side injection and sanitization in
client/src/Pages/v1/StatusPage/Status/index.jsx(DOMPurify usage, sanitization configuration, cleanup). - Verify Joi limits in
server/src/validation/joi.jsalign with schemamaxLengthinserver/src/db/v1/models/StatusPage.js. - Confirm
server/src/db/v1/modules/statusPageModule.jsincludes new fields consistently in early-return and aggregation projection. - Ensure
client/src/Pages/v1/StatusPage/Create/Components/Tabs/Settings.jsxfield names match validation and are persisted in payload. - Check
client/package.jsondependency changes for build compatibility.
Poem
🐇
I nibble styles and tuck a script away,
A header, footer—cleaned for bright display,
I hop through markup, sanitize with care,
Nest CSS in head, JS in a guarded lair,
Happy hops—your status page now wears flair! 🥕✨
Pre-merge checks and finishing touches
❌ Failed checks (1 inconclusive)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Linked Issues check | ❓ Inconclusive | While core features (custom CSS/HTML/JS fields, DOMPurify sanitization, UI inputs, i18n) are implemented, several issue requirements lack clear implementation: live preview, export/import JSON, dedicated syntax-highlighting editors, CSP enforcement, audit logging, and explicit risk acknowledgement in UI for JavaScript. | Verify that DOMPurify sanitization, risk acceptance UI gate for JavaScript, and critical security measures (CSP, audit logging) are fully implemented; confirm whether preview/export/import are deferred to follow-up work. |
✅ Passed checks (4 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | The title concisely summarizes the main change: adding custom CSS/JS/HTML overrides to status pages, referencing the associated issue #2863. |
| Description check | ✅ Passed | The description covers all major changes, lists backend and frontend modifications, includes the issue reference, and shows most checklist items completed; minor incomplete items do not materially impact overall adequacy. |
| Out of Scope Changes check | ✅ Passed | All changes directly support the linked issue requirements: schema extensions, validation rules, frontend UI inputs, i18n localization, and sanitization. No unrelated modifications detected. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
✨ Finishing touches
- [ ] 📝 Generate docstrings
🧪 Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
📜 Recent review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between f99222cf61c0b0ebbc9b99b4d93ec8aa7cb5cbac and 63b5912602ca9bd0c8fea9c76aae51458e4c2935.
📒 Files selected for processing (1)
client/src/Pages/v1/StatusPage/Create/Components/Tabs/Settings.jsx(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- client/src/Pages/v1/StatusPage/Create/Components/Tabs/Settings.jsx
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
The headerHTML and footerHTML fields introduce raw HTML injection into the page. As CodeRabbit is warning, this is essentially creating an critical XSS risk. I understand that the feature is admin-only but rendering untrusted HTML and directly injecting JS is a bad practice overall.
@SajanGhuman @ajhollid Thank you for the critical review. I fully agree with the security concerns raised regarding the XSS risks and arbitrary code execution.
My plan to fix this:
HTML Sanitization: I will implement DOMPurify to sanitize both headerHTML and footerHTML before rendering, ensuring no malicious scripts can be injected via these fields.
Backend Limits: I will update the Joi validation to enforce strict character limits (as suggested by CodeRabbit) to prevent database performance issues.
Custom JS: I understand the risk here. Since this was a requested feature in issue #2863 (allowing admins to override behavior), I will add a strict "Risk Acceptance" warning in the UI that the admin must check before saving.
If you believe customJS is too dangerous even with admin warnings, please let me know, and I can remove that specific field and limit the scope to just CSS and Sanitized HTML.
I will push these fixes shortly.
Hi @Armaansaxena,
Perhaps the solution is to gate this feature behind some sort of approval process whereby the admin acknowledges the risks of allowing arbitrary code to be executed.
@SajanGhuman @gorkemcetin what do you think?
Hi @Armaansaxena,
Perhaps the solution is to gate this feature behind some sort of approval process whereby the admin acknowledges the risks of allowing arbitrary code to be executed.
@SajanGhuman @gorkemcetin what do you think?
I agree. There should be some kind of warning explaining the risks that the admin is aware of and acknowledges to.
Hi @Armaansaxena, Perhaps the solution is to gate this feature behind some sort of approval process whereby the admin acknowledges the risks of allowing arbitrary code to be executed. @SajanGhuman @gorkemcetin what do you think?
I agree. There should be some kind of warning explaining the risks that the admin is aware of and acknowledges to.
Just a warning should be fine.
@gorkem-bwl @SajanGhuman @ajhollid
Update: All requested security controls and fixes are implemented.
Based on the feedback, I have finalized the security model for this feature:
-
JS Risk Gatekeeper (Implemented): The "Custom JavaScript" input is now disabled by default. The Admin must strictly check a "Risk Acceptance" checkbox to unlock the field.
-
CSS Sanitization (Hardened): Per CodeRabbit's feedback, I updated the CSS injection to strictly block dangerous patterns (e.g., url(), @import, behavior, javascript:).
-
HTML Sanitization: Full DOMPurify implementation for Header/Footer is in place.
-
Backend Validation: Added strict maxLength constraints to the schema.
-
Fixes: Resolved the i18n fallback syntax and variable naming conflicts.
The feature is now secure, gated, and validates all inputs. Ready for merge!