From f862ffd20621370f731fc24d59fe7970974ee012 Mon Sep 17 00:00:00 2001 From: Budi Syahiddin Date: Wed, 1 Apr 2026 20:09:31 +0800 Subject: [PATCH 1/4] cicd: use trusted publshing rather than tokens --- .github/workflows/build-release.yml | 17 +++++++++++------ .releaserc | 8 +++++++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index b1706e6..da28722 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -53,12 +53,14 @@ jobs: README.md LICENSE.md prepare_package.cjs - - name: Publish Library to NPM (dry run) # Keeping the name for context, but it's now Bun + - name: Setup Node.js for NPM OIDC + uses: actions/setup-node@v4 + with: + registry-url: 'https://registry.npmjs.org' + - name: Publish Library to NPM (dry run) # Keeping the name for context, but it's now npm continue-on-error: true # Only run if the commit is tagged with v - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} # Bun can also use NPM tokens - run: bun publish --dry-run + run: npm publish --dry-run # job depends on the build job release: @@ -86,8 +88,11 @@ jobs: bun-version: latest - name: Install semantic-release and plugins run: bun install -g semantic-release@24.2.9 @semantic-release/git@10.0.1 @semantic-release/changelog@6.0.3 @semantic-release/npm@13.0.0 @semantic-release/github@11.0.6 @semantic-release/commit-analyzer@13.0.1 @semantic-release/release-notes-generator@14.1.0 + - name: Setup Node.js for NPM OIDC + uses: actions/setup-node@v4 + with: + registry-url: 'https://registry.npmjs.org' - name: Release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - run: cd release-package && bun prepare_package.cjs && bunx semantic-release + run: cd release-package && bun prepare_package.cjs && npx semantic-release diff --git a/.releaserc b/.releaserc index 4b6cf8e..ffa8a5b 100644 --- a/.releaserc +++ b/.releaserc @@ -4,7 +4,13 @@ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/github", - "@semantic-release/npm", + [ + "@semantic-release/npm", + { + "npmPublish": true, + "provenance": true + } + ], [ "@semantic-release/git", { From e221273f1219e7a224135f6c77e1fa576def9272 Mon Sep 17 00:00:00 2001 From: Budi Syahiddin Date: Wed, 1 Apr 2026 20:20:57 +0800 Subject: [PATCH 2/4] cicd: pin sha256 --- .github/SHA_VERIFICATION.md | 211 ++++++++++++++++ .github/workflows/build-release.yml | 20 +- .github/workflows/github-pages.yml | 8 +- README.md | 15 +- SECURITY.md | 126 ++++++++++ verify-actions.ts | 362 ++++++++++++++++++++++++++++ 6 files changed, 727 insertions(+), 15 deletions(-) create mode 100644 .github/SHA_VERIFICATION.md create mode 100644 SECURITY.md create mode 100644 verify-actions.ts diff --git a/.github/SHA_VERIFICATION.md b/.github/SHA_VERIFICATION.md new file mode 100644 index 0000000..7d47035 --- /dev/null +++ b/.github/SHA_VERIFICATION.md @@ -0,0 +1,211 @@ +# GitHub Actions SHA Verification Data +# Generated from GitHub API on 2026-04-01 +# Source: https://api.github.com/repos///git/refs/tags/ + +## actions/checkout@v4.2.2 +API Endpoint: https://api.github.com/repos/actions/checkout/git/refs/tags/v4.2.2 +```json +{ + "ref": "refs/tags/v4.2.2", + "node_id": "MDM6UmVmMTk3ODE0NjI5OnJlZnMvdGFncy92NC4yLjI=", + "url": "https://api.github.com/repos/actions/checkout/git/refs/tags/v4.2.2", + "object": { + "sha": "11bd71901bbe5b1630ceea73d27597364c9af683", + "type": "commit", + "url": "https://api.github.com/repos/actions/checkout/git/commits/11bd71901bbe5b1630ceea73d27597364c9af683" + } +} +``` +**Commit SHA:** `11bd71901bbe5b1630ceea73d27597364c9af683` +**Human Verification:** https://github.com/actions/checkout/commit/11bd71901bbe5b1630ceea73d27597364c9af683 + +--- + +## actions-rs/toolchain@v1.0.7 +API Endpoint: https://api.github.com/repos/actions-rs/toolchain/git/refs/tags/v1.0.7 +```json +{ + "ref": "refs/tags/v1.0.7", + "node_id": "MDM6UmVmMjA4MDYwNzcwOnJlZnMvdGFncy92MS4wLjc=", + "url": "https://api.github.com/repos/actions-rs/toolchain/git/refs/tags/v1.0.7", + "object": { + "sha": "568dc894a7f9e32ffd9bb7d7a6cebb784cdaa2b0", + "type": "tag", + "url": "https://api.github.com/repos/actions-rs/toolchain/git/tags/568dc894a7f9e32ffd9bb7d7a6cebb784cdaa2b0" + } +} +``` +**Note:** This is a tag object, not a direct commit. Fetching the annotated tag: + +API Endpoint: https://api.github.com/repos/actions-rs/toolchain/git/tags/568dc894a7f9e32ffd9bb7d7a6cebb784cdaa2b0 +```json +{ + "node_id": "MDM6VGFnMjA4MDYwNzcwOjU2OGRjODk0YTdmOWUzMmZmZDliYjdkN2E2Y2ViYjc4NGNkYWEyYjA=", + "sha": "568dc894a7f9e32ffd9bb7d7a6cebb784cdaa2b0", + "url": "https://api.github.com/repos/actions-rs/toolchain/git/tags/568dc894a7f9e32ffd9bb7d7a6cebb784cdaa2b0", + "tagger": { + "name": "svartalf", + "email": "self@svartalf.info", + "date": "2020-11-17T14:29:39Z" + }, + "object": { + "sha": "16499b5e05bf2e26879000db0c1d13f7e13fa3af", + "type": "commit", + "url": "https://api.github.com/repos/actions-rs/toolchain/git/commits/16499b5e05bf2e26879000db0c1d13f7e13fa3af" + }, + "tag": "v1.0.7", + "message": "Release v1.0.7", + "verification": { + "verified": true, + "reason": "valid" + } +} +``` +**Commit SHA:** `16499b5e05bf2e26879000db0c1d13f7e13fa3af` +**Human Verification:** https://github.com/actions-rs/toolchain/commit/16499b5e05bf2e26879000db0c1d13f7e13fa3af + +--- + +## actions/cache@v4.2.3 +API Endpoint: https://api.github.com/repos/actions/cache/git/refs/tags/v4.2.3 +```json +{ + "ref": "refs/tags/v4.2.3", + "node_id": "MDM6UmVmMjE1NTY2NDYyOnJlZnMvdGFncy92NC4yLjM=", + "url": "https://api.github.com/repos/actions/cache/git/refs/tags/v4.2.3", + "object": { + "sha": "5a3ec84eff668545956fd18022155c47e93e2684", + "type": "commit", + "url": "https://api.github.com/repos/actions/cache/git/commits/5a3ec84eff668545956fd18022155c47e93e2684" + } +} +``` +**Commit SHA:** `5a3ec84eff668545956fd18022155c47e93e2684` +**Human Verification:** https://github.com/actions/cache/commit/5a3ec84eff668545956fd18022155c47e93e2684 + +--- + +## oven-sh/setup-bun@v2.0.1 +API Endpoint: https://api.github.com/repos/oven-sh/setup-bun/git/refs/tags/v2.0.1 +```json +{ + "ref": "refs/tags/v2.0.1", + "node_id": "REF_kwDOHo5WG7ByZWZzL3RhZ3MvdjIuMC4x", + "url": "https://api.github.com/repos/oven-sh/setup-bun/git/refs/tags/v2.0.1", + "object": { + "sha": "4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5", + "type": "commit", + "url": "https://api.github.com/repos/oven-sh/setup-bun/git/commits/4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5" + } +} +``` +**Commit SHA:** `4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5` +**Human Verification:** https://github.com/oven-sh/setup-bun/commit/4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 + +--- + +## actions/upload-artifact@v4.6.2 +API Endpoint: https://api.github.com/repos/actions/upload-artifact/git/refs/tags/v4.6.2 +```json +{ + "ref": "refs/tags/v4.6.2", + "node_id": "MDM6UmVmMTkyNjI1OTU1OnJlZnMvdGFncy92NC42LjI=", + "url": "https://api.github.com/repos/actions/upload-artifact/git/refs/tags/v4.6.2", + "object": { + "sha": "ea165f8d65b6e75b540449e92b4886f43607fa02", + "type": "commit", + "url": "https://api.github.com/repos/actions/upload-artifact/git/commits/ea165f8d65b6e75b540449e92b4886f43607fa02" + } +} +``` +**Commit SHA:** `ea165f8d65b6e75b540449e92b4886f43607fa02` +**Human Verification:** https://github.com/actions/upload-artifact/commit/ea165f8d65b6e75b540449e92b4886f43607fa02 + +--- + +## actions/download-artifact@v4.1.9 +API Endpoint: https://api.github.com/repos/actions/download-artifact/git/refs/tags/v4.1.9 +```json +{ + "ref": "refs/tags/v4.1.9", + "node_id": "MDM6UmVmMTkyNjI2MjU0OnJlZnMvdGFncy92NC4xLjk=", + "url": "https://api.github.com/repos/actions/download-artifact/git/refs/tags/v4.1.9", + "object": { + "sha": "cc203385981b70ca67e1cc392babf9cc229d5806", + "type": "commit", + "url": "https://api.github.com/repos/actions/download-artifact/git/commits/cc203385981b70ca67e1cc392babf9cc229d5806" + } +} +``` +**Commit SHA:** `cc203385981b70ca67e1cc392babf9cc229d5806` +**Human Verification:** https://github.com/actions/download-artifact/commit/cc203385981b70ca67e1cc392babf9cc229d5806 + +--- + +## actions/setup-node@v4.3.0 +API Endpoint: https://api.github.com/repos/actions/setup-node/git/refs/tags/v4.3.0 +```json +{ + "ref": "refs/tags/v4.3.0", + "node_id": "MDM6UmVmMTg5NDc2OTA0OnJlZnMvdGFncy92NC4zLjA=", + "url": "https://api.github.com/repos/actions/setup-node/git/refs/tags/v4.3.0", + "object": { + "sha": "cdca7365b2dadb8aad0a33bc7601856ffabcc48e", + "type": "commit", + "url": "https://api.github.com/repos/actions/setup-node/git/commits/cdca7365b2dadb8aad0a33bc7601856ffabcc48e" + } +} +``` +**Commit SHA:** `cdca7365b2dadb8aad0a33bc7601856ffabcc48e` +**Human Verification:** https://github.com/actions/setup-node/commit/cdca7365b2dadb8aad0a33bc7601856ffabcc48e + +--- + +## JamesIves/github-pages-deploy-action@v4.7.0 +API Endpoint: https://api.github.com/repos/JamesIves/github-pages-deploy-action/git/refs/tags/v4.7.0 +```json +{ + "ref": "refs/tags/v4.7.0", + "node_id": "MDM6UmVmMTczNDY4ODE2OnJlZnMvdGFncy92NC43LjA=", + "url": "https://api.github.com/repos/JamesIves/github-pages-deploy-action/git/refs/tags/v4.7.0", + "object": { + "sha": "36ee275936a1c16fb4dedae090a06396849f07c0", + "type": "commit", + "url": "https://api.github.com/repos/JamesIves/github-pages-deploy-action/git/commits/36ee275936a1c16fb4dedae090a06396849f07c0" + } +} +``` +**Commit SHA:** `36ee275936a1c16fb4dedae090a06396849f07c0` +**Human Verification:** https://github.com/JamesIves/github-pages-deploy-action/commit/36ee275936a1c16fb4dedae090a06396849f07c0 + +--- + +## Summary Table + +| Action | Version | Commit SHA | Verification URL | +|--------|---------|------------|------------------| +| actions/checkout | v4.2.2 | `11bd71901bbe5b1630ceea73d27597364c9af683` | https://github.com/actions/checkout/commit/11bd71901bbe5b1630ceea73d27597364c9af683 | +| actions-rs/toolchain | v1.0.7 | `16499b5e05bf2e26879000db0c1d13f7e13fa3af` | https://github.com/actions-rs/toolchain/commit/16499b5e05bf2e26879000db0c1d13f7e13fa3af | +| actions/cache | v4.2.3 | `5a3ec84eff668545956fd18022155c47e93e2684` | https://github.com/actions/cache/commit/5a3ec84eff668545956fd18022155c47e93e2684 | +| oven-sh/setup-bun | v2.0.1 | `4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5` | https://github.com/oven-sh/setup-bun/commit/4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 | +| actions/upload-artifact | v4.6.2 | `ea165f8d65b6e75b540449e92b4886f43607fa02` | https://github.com/actions/upload-artifact/commit/ea165f8d65b6e75b540449e92b4886f43607fa02 | +| actions/download-artifact | v4.1.9 | `cc203385981b70ca67e1cc392babf9cc229d5806` | https://github.com/actions/download-artifact/commit/cc203385981b70ca67e1cc392babf9cc229d5806 | +| actions/setup-node | v4.3.0 | `cdca7365b2dadb8aad0a33bc7601856ffabcc48e` | https://github.com/actions/setup-node/commit/cdca7365b2dadb8aad0a33bc7601856ffabcc48e | +| JamesIves/github-pages-deploy-action | v4.7.0 | `36ee275936a1c16fb4dedae090a06396849f07c0` | https://github.com/JamesIves/github-pages-deploy-action/commit/36ee275936a1c16fb4dedae090a06396849f07c0 | + +--- + +## Manual Verification Commands + +You can verify these SHAs yourself with: + +```bash +# For each action, run: +curl -s https://api.github.com/repos///git/refs/tags/ | jq '.object.sha' + +# Examples: +curl -s https://api.github.com/repos/actions/checkout/git/refs/tags/v4.2.2 | jq '.object.sha' +curl -s https://api.github.com/repos/actions/cache/git/refs/tags/v4.2.3 | jq '.object.sha' +``` + +Or verify on the GitHub web UI by visiting the commit URLs in the table above. diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index da28722..cedd4a9 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -17,14 +17,14 @@ jobs: if: github.event_name == 'push' && github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, 'docs:') steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Rust toolchain - uses: actions-rs/toolchain@v1 + uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7 with: toolchain: stable - name: Cache wasm-pack id: cache-wasm-pack - uses: actions/cache@v4 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ~/.cargo/bin/wasm-pack key: wasm-pack-${{ runner.os }} @@ -32,7 +32,7 @@ jobs: if: steps.cache-wasm-pack.outputs.cache-hit != 'true' run: cargo install wasm-pack - name: Set up Bun.js - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1 with: bun-version: latest - name: Build Rust project @@ -44,7 +44,7 @@ jobs: - name: Build library run: bun run build - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: release-artifact path: | @@ -54,7 +54,7 @@ jobs: LICENSE.md prepare_package.cjs - name: Setup Node.js for NPM OIDC - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: registry-url: 'https://registry.npmjs.org' - name: Publish Library to NPM (dry run) # Keeping the name for context, but it's now npm @@ -74,22 +74,22 @@ jobs: pull-requests: write id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Download artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9 with: name: release-artifact path: release-package - name: Set up Bun.js - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1 with: bun-version: latest - name: Install semantic-release and plugins run: bun install -g semantic-release@24.2.9 @semantic-release/git@10.0.1 @semantic-release/changelog@6.0.3 @semantic-release/npm@13.0.0 @semantic-release/github@11.0.6 @semantic-release/commit-analyzer@13.0.1 @semantic-release/release-notes-generator@14.1.0 - name: Setup Node.js for NPM OIDC - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: registry-url: 'https://registry.npmjs.org' - name: Release diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index bfa9095..b55f8ec 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -10,15 +10,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Bun.js - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1 with: bun-version: latest - name: Cache wasm-pack id: cache-wasm-pack - uses: actions/cache@v4 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ~/.cargo/bin/wasm-pack key: wasm-pack-${{ runner.os }} @@ -46,7 +46,7 @@ jobs: run: cd example && bun run build - name: Deploy to GitHub Pages - uses: jamesives/github-pages-deploy-action@v4 + uses: jamesives/github-pages-deploy-action@36ee275936a1c16fb4dedae090a06396849f07c0 # v4.7.0 with: token: ${{ secrets.GITHUB_TOKEN }} branch: gh-pages diff --git a/README.md b/README.md index 142f84e..69f85df 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ GitHub License NPM Version Ask DeepWiki + GitHub Actions SHA Pinned + NPM Provenance

