Skip to content

fix(english/lightnovelto): sanitize chapter HTML and handle protocol-relative URLs in resolveUrl - #2727

Open
RevDev909 wants to merge 3 commits into
lnreader:masterfrom
RevDev909:fix-lightnovelto-sanitize
Open

RevDev909 wants to merge 3 commits into
lnreader:masterfrom
RevDev909:fix-lightnovelto-sanitize

Conversation

@RevDev909

Copy link
Copy Markdown
Contributor

Chapter HTML is now sanitized before it reaches the reader: scripts, frames, form elements, inline event handlers, and javascript:/vbscript:/data:text/html URLs are stripped. URL values are checked regardless of quoting (double, single, or unquoted) and after decoding HTML entities, so single-quoted, unquoted, and entity-encoded javascript: links are caught too, along with mixed-case and control-character-obfuscated schemes, while story text, links, and images are kept. resolveUrl also handles protocol-relative URLs now. Version bumped to 1.0.1. Tested: eslint and prettier clean, check:plugin all four checks pass.

Checklist

  • Update version code if an existing plugin was modified
  • Test changes in Plugin Playground or the app
  • Reference related issues in the PR body (e.g. Closes #xyz)
  • Commit messages follow type(scope): description (e.g. feat(<generator>): add new source)

@greptile-apps

greptile-apps Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 0/5

[Medium impact] The changes affect chapter reading and URL resolution for LightNovel.to.

Fix the executable HTML and URL bypasses before merging.

Findings

  1. P1 Security Slash-separated handlers still run ▶
  2. P1 Security Encoded script links survive ▶
  3. P1 Security Quotes hide script destinations ▶
  4. P2 Ordinary chapter text disappears ▶

Summary

Adds chapter HTML filtering, supports protocol-relative URLs in resolveUrl, and raises the plugin version to 1.0.1.

  • LightNovel.to chapter pages now send cleaned HTML to the reader.
  • LightNovel.to now resolves protocol-relative URLs with HTTPS.

Reviews (1) · Last reviewed commit: "fix(english/lightnovelto): sanitize chap..." · Reviewed by Greptile

Comment thread plugins/english/lightnovelto.ts Outdated
Comment on lines +305 to +307
.replace(/\son\w+\s*=\s*"[^"]*"/gi, '')
.replace(/\son\w+\s*=\s*'[^']*'/gi, '')
.replace(/\son\w+\s*=\s*[^\s>]+/gi, '')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Slash-separated handlers still run

The event filters require whitespace before the attribute name, so <img src="x"/onerror=alert(1)> survives unchanged. Browsers read the slash-separated onerror as an attribute and run it when the image fails to load. Parse tags and remove event attributes instead of matching whitespace-prefixed text.

How this was verified: The handler survives every replacement and reaches dangerouslySetInnerHTML through parseChapter.

Knowledge Base Used: Plugin authoring contract

Comment thread plugins/english/lightnovelto.ts Outdated
Comment on lines +338 to +342
.replace(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&quot;/g, '"')
.replace(/&apos;/g, "'");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Encoded script links survive

decodeEntities misses browser-supported references such as &colon; and numeric references without a semicolon. For example, <a href="javascript&colon;alert(1)">open</a> passes the check, but the browser reads its destination as javascript:alert(1). Clicking it can run JavaScript. Use a complete HTML attribute decoder before checking the scheme.

How this was verified: The decoder leaves &colon; unchanged, the scheme check accepts it, and the returned link reaches raw HTML rendering.

Knowledge Base Used: Plugin authoring contract

Comment thread plugins/english/lightnovelto.ts Outdated
Comment on lines +351 to +355
const quoted = /"([^"]*)"|'([^']*)'/.exec(attr);
if (quoted) {
raw = quoted[1] !== undefined ? quoted[1] : quoted[2];
} else {
const unquoted = /=\s*([^\s>]+)/.exec(attr);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Quotes hide script destinations

isSafeUrlValue treats any quoted substring as the whole attribute value. For <a href=javascript:alert('x')>open</a>, it checks only x and keeps the link. Browsers retain those quotes inside the unquoted value, so clicking the link can run JavaScript. Read the value from immediately after = and distinguish quoted values from quotes inside an unquoted value.

How this was verified: The attribute matcher captures the full unquoted destination, but isSafeUrlValue selects only 'x' and returns true.

Knowledge Base Used: Plugin authoring contract

Comment thread plugins/english/lightnovelto.ts Outdated
Comment on lines +307 to +309
.replace(/\son\w+\s*=\s*[^\s>]+/gi, '')
.replace(/\sstyle\s*=\s*"[^"]*"/gi, '')
.replace(/\sstyle\s*=\s*'[^']*'/gi, '')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Ordinary chapter text disappears

These replacements run over story text as well as tag attributes. For example, <p>Set online=true before continuing.</p> becomes <p>Set before continuing.</p> because online matches on\w+. The style replacements have the same problem. Limit attribute removal to parsed tags so chapter text stays intact.

Knowledge Base Used: Plugin authoring contract

…arated handlers, encoded schemes, and quote-hidden destinations
…arated handlers, encoded schemes, and quote-hidden destinations

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant