Fix: Allow advanced markdown syntax in MarkdownRenderer (fixes #1912) - #1935
Fix: Allow advanced markdown syntax in MarkdownRenderer (fixes #1912)#1935anshika1179 wants to merge 1 commit into
Conversation
|
@anshika1179 is attempting to deploy a commit to the durdana3105's projects Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughThe Markdown renderer expands its rehype sanitization schema to support form inputs, table markup, styling attributes, input attributes, and table cell alignment and span attributes. ChangesMarkdown rendering
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/MarkdownRenderer.tsx`:
- Line 22: Remove the global style allowance from the rehypeSanitize attribute
configuration in MarkdownRenderer, leaving only the existing globally permitted
attributes. If styling is required, allow style only on the specific elements
that need it; preserve table alignment through align attributes.
- Around line 20-26: Update the attribute configuration in the Markdown renderer
to merge each relevant defaultSchema entry before adding the explicitly required
custom attributes, rather than replacing those entries. Preserve existing global
attributes and retain default ARIA, className, style, and table attributes such
as scope and headers while keeping the current custom allowlists for links and
inputs.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e968454b-5dfe-467b-8885-fa985813564e
📒 Files selected for processing (1)
src/components/MarkdownRenderer.tsx
| attributes: { | ||
| ...defaultSchema.attributes, | ||
| '*': ['className', 'style'], | ||
| a: ['href', 'title', 'target', 'rel'], | ||
| input: ['type', 'checked', 'disabled'], | ||
| th: ['align', 'colSpan', 'rowSpan'], | ||
| td: ['align', 'colSpan', 'rowSpan'], |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg '(^|/)(package\.json|package-lock\.json|yarn\.lock|pnpm-lock\.yaml|MarkdownRenderer\.tsx|ChatMessage\.tsx|ChatBox\.tsx)$' || true
echo
echo "== package versions =="
for f in package.json package-lock.json yarn.lock pnpm-lock.yaml; do
if [ -f "$f" ]; then
echo "--- $f ---"
if [ "$f" = "package.json" ]; then
node -e "const p=require('./package.json'); console.log(JSON.stringify({dependencies:p.dependencies,devDependencies:p.devDependencies,engines:p.engines}, null, 2))"
elif [ "$f" = "package-lock.json" ]; then
node -e "const p=require('./package-lock.json'); for (const key of ['node_modules/rehype-sanitize','node_modules/hast-util-sanitize','node_modules/remark-gfm','node_modules/react-markdown']) console.log(key, p.packages?.[key]?.version)"
else
rg -n "rehype-sanitize|hast-util-sanitize|remark-gfm|react-markdown" "$f" -C 2 || true
fi
fi
done
echo
echo "== MarkdownRenderer =="
fd -a 'MarkdownRenderer\.tsx$' . | while read -r f; do
echo "--- $f ---"
sed -n '1,180p' "$f" | cat -n
done
echo
echo "== usages =="
for f in $(fd 'ChatMessage\.tsx$|ChatBox\.tsx$|MarkdownRenderer\.tsx$' .); do
echo "--- $f ---"
wc -l "$f"
sed -n '1,220p' "$f" | cat -n
doneRepository: durdana3105/peer-learning
Length of output: 14265
🌐 Web query:
rehype-sanitize 6.0.0 default schema hast-util-sanitize 5.0.0 GFM footnote attributes tables
💡 Result:
In rehype-sanitize 6.0.0, which utilizes hast-util-sanitize 5.0.0, the default schema includes sanitization logic that affects GFM (GitHub Flavored Markdown) features like footnotes, tables, and IDs [1][2][3]. The core issue involves DOM clobbering prevention [4]. By default, rehype-sanitize and hast-util-sanitize rewrite specific attributes (such as id and name) to prefix them, which is intended to protect against security vulnerabilities [5][6][4]. Specifically regarding GFM footnotes and internal links: - The default schema's clobbering protection often causes mismatches between footnote references and their corresponding footnote definitions because the IDs and the referenced fragments in href attributes are rewritten inconsistently or clobbered [5][6][4]. - While the default schema allows for elements used in GFM tables (such as table, thead, tbody, tr, td, th), the aggressive sanitization of IDs and link targets can still break navigation within those tables or footnoted content [4][7]. If you are encountering broken GFM footnote links or table-related ID issues, it is typically because the library is sanitizing these identifiers by default to mitigate DOM clobbering [4]. You can address this by providing a custom schema to rehype-sanitize, extending the default schema, or adjusting the clobbering configuration if necessary [8][4]. Developers often work around this by either disabling specific clobbering rules or adjusting the schema to allow the required attributes and values without the default prefixing [4].
Citations:
- 1: https://github.com/rehypejs/rehype-sanitize/
- 2: https://registry.npmjs.org/hast-util-sanitize
- 3: https://github.com/syntax-tree/hast-util-sanitize/releases/tag/5.0.0
- 4: Improve handling of clobbering syntax-tree/hast-util-sanitize#31
- 5: GFM footnotes syntax-tree/hast-util-sanitize#30
- 6: id and anchor of footnote do not match with rehype-sanitize remarkjs/remark-gfm#28
- 7: https://npmx.dev/package/hast-util-sanitize/v/%5E5.0.0
- 8: https://github.com/syntax-tree/hast-util-sanitize
🌐 Web query:
GitHub rehype-sanitize v6.0.0 package.json dependencies hast-util-sanitize
💡 Result:
The rehype-sanitize version 6.0.0 package relies on hast-util-sanitize as its underlying utility for cleaning HAST (HTML Abstract Syntax Tree) nodes [1][2]. In the package.json for rehype-sanitize v6.0.0, hast-util-sanitize is listed as a dependency, specifically requiring version ^5.0.0 [1][3]. Rehype-sanitize functions as a higher-level abstraction, utilizing hast-util-sanitize to perform the actual sanitization of the syntax trees while simplifying the integration for users within the unified/rehype ecosystem [1][4][2].
Citations:
- 1: https://registry.npmjs.org/rehype-sanitize
- 2: https://p.rst.im/q/github.com/rehypejs/rehype-sanitize
- 3: https://www.npmjs.com/package/rehype-sanitize
- 4: https://p.rst.im/q/github.com/syntax-tree/hast-util-sanitize
🏁 Script executed:
#!/bin/bash
set -euo pipefail
tmp="$(mktemp -d)"
cd "$tmp"
echo "== fetch packages =="
npm pack github:syntax-tree/hast-util-sanitize@5.0.2 --silent 2>/dev/null || true
tar -xzf hast-util-sanitize-5.0.2.tgz
echo
echo "== locate schema assets =="
find package -maxdepth 3 -type f \( -name '*.js' -o -name '*.mjs' -o -name '*.d.ts' -o -name 'schema.*' \) -print | sort | sed -n '1,120p'
echo
echo "== search default attributes for relevant keys =="
rg -n "default|attributes|footnote|aria|role|scope|headers|clobber|className|data-footnote|id:" package -S || true
echo
echo "== inspect likely default/schema file slices =="
for f in $(find package -maxdepth 3 -type f \( -name '*.js' -o -name '*.mjs' -o -name 'schema.*' \) | sort); do
if rg -q "defaultSchema|attributes|footnote|role|scope|headers" "$f"; then
echo "--- $f ---"
wc -l "$f"
sed -n '1,260p' "$f" | cat -n
fi
doneRepository: durdana3105/peer-learning
Length of output: 389
🌐 Web query:
github.com syntax-tree/hast-util-sanitize v5.0.2 default schema attributes
💡 Result:
In hast-util-sanitize version 5.0.2, the default schema is exported as defaultSchema [1][2]. It follows GitHub-style sanitation rules to determine which nodes and properties are permitted [1][3][2]. The attributes configuration is defined as a mapping of tag names to allowed property names, where defaultSchema.attributes provides the default values [1][4]. Key characteristics of this configuration include: 1. Special Wildcard Key: The key '' is used to define property names that are allowed on all elements [1][5]. 2. Data Properties: The special value 'data' can be used as a property name to allow all data attributes [1][2]. 3. Granular Control: You can specify simple string arrays for property names, or use nested arrays to restrict specific values (e.g., input: [['type', 'checkbox', 'radio']]) [1][5]. 4. Extending the Schema: To modify the default attributes, you can clone defaultSchema and override the attributes key in your custom configuration [1][4]. If a top-level key is missing in a user-provided schema, the library automatically falls back to the corresponding value from defaultSchema [1][2]. For the full list of default allowed attributes, you can access the defaultSchema object directly in your code: import {defaultSchema} from 'hast-util-sanitize' console.log(defaultSchema.attributes)
Citations:
- 1: https://github.com/syntax-tree/hast-util-sanitize
- 2: https://p.rst.im/q/github.com/syntax-tree/hast-util-sanitize
- 3: https://github.com/syntax-tree/hast-util-sanitize/blob/main/readme.md?plain=1
- 4: https://www.npmjs.com/package/hast-util-sanitize
- 5: https://registry.npmjs.org/hast-util-sanitize
🌐 Web query:
raw.githubusercontent.com syntax-tree/hast-util-sanitize v5.0.2 default.js
💡 Result:
In the hast-util-sanitize package version 5.0.2, there is no file named default.js [1]. The package exports an identifier called defaultSchema, which is defined within the library's source code (typically in lib/index.js or similar) and made available to users [2][3][4]. The defaultSchema serves as the standard configuration for the sanitize function, designed to mimic GitHub's sanitization style [2][3]. It specifies which HTML nodes, attributes, and properties are permitted [5][4]. Because the package uses named exports, you do not import a file named default.js; instead, you import the schema directly from the package [2][3]: import { defaultSchema, sanitize } from 'hast-util-sanitize'; Users can access, inspect, or extend this schema by cloning it or using tools like deepmerge to modify it for their specific requirements [2][5][4]. The package documentation provides examples on how to utilize this default configuration when sanitizing HAST (Hypertext Abstract Syntax Tree) nodes [2][4].
Citations:
- 1: https://unpkg.com/hast-util-sanitize@5.0.2/
- 2: https://github.com/syntax-tree/hast-util-sanitize
- 3: https://p.rst.im/q/github.com/syntax-tree/hast-util-sanitize
- 4: https://github.com/syntax-tree/hast-util-sanitize/blob/main/readme.md?plain=1
- 5: https://fastly.jsdelivr.net/npm/hast-util-sanitize@5.0.2/lib/index.d.ts
🌐 Web query:
unpkg.com hast-util-sanitize 5.0.2 lib/index.js defaultSchema attributes footnote role scope headers
💡 Result:
The hast-util-sanitize package (version 5.0.2) provides a defaultSchema that defines which nodes and properties are permitted in a HAST (Hypertext Abstract Syntax Tree) [1][2]. This default schema mimics GitHub-style sanitation [1][3]. Regarding the specific attributes you mentioned (footnote, role, scope, headers): 1. defaultSchema is an exported object that maps tag names to allowed property names [1][3]. 2. The package does not explicitly list footnote, role, scope, or headers in its core documentation as being part of the defaultSchema [3][4]. 3. The defaultSchema can be extended or modified by the user [1][3]. To allow these attributes, you can clone the defaultSchema and merge your own modifications into the attributes object [1][3]. For example, to allow these attributes on specific elements, you can use a library like deepmerge [1][4]: javascript import deepmerge from 'deepmerge'; import { defaultSchema } from 'hast-util-sanitize'; const mySchema = deepmerge(defaultSchema, { attributes: { // Example: allow 'scope' and 'headers' on 'td' or 'th' elements td: ['scope', 'headers'], th: ['scope', 'headers'], // Example: allow 'role' on any element '*': ['role'] } }); Because hast-util-sanitize follows GitHub's sanitation rules, attributes not included in the allow-list are stripped by default when using defaultSchema [1][3]. If you require footnote, role, scope, or headers, you must explicitly add them to your configuration schema [1][4].
Citations:
- 1: https://www.npmjs.com/package/hast-util-sanitize
- 2: https://github.com/syntax-tree/hast-util-sanitize
- 3: https://github.com/syntax-tree/hast-util-sanitize/blob/main/readme.md
- 4: https://github.com/syntax-tree/hast-util-sanitize/blob/main/readme.md?plain=1
🌐 Web query:
raw.githubusercontent.com syntax-tree/hast-util-sanitize v5.0.2 default.js attributes | rg footnote role scope headers className
💡 Result:
In hast-util-sanitize v5.0.2, the default schema (defaultSchema) defines allowed attributes for HAST nodes, primarily following GitHub's sanitation rules [1][2]. Regarding the specific attributes queried: - className: This is allowed on many elements by default, but it is often restricted to specific values (e.g., for syntax highlighting classes) on certain tags [1][3]. - footnote, role, scope, headers: These attributes are generally not included in the default schema for elements unless specifically permitted by the underlying GitHub sanitation logic that the library mimics [1][2]. The attributes configuration in hast-util-sanitize is a mapping of tag names to allowed property names [1][4]. You can extend or override the default behavior by merging your own schema with defaultSchema [2][5]. For example, to allow these attributes globally or on specific elements, you can define them in your schema configuration: const schema = deepmerge(defaultSchema, { attributes: { '*': ['className', 'role'], // Example: allowing className and role on all elements th: ['scope', 'headers'], // Example: allowing specific table attributes //... } }); Because hast-util-sanitize uses an allow-list approach, any attribute not explicitly defined in the schema (either in defaultSchema or your custom extension) will be stripped from the HAST nodes during sanitization [1][2].
Citations:
- 1: https://github.com/syntax-tree/hast-util-sanitize
- 2: https://p.rst.im/q/github.com/syntax-tree/hast-util-sanitize
- 3: https://github.com/syntax-tree/hast-util-sanitize/blob/main/readme.md?plain=1
- 4: https://www.npmjs.com/package/hast-util-sanitize
- 5: id property is always removed when using <h2> tag syntax-tree/hast-util-sanitize#27
🌐 Web query:
raw.githubusercontent.com syntax-tree/hast-util-sanitize v5.0.2 default.js table th td footnote role scope headers className
💡 Result:
The hast-util-sanitize package, version 5.0.2, uses a default schema (defaultSchema) designed to mimic GitHub's sanitization logic [1][2]. This schema determines which HTML tags and attributes are permitted in the output tree [3][4]. Regarding the specific properties and tags mentioned: 1. className: By default, the schema includes specific rules for the className attribute. While className is not allowed on all elements by default, you can allow it globally by modifying the schema [1][3]. This is commonly done by merging a custom configuration with the defaultSchema [1][2]: import deepmerge from 'deepmerge'; import { defaultSchema } from 'hast-util-sanitize'; const schema = deepmerge(defaultSchema, {attributes: {'*': ['className']}}); 2. table, th, td, footnote (note: footnote is not a standard HTML element), role, scope, headers: The defaultSchema explicitly defines which attributes are permitted for specific elements, including table-related tags [3][5]. - Attributes like scope and headers are typically managed within the attributes configuration for table elements (th/td) [3][6]. - The role attribute is generally stripped by default unless explicitly allowed in your custom schema, as it is often restricted to prevent accessibility-related XSS or spoofing issues. - If an element or attribute is not included in the defaultSchema for a specific tag, it is removed during sanitization [4][5]. To allow these, you must extend the defaultSchema by adding them to the attributes object for the corresponding tag names [1][7]. The package does not have a single flat file that lists all allowed attributes; instead, it uses a structured schema object [4]. You can inspect the actual allowed values by importing defaultSchema from the package in a Node.js environment to view the full default configuration [1][8].
Citations:
- 1: https://www.npmjs.com/package/hast-util-sanitize
- 2: https://p.rst.im/q/github.com/syntax-tree/hast-util-sanitize
- 3: https://github.com/syntax-tree/hast-util-sanitize/blob/main/readme.md
- 4: https://github.com/syntax-tree/hast-util-sanitize
- 5: https://npmx.dev/package/hast-util-sanitize/v/%5E5.0.0
- 6: https://fastly.jsdelivr.net/npm/hast-util-sanitize@5.0.2/lib/index.d.ts
- 7: https://github.com/syntax-tree/hast-util-sanitize/blob/main/readme.md?plain=1
- 8: https://registry.npmjs.org/hast-util-sanitize
🏁 Script executed:
#!/bin/bash
set -euo pipefail
tmp="$(mktemp -d)"
cd "$tmp"
echo "== fetch unrejected package tarball if possible =="
url="$(node - <<'JS'
const fs = require('fs')
const lock = JSON.parse(fs.readFileSync('../package-lock.json', 'utf8'))
const pkg = lock.packages?.['node_modules/hast-util-sanitize']?.resolved || lock.packages?.['node_modules/hast-util-sanitize']?.version
console.log(pkg)
JS
)"
echo "resolved: $url"
npm fetch "$url" --silent > hast-util-sanitize.tgz 2>&1 || cat hast-util-sanitize.tgz
tar -tzf hast-util-sanitize.tgz | sed -n '1,120p'
tar -xzf hast-util-sanitize.tgz
echo
echo "== default schema source =="
find package -maxdepth 3 -type f \( -name '*.js' -o -name '*.mjs' -o -name '*.d.ts' \) -print0 | sort -z | while IFS= read -r -d '' f; do
if grep -qE "defaultSchema|attributes|className|aria|role|scope|headers|footnote|data-footnote|clobber" "$f"; then
echo "--- $f ---"
wc -l "$f"
grep -nE "defaultSchema|attributes|className|aria|role|scope|headers|footnote|data-footnote|clobber|protocols" "$f" -C 3 || true
fi
done
echo
echo "== lockfile exact package info =="
node - <<'JS'
const fs = require('fs')
const lock = JSON.parse(fs.readFileSync('../../package-lock.json', 'utf8'))
for (const key of ['node_modules/react-markdown','node_modules/remark-gfm','node_modules/rehype-sanitize','node_modules/hast-util-sanitize']) {
console.log(key, lock.packages?.[key])
}
JSRepository: durdana3105/peer-learning
Length of output: 981
🏁 Script executed:
#!/bin/bash
set -euo pipefail
cd "$(pwd)"
tmp="$(mktemp -d)"
cd "$tmp"
echo "== inspect local lock package info =="
node - <<'JS'
const fs = require('fs')
const lock = JSON.parse(fs.readFileSync('/workspace/package-lock.json', 'utf8'))
for (const key of ['node_modules/react-md','node_modules/react-markdown','node_modules/remark-gfm','node_modules/rehype-sanitize','node_modules/hast-util-sanitize']) {
console.log(key, JSON.stringify(lock.packages?.[key], null, 2))
}
JS
echo
echo "== fetch hast-util-sanitize lock resolved source if resolvable =="
node - <<'JS'
const fs = require('fs')
const lock = JSON.parse(fs.readFileSync('/workspace/package-lock.json', 'utf8'))
const pkg = lock.packages?.['node_modules/hast-util-sanitize']
console.log(JSON.stringify(pkg, null, 2))
JSRepository: durdana3105/peer-learning
Length of output: 984
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== package files and cwd =="
pwd
git ls-files 'package-lock.json' 'package.json' | cat -n
echo
echo "== local lock package info =="
node - <<'JS'
const fs = require('fs')
const paths = ['package-lock.json', 'package-lock.json', '../package-lock.json', '/workspace/package-lock.json']
let lock
for (const p of paths) {
try {
if (fs.existsSync(p)) {
lock = JSON.parse(fs.readFileSync(p, 'utf8'))
console.log('loaded', p)
break
}
} catch (e) { console.error(p, e.message) }
}
if (!lock) throw new Error('no package-lock.json loaded')
for (const key of ['node_modules/react-markdown','node_modules/remark-gfm','node_modules/rehype-sanitize','node_modules/hast-util-sanitize']) {
console.log(key)
console.log(JSON.stringify(lock.packages?.[key], null, 2))
}
JSRepository: durdana3105/peer-learning
Length of output: 2685
🌐 Web query:
hast-util-sanitize 5.0.2 npm files lib default.js source
💡 Result:
In the npm package hast-util-sanitize version 5.0.2, the source code is located within the lib directory, and it exports an identifier named defaultSchema [1][2][3]. This defaultSchema provides a predefined configuration for the sanitize function, which is designed to mirror how GitHub handles HTML sanitization [4][5]. Users can customize sanitization by providing their own schema or by extending the defaultSchema [4][5]. The package is written as an ESM-only module and is maintained by the syntax-tree collective [1][3]. You can view the package contents and source structure directly via services like UNPKG [6].
Citations:
- 1: https://github.com/syntax-tree/hast-util-sanitize
- 2: https://npmx.dev/package/hast-util-sanitize/v/%5E5.0.0
- 3: https://p.rst.im/q/github.com/syntax-tree/hast-util-sanitize
- 4: https://fastly.jsdelivr.net/npm/hast-util-sanitize@5.0.2/lib/index.d.ts
- 5: https://github.com/syntax-tree/hast-util-sanitize/blob/main/readme.md?plain=1
- 6: https://unpkg.com/hast-util-sanitize@5.0.2/
🌐 Web query:
hast-util-sanitize v5.0.2 npmx default attributes role scope headers className table footnote
💡 Result:
In hast-util-sanitize v5.0.2, the default configuration is determined by the defaultSchema object, which is modeled after GitHub's sanitation practices [1][2]. Regarding the specific attributes you inquired about: 1. className: This property is generally allowed on elements if explicitly configured, but it is not included in the default schema's wildcard ('') list by default [1][3]. To allow className on all elements, you must merge a custom schema with the defaultSchema, for example: deepmerge(defaultSchema, {attributes: {'': ['className']}}) [1][4][3]. 2. role: ARIA attributes (such as role) are typically allowed by the default schema for accessibility, as they are part of the standard set of attributes deemed safe by GitHub-style sanitation [5]. 3. scope and headers: These attributes are standard for HTML table elements and are included within the defaultSchema for relevant tags (such as th) to maintain valid, accessible table structures [5]. 4. table and footnote: These refer to HTML tags rather than attributes. The defaultSchema permits standard HTML elements like table (and associated tags like thead, tbody, tr, th, td), provided they do not contain dangerous properties or nested structures [1][3]. A footnote is not a native HTML tag and is not explicitly handled by the default schema; if you use custom tags for footnotes (e.g., ), they will be stripped or sanitized unless you add them to the allowed tagNames in your schema [2]. To modify these behaviors, you can pass a custom schema to the sanitize function. If any top-level key (such as attributes) is missing in your provided schema, the corresponding value from defaultSchema is used automatically [1][3].
Citations:
- 1: https://www.npmjs.com/package/hast-util-sanitize
- 2: https://registry.npmjs.org/hast-util-sanitize
- 3: https://github.com/syntax-tree/hast-util-sanitize/blob/main/readme.md?plain=1
- 4: https://github.com/syntax-tree/hast-util-sanitize
- 5: https://fastly.jsdelivr.net/npm/hast-util-sanitize@5.0.2/lib/index.d.ts
Merge the defaultSchema attribute entries before overriding allowed attributes.
The nested object spread replaces each schema entry instead of extending it. This keeps className, ARIA attributes, and table attributes such as scope and headers out when they would otherwise be allowed. Only explicitly needed additional attributes should remain in the custom arrays.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/MarkdownRenderer.tsx` around lines 20 - 26, Update the
attribute configuration in the Markdown renderer to merge each relevant
defaultSchema entry before adding the explicitly required custom attributes,
rather than replacing those entries. Preserve existing global attributes and
retain default ARIA, className, style, and table attributes such as scope and
headers while keeping the current custom allowlists for links and inputs.
| ], | ||
| attributes: { | ||
| ...defaultSchema.attributes, | ||
| '*': ['className', 'style'], |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== repo files =="
git ls-files | sed -n '1,120p'
echo
echo "== find MarkdownRenderer and relevant files =="
fd -a 'MarkdownRenderer|ChatMessage|ChatBox' . 2>/dev/null || true
echo
echo "== package manifests =="
for f in package.json pnpm-lock.yaml package-lock.json yarn.lock bun.lockb; do
[ -f "$f" ] && { echo "--- $f"; if [ "$f" != bun.lockb ]; then sed -n '1,220p' "$f"; fi; }
done
echo
echo "== MarkdownRenderer outline/content =="
if [ -f src/components/MarkdownRenderer.tsx ]; then
wc -l src/components/MarkdownRenderer.tsx
cat -n src/components/MarkdownRenderer.tsx
fi
echo
echo "== search rehype/rehypePlugins/hast-util-to-jsx/runtime usage =="
rg -n "rehypePlugins|rehype|remark|hast-util-to-jsx|toJsxRuntime|style|rawHtml|stripHtml" src package.json || trueRepository: durdana3105/peer-learning
Length of output: 26834
🌐 Web query:
rehype-sanitize v6 inline-style-parser style sanitizer defaultSchema allows style property
💡 Result:
In rehype-sanitize v6, the defaultSchema does not allow the style property [1][2][3]. The library is designed to be restrictive by default to prevent security risks such as CSS-based attacks (e.g., overlaying invisible elements or data exfiltration via external resources) [3]. If your application requires support for inline styles, you must explicitly extend the defaultSchema by adding the style attribute to the elements where you want to permit it [3]. Because rehype-sanitize uses inline-style-parser to handle style strings, providing access to the style attribute allows the plugin to parse and sanitize the content within that attribute rather than stripping it entirely [4][5][6]. To allow the style attribute, you can configure the plugin as follows [3]: import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'; const customSchema = {...defaultSchema, attributes: {...defaultSchema.attributes, // Add 'style' to the allowed attributes for the desired elements span: [...(defaultSchema.attributes?.span || []), 'style'], }, }; // Use the custom schema in your unified pipeline //.use(rehypeSanitize, customSchema) When enabling this, it is recommended to be deliberate about which elements you allow the style attribute on, as it increases the attack surface of your application [3].
Citations:
- 1: https://www.npmjs.com/package/rehype-sanitize
- 2: https://github.com/rehypejs/rehype-sanitize/blob/main/readme.md
- 3: https://affine.pro/blog/react-markdown
- 4: https://repos.status.im/logos-messaging/OpChan/commit/a82bbe124332114d7660767808d91679051a5400.diff
- 5: https://repos.status.im/logos-messaging/OpChan/commit/a82bbe124332114d7660767808d91679051a5400.patch
- 6: terryHu7/xLog@251e183
Security Misconfiguration (CWE-20): Improper Input Validation
Remove the global style allowance unless inline styling is required.
Adding style to attributes["*"] lets user/assistant markdown pass inline styles through rehypeSanitize. inline-style-parser sanitizes those values, but this still extends the attack surface and can throw on invalid CSS. Use style only on specific elements when needed; GFM tables should rely on align attributes instead.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/MarkdownRenderer.tsx` at line 22, Remove the global style
allowance from the rehypeSanitize attribute configuration in MarkdownRenderer,
leaving only the existing globally permitted attributes. If styling is required,
allow style only on the specific elements that need it; preserve table alignment
through align attributes.
This PR fixes #1912 by configuring rehype-sanitize to allow className, style, and table/input tags. This ensures that remark-gfm can properly render nested code blocks and complex tables without stripping their styling and alignment attributes.
Summary by CodeRabbit