Skip to content

fix(webserver): add htmlspecialchars + addslashes builtins and escape remote-controlled strings in the WebUI (XSS) - #106

Merged
ngosang merged 3 commits into
amule-org:masterfrom
ngosang:feature/issues3
Jun 11, 2026
Merged

fix(webserver): add htmlspecialchars + addslashes builtins and escape remote-controlled strings in the WebUI (XSS)#106
ngosang merged 3 commits into
amule-org:masterfrom
ngosang:feature/issues3

Conversation

@ngosang

@ngosang ngosang commented Jun 11, 2026

Copy link
Copy Markdown
Member

What

Fixes stored/reflected XSS in the amuleweb default template. Adds two
escaping builtins to the embedded PHP interpreter and uses them to escape
every echo of remote-controlled data in the right context.

Why

Several pages echoed attacker-influenced strings into HTML without escaping, so
a shared file or server named <script>…</script> (or a malicious eD2K server
name, or a remote client's reported version/OS string) executed JavaScript in
the admin's authenticated session.

The bundled mini-PHP interpreter had no escaping builtins (htmlspecialchars,
str_replace, …), and include() is unusable (it resolves against the process
cwd), so there was previously no clean way to escape from a template.

Changes (3 commits)

1. htmlspecialchars builtin (php_core_lib.cpp)

  • Escapes & < > " ' (matching PHP ≥8.1 htmlspecialchars with ENT_QUOTES).
  • Byte-wise into a std::string — UTF-8 safe (metacharacters are ASCII and
    never appear inside multibyte sequences), no manual buffer sizing.

2. addslashes builtin (php_core_lib.cpp)

  • Escapes a string for a double-quoted JavaScript string literal inside a
    <script> block
    . On top of the classic \ " ' set, it escapes < as
    \x3C (so an embedded </script> cannot terminate the script element) and
    CR/LF as \r/\n.
  • Every escape decodes back to the original char in JS, so a value assigned to
    a form field is displayed verbatim — unlike htmlspecialchars, whose HTML
    entities are not decoded inside a raw-text <script>.

3. Audit + escape across all .php templates

  • HTML text / attribute context → htmlspecialchars: file names, user names
    (dload, shared, search), server name/desc/addr (servers), raw log/serverinfo
    (log.php), connected server name/address in the iframe status bar
    (stats.php), stats-tree leaf labels (stats_tree.php), category names in
    <option> lists (dload, search, footer).
  • JS-string context → addslashes: the nickname (settable via ?nick=) and
    option values emitted into the <script> initvals block in prefs.php.
  • Updated an obsolete comment in amuleweb-main-search.php (the sort param
    stays whitelisted — stricter than escaping for that reflected value).

Testing

  • amuleweb builds clean (no new warnings).
  • Built the standalone interpreter under AddressSanitizer + UBSan and ran,
    for both builtins:
    • Functional/edge-case batteries (all specials, empty, non-string types,
      nested calls, UTF-8, missing/extra args).
    • 10k–100k-call loops and multi-MB worst-case inputs — no per-call leaks
      (allocation count independent of iteration count), no overflow.
    • Differential fuzz (hundreds of random byte strings) vs reference escapers —
      exact match.
    • addslashes: real-JS (node) round-trip — every payload (incl.
      </script>, quotes, backslash, newlines, unicode) decodes back to the
      original and never produces a literal </script> that closes the block.
    • All 13 templates parse and run clean; crafted payloads render inert and
      display correctly.

ngosang added 3 commits June 11, 2026 17:54
The template mini-PHP had no way to escape HTML, forcing each page to
duplicate an html_escape()/html_join() helper built on split() (include
is unusable, it resolves against the process cwd). Add a proper builtin
that escapes & < > " ' (matching PHP >=8.1 htmlspecialchars with
ENT_QUOTES), so templates can call it directly.
Escapes a string for safe inclusion in a double-quoted JavaScript string
literal inside an HTML <script> block. On top of the classic addslashes
set (\ " ') it also escapes < as \x3C so an embedded </script> cannot
terminate the <script> element (the HTML parser scans raw-text script
content for that literal sequence regardless of JS syntax), and CR/LF as
\r/\n so a multi-line value can't break the literal.

Every escape decodes back to the original character in JS, so a value
assigned to a form field is displayed verbatim -- unlike htmlspecialchars,
whose HTML entities are not decoded inside a raw-text <script>.
Audit every echo of non-constant data across all .php templates and wrap
the dangerous ones with the appropriate escaping builtin:

- file names / user names (dload, shared, search), server name/desc/addr
  (servers), raw log/serverinfo (log.php): echoed verbatim -> stored XSS
  from a shared file or server named '<script>...</script>'.
- connected server name/address in the status bar (stats.php): the name
  is self-declared by the eD2K server and the bar loads in an iframe on
  every page.
- stats tree leaf labels (stats_tree.php): client version / OS strings
  are reported as free text by remote clients.
- category names in <option> lists (dload, search, footer).

These all land in HTML text or quoted-attribute context, so they use
htmlspecialchars, where the parser decodes the entities for display.

prefs.php is different: the nickname (settable via ?nick=) and option
values are emitted into double-quoted JS string literals inside a
<script> block. There they are escaped with addslashes (JS-string
context), not htmlspecialchars -- HTML entities are not decoded in a
raw-text <script>, so htmlspecialchars would display the literal
entities in the form fields and round-trip them back on save.

Verified end to end with the standalone interpreter under ASan/UBSan and
a real-JS (node) round-trip: every page parses and runs clean, crafted
payloads render inert, and escaped values decode back to the original.
@ngosang ngosang changed the title fix(webserver): add htmlspecialchars builtin and escape remote-controlled strings in the WebUI (XSS) fix(webserver): add htmlspecialchars + addslashes builtins and escape remote-controlled strings in the WebUI (XSS) Jun 11, 2026
@ngosang
ngosang merged commit e27496c into amule-org:master Jun 11, 2026
9 checks passed
@ngosang
ngosang deleted the feature/issues3 branch June 11, 2026 17:40
@got3nks

got3nks commented Jun 11, 2026

Copy link
Copy Markdown

Great job on the testing side! 👏

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.

2 participants