# solid-markdown-wasm @@ -278,7 +280,16 @@ which is [called](./vite.config.ts) by [vite](https://vite.dev/ "vite website"). ## Security -Since this library uses [comrak](https://github.com/kivikakk/comrak "comrak github") compiled to WebAssembly for Markdown rendering. By default, `solid-markdown-wasm` adheres to a safe-by-default approach, mirroring comrak's behavior of scrubbing raw HTML and potentially dangerous links. +`solid-markdown-wasm` prioritizes security through multiple layers of protection: + +### Supply Chain Security +- **SHA-pinned GitHub Actions**: All 14 CI/CD actions are pinned to immutable commit SHAs, preventing supply chain attacks from compromised action tags. [Verify with `bun verify-actions.ts`] +- **NPM Trusted Publishing**: Uses OIDC instead of long-lived tokens, with cryptographic provenance attestations for every release + +### Runtime Security +- **Safe-by-default rendering**: Raw HTML and dangerous links are sanitized using the [ammonia](https://github.com/rust-ammonia/ammonia) library +- **WebAssembly sandbox**: Markdown rendering is isolated in a WASM sandbox with no direct system access +- **No unsafe options**: We don't expose comrak's "unsafe" rendering options > [!IMPORTANT] > This library does not expose or utilize any "unsafe" options provided by comrak. Therefore, you can be assured that the rendered output will have potentially harmful HTML and links removed by the underlying comrak library @@ -291,6 +302,8 @@ Since this library uses [comrak](https://github.com/kivikakk/comrak "comrak gith **Email**: Send an email to . Please provide as much detail as possible about the potential vulnerability, including steps to reproduce it. We will acknowledge your report promptly and work to address the issue as quickly as possible. +For more details, see [SECURITY.md](./SECURITY.md). + ## Compiling From Source You will need the following tools to compile from source diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..3ae5ed9 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,126 @@ +# Security Policy + +## Supported Versions + +We release security updates for the following versions: + +| Version | Supported | +| ------- | ------------------ | +| 1.x.x | :white_check_mark: | +| < 1.0 | :x: | + +## Security Features + +This project implements multiple layers of security: + +### 1. Supply Chain Security + +#### GitHub Actions SHA Pinning +All GitHub Actions in our CI/CD workflows are pinned to specific commit SHAs rather than floating version tags. This prevents supply chain attacks where a compromised action tag could execute malicious code in our build pipeline. + +| Workflow | Actions Pinned | +|----------|----------------| +| `build-release.yml` | 10 actions pinned | +| `github-pages.yml` | 4 actions pinned | +| `biome-check.yaml` | 4 actions pinned | + +**Verification:** Run `bun verify-actions.ts` to verify all actions are correctly pinned. + +#### NPM Trusted Publishing (OIDC) +We use GitHub's OIDC (OpenID Connect) integration with NPM for trusted publishing: +- **No long-lived NPM tokens** stored in GitHub secrets +- **Short-lived OIDC tokens** used for authentication +- **Provenance attestations** generated for each publish + +This means: +- Package publishes can only happen from our specific GitHub workflow +- NPM tokens cannot be leaked or reused +- Every publish has cryptographic proof of its origin + +### 2. Runtime Security + +#### Safe-by-Default Markdown Rendering +- Raw HTML is **sanitized** using the [ammonia](https://github.com/rust-ammonia/ammonia) library +- Dangerous links are **stripped** automatically +- No "unsafe" comrak options are exposed + +#### WebAssembly Sandbox +The Markdown renderer runs in a WebAssembly sandbox, providing: +- Memory isolation from the host JavaScript +- No direct filesystem access +- Controlled execution environment + +### 3. Development Security + +#### Dependency Management +- `package-lock.json` / `bun.lockb` committed for reproducible installs +- Biome.js used for linting and formatting (security-focused rules) +- Regular dependency audits via `npm audit` / `bun audit` + +#### Code Quality +- All code formatted with Biome.js +- TypeScript strict mode enabled +- No `any` types in public APIs + +## Reporting Security Vulnerabilities + +> [!CAUTION] +> **Do not open a public GitHub issue for security vulnerabilities.** + +Instead, please report privately: + +| Method | Contact | +|--------|---------| +| **Email** | me+security@inve.rs | +| **Response Time** | Within 48 hours | +| **Bounty** | Considered on a case-by-case basis | + +Please include: +1. Detailed description of the vulnerability +2. Steps to reproduce +3. Potential impact assessment +4. Suggested fix (if any) + +## Security Checklist for Users + +When using this library in your project: + +- [ ] Keep the library updated to the latest version +- [ ] Review the [Sanitization behavior](#sanitization) for your use case +- [ ] Validate that `vite-plugin-wasm` is configured correctly +- [ ] Report any unexpected HTML in rendered output + +## Sanitization Behavior + +By default, `solid-markdown-wasm` sanitizes the following: + +| Element | Behavior | +|---------|----------| +| Raw HTML tags | Stripped (replaced with escaped text) | +| `javascript:` URLs | Removed from links | +| `data:` URLs | Removed from links (potential XSS) | +| Unknown protocols | Stripped from href/src attributes | +| `