{"id":15115487,"url":"https://github.com/kkomelin/isomorphic-dompurify","last_synced_at":"2026-04-02T11:55:37.470Z","repository":{"id":38019972,"uuid":"248014821","full_name":"kkomelin/isomorphic-dompurify","owner":"kkomelin","description":"Use DOMPurify on server and client in the same way","archived":false,"fork":false,"pushed_at":"2026-03-24T10:01:23.000Z","size":2122,"stargazers_count":567,"open_issues_count":2,"forks_count":16,"subscribers_count":4,"default_branch":"master","last_synced_at":"2026-03-25T07:58:02.002Z","etag":null,"topics":["dompurify","html-escape","isomorphic","isomorphic-dompurify","sanitize","sanitize-html","sanitizer","security","ssr","universal","wrapper","xss","xss-filter"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kkomelin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"kkomelin","buy_me_a_coffee":"kkomelin"}},"created_at":"2020-03-17T16:09:17.000Z","updated_at":"2026-03-24T10:02:30.000Z","dependencies_parsed_at":"2024-03-29T01:26:38.482Z","dependency_job_id":"2f017116-50b5-477f-a127-4486e29affd4","html_url":"https://github.com/kkomelin/isomorphic-dompurify","commit_stats":{"total_commits":213,"total_committers":6,"mean_commits":35.5,"dds":0.5211267605633803,"last_synced_commit":"8d60d9c1691dc694ff16b16c7c5e45367d608e15"},"previous_names":[],"tags_count":92,"template":false,"template_full_name":null,"purl":"pkg:github/kkomelin/isomorphic-dompurify","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kkomelin%2Fisomorphic-dompurify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kkomelin%2Fisomorphic-dompurify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kkomelin%2Fisomorphic-dompurify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kkomelin%2Fisomorphic-dompurify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kkomelin","download_url":"https://codeload.github.com/kkomelin/isomorphic-dompurify/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kkomelin%2Fisomorphic-dompurify/sbom","scorecard":{"id":562760,"data":{"date":"2025-08-11","repo":{"name":"github.com/kkomelin/isomorphic-dompurify","commit":"aaa9cbe1be38118fcdbe664877ad53b1754def5d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.5,"checks":[{"name":"Code-Review","score":1,"reason":"Found 1/7 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/build_test.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build_test.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/kkomelin/isomorphic-dompurify/build_test.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build_test.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/kkomelin/isomorphic-dompurify/build_test.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build_test.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/kkomelin/isomorphic-dompurify/build_test.yml/master?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Maintained","score":10,"reason":"30 commit(s) and 7 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 24 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-20T14:09:34.877Z","repository_id":38019972,"created_at":"2025-08-20T14:09:34.877Z","updated_at":"2025-08-20T14:09:34.877Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31305938,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T09:48:21.550Z","status":"ssl_error","status_checked_at":"2026-04-02T09:48:19.196Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dompurify","html-escape","isomorphic","isomorphic-dompurify","sanitize","sanitize-html","sanitizer","security","ssr","universal","wrapper","xss","xss-filter"],"created_at":"2024-09-26T01:43:53.332Z","updated_at":"2026-04-02T11:55:37.464Z","avatar_url":"https://github.com/kkomelin.png","language":"TypeScript","funding_links":["https://github.com/sponsors/kkomelin","https://buymeacoffee.com/kkomelin"],"categories":["JavaScript"],"sub_categories":[],"readme":"# Isomorphic DOMPurify\n[![npm version](https://img.shields.io/npm/v/isomorphic-dompurify.svg)](https://www.npmjs.com/package/isomorphic-dompurify)\n[![Test Status](https://github.com/kkomelin/isomorphic-dompurify/actions/workflows/build_test.yml/badge.svg)](https://github.com/kkomelin/isomorphic-dompurify/actions/workflows/build_test.yml)\n\nThe library makes it possible to seamlessly use [DOMPurify](https://github.com/cure53/DOMPurify) on both server and client in the same way.\nIt does nothing by itself except for providing an isomorphic/universal wrapper around DOMPurify, so all credits go to DOMPurify authors and contributors.\n\n\u003e DOMPurify - a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. DOMPurify works with a secure default, but offers a lot of configurability and hooks. \n- [DOMPurify Demo](https://cure53.de/purify)\n- [DOMPurify Documentation](https://github.com/cure53/DOMPurify/blob/master/README.md)\n\n## Motivation\n\nDOMPurify needs a DOM tree to work with, which is not available in Node by default. To work on the server side, we need a fake DOM to be created and supplied to DOMPurify. It means that DOMPurify initialization logic on the server is not the same as on the client.\n\nThis project was born with the idea of encapsulating DOMPurify initialization details and providing an easy way to import the library on both server and client, for example in Next.js apps.\n\nIt was inspired by [Isomorphic Unfetch](https://github.com/developit/unfetch/tree/master/packages/isomorphic-unfetch).\n\n## Requirements\n\n| isomorphic-dompurify  | Node.js | Environment |\n| ------------- | ------------- | ------------- |\n| `\u003c=0.19.0`  | `\u003e=12`  | Server  |\n| `\u003e=0.20.0`  | `\u003e=14`  | Server  |\n| `\u003e=1.4.0`  | `\u003e=16`  | Server  |\n| `\u003e=1.10.0`  | `\u003e=18`  | Server  |\n| `\u003e=2.27.0`  | `\u003e=20`  | Server  |\n| `\u003e=2.30.0`  | `\u003e=20.19.5`  | Server  |\n| `\u003e=3.0.0`  | `^20.19.0 \\|\\| ^22.12.0 \\|\\| \u003e=24.0.0`  | Server  |\n| `\u003e=3.4.0`  | `^20.19.0 \\|\\| ^22.13.0 \\|\\| \u003e=24.0.0`  | Server  |\n\n## Installation\n\n```shell_script\n$ npm i isomorphic-dompurify\n```\n\n## Updates\n\nPlease note that the DOMPurify library [doesn't follow Semantic Versioning](https://github.com/cure53/DOMPurify/issues/446#issuecomment-643761433), so we have to release every change as a minor version because we cannot be 100% sure whether new features are added to patch DOMPurify releases or not.\n\n## Usage\n\n```javascript\nimport DOMPurify from \"isomorphic-dompurify\";\n\nconst clean = DOMPurify.sanitize(dirtyString);\n```\n\nYou can pass the [config](https://github.com/cure53/DOMPurify/blob/main/README.md) as a second argument:\n```javascript\nconst clean = DOMPurify.sanitize(dirtyString, { USE_PROFILES: { html: true } });\n```\n\nNamed imports are also supported:\n```javascript\nimport { sanitize } from \"isomorphic-dompurify\";\n\nconst clean = sanitize(dirtyString);\n```\n\nThe default export is also callable as a factory, matching the `dompurify` API. This is useful when you need a DOMPurify instance bound to a specific window (e.g. in tests or sandboxed environments):\n```javascript\nimport DOMPurify from \"isomorphic-dompurify\";\nimport { JSDOM } from \"jsdom\";\n\nconst purify = DOMPurify(new JSDOM().window);\nconst clean = purify.sanitize(dirtyString);\n```\n\n## Memory Management (Server)\n\nIn long-running Node.js processes, the internal jsdom window accumulates DOM state across sanitization calls, which can cause progressive slowdown and memory growth. Use `clearWindow()` to periodically release these resources:\n\n```javascript\nimport { sanitize, clearWindow } from \"isomorphic-dompurify\";\n\n// Sanitize as usual\nconst clean = sanitize(dirtyString);\n\n// Release jsdom resources when appropriate (e.g. after a request, after a batch)\nclearWindow();\n```\n\n`clearWindow()` closes the current jsdom window and creates a fresh one. All import styles (default and named) continue to work after calling it.\n\n\u003e **Note:** Any hooks or config set via `addHook`/`setConfig` will need to be re-applied after calling `clearWindow()`. In the browser build, `clearWindow()` is a no-op.\n\n## Web Worker Support\n\nThe `isomorphic-dompurify` library is [compatible with Web Workers](https://github.com/kkomelin/isomorphic-dompurify/pull/242), \nhowever, `dompurify`, which it depends upon, [is not, at least not yet](https://github.com/cure53/DOMPurify/issues/577).\n\n## Playgrounds\n\nWant to try `isomorphic-dompurify` with your favorite framework? Check out [isomorphic-dompurify-playgrounds](https://github.com/kkomelin/isomorphic-dompurify-playgrounds) — minimal setups for popular frameworks including Astro, Next.js, Nuxt, React, Svelte, and others.\n\n## Known Issues\n\n- **ERR_REQUIRE_ESM in CommonJS environments (v3.0.0+):** `jsdom@28` pulls in an ESM-only dependency that breaks `require()` in environments like Next.js on Vercel. Workaround: pin `jsdom` to `25.0.1` via package manager overrides. See [#394](https://github.com/kkomelin/isomorphic-dompurify/issues/394).\n\n## License\n\nDOMPurify -\n[Apache 2.0 or MPL 2.0](https://github.com/cure53/DOMPurify/blob/master/LICENSE)\n© 2015 Mario Heiderich\n\nIsomorphic DOMPurify - [MIT License](LICENSE) © 2020 [Konstantin Komelin](https://github.com/kkomelin) and [contributors](https://github.com/kkomelin/isomorphic-dompurify/graphs/contributors)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkkomelin%2Fisomorphic-dompurify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkkomelin%2Fisomorphic-dompurify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkkomelin%2Fisomorphic-dompurify/lists"}