Skip to content

fix: cap and type-check author display names - #8475

Merged
JohnMcLear merged 1 commit into
developfrom
ghsa-w4w9-author-name-cap
Nov 11, 2026
Merged

JohnMcLear merged 1 commit into
developfrom
ghsa-w4w9-author-name-cap

Conversation

@JohnMcLear

Copy link
Copy Markdown
Member

Author display names sent over the pad socket (CLIENT_READY, USERINFO_UPDATE) were stored with no type or length check, so a client could save a name close to 1 MB that was then sent to everyone who opened the pad. A non-string name also broke the admin author search.

This adds AuthorManager.sanitizeAuthorName(). It nulls non-strings and blank strings, then trims and caps the name at 128 code points. Any Unicode is accepted, and surrogate pairs are never split. The helper runs on write (socket handlers, SUGGEST_USER_NAME, setAuthorName, createAuthor) and on read (historicalAuthorData, USER_NEWINFO, getAuthorName, searchAuthors), so records stored before the cap aren't rebroadcast. The pad name inputs get a matching maxlength.

Tests: new authorNameCap spec (24 tests); the full backend suite passes locally.

GHSA-w4w9-j4c3-hjf6, reported by @MAYASEVEN.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TcYAoDMav4BPPE9JrMtSvw

CLIENT_READY and USERINFO_UPDATE stored userInfo.name with no type or
length check, so an unauthenticated client could save a name of up to
~1 MB (bounded only by engine.io's maxHttpBufferSize) that was then sent
to every client opening the pad via historicalAuthorData and
USER_NEWINFO. A non-string name also broke the admin author search.

Add AuthorManager.sanitizeAuthorName(): non-strings and blank strings
become null, everything else is trimmed and cut to 128 code points.
Apply it on write (both socket handlers, SUGGEST_USER_NAME,
setAuthorName, createAuthor) and on read (historicalAuthorData,
USER_NEWINFO, the joining client's own name, getAuthorName for chat),
so records stored before the cap are not rebroadcast at full size.
Match the cap with maxlength on the pad's name inputs.

GHSA-w4w9-j4c3-hjf6

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TcYAoDMav4BPPE9JrMtSvw
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Cap and type-check author display names

🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Limit author names to 128 Unicode code points to prevent oversized names from being stored or
 rebroadcast.
• Sanitize legacy records when serving pad data and handle malformed names in admin search.
• Add matching pad input limits and regression tests for socket messages, Unicode, and legacy
 records.
Diagram

graph TD
  UI["Pad name inputs"] --> Socket["Socket handlers"] --> Sanitize["Name sanitizer"] --> DB[("Author records")]
  DB --> Sanitize --> Output["Pad messages"]
  DB --> Search["Admin search"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Migrate existing author records
  • ➕ Removes oversized and malformed names from existing storage.
  • ➕ Reduces repeated sanitization of migrated records.
  • ➖ Requires a database-wide migration and deployment coordination.
  • ➖ Does not protect against malformed records restored or introduced later.

Recommendation: Keep write-time validation with read-time protection: it immediately bounds names sent to pad clients without requiring a migration. A migration could later clean stored records, but should not replace read-time checks. Note that admin search type-checks legacy names but does not cap oversized string names in its results.

Files changed (5) +280 / -11

Bug fix (4) +54 / -11
AuthorManager.tsCentralize author-name sanitization +36/-6

Centralize author-name sanitization

• Adds a 128-code-point sanitizer that returns null for non-string or blank names and preserves surrogate pairs. Applies it when creating, setting, and reading names; admin search now treats legacy non-string names as unnamed.

src/node/db/AuthorManager.ts

PadMessageHandler.tsBound names entering and leaving pad sockets +16/-4

Bound names entering and leaving pad sockets

• Sanitizes names from CLIENT_READY, USERINFO_UPDATE, and SUGGEST_USER_NAME. Also sanitizes stored names before sending the joining client's name, historical author data, and USER_NEWINFO.

src/node/handler/PadMessageHandler.ts

pad_userlist.tsLimit dynamically created name inputs +1/-0

Limit dynamically created name inputs

• Sets maxlength to 128 on the user-list name input.

src/static/js/pad_userlist.ts

pad.htmlLimit the pad username input +1/-1

Limit the pad username input

• Sets maxlength to 128 on the pad's username input.

src/templates/pad.html

Tests (1) +226 / -0
authorNameCap.tsCover oversized, malformed, and legacy author names +226/-0

Cover oversized, malformed, and legacy author names

• Adds sanitizer and socket-path tests for normal, oversized, non-string, and Unicode names. Tests that legacy records are bounded in pad messages and that a non-string record does not break admin search.

src/tests/backend/specs/authorNameCap.ts

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Admin author search sends oversized names 🐞 Bug ➹ Performance
Description
searchAuthors type-checks rec.name but returns the original string instead of passing it through
sanitizeAuthorName. When a record predating the cap contains a long name, the admin search emits
that full value and also uses it for filtering and sorting.
Code

src/node/db/AuthorManager.ts[543]

+    const name = typeof rec.name === 'string' ? rec.name : null;
Evidence
The changed assignment retains any string at full length, and the row includes it unchanged. The
admin socket emits the search result; the new tests establish that oversized legacy records are a
supported condition.

src/node/db/AuthorManager.ts[541-555]
src/node/db/AuthorManager.ts[568-582]
src/node/hooks/express/adminsettings.ts[412-431]
src/tests/backend/specs/authorNameCap.ts[168-181]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Admin author search still processes and returns oversized names from legacy records because it only type-checks them.
## Fix Focus Areas
- src/node/db/AuthorManager.ts[541-555]
## Recommended Fix
Use `sanitizeAuthorName(rec.name)` for the search row and its name matching, so legacy names are bounded before sorting or returning them.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Emoji names are cut short in the editor 🐞 Bug ≡ Correctness
Description
Both new maxlength="128" attributes limit browser input by UTF-16 code units, while
sanitizeAuthorName limits names by Unicode code points. A user entering supplementary-plane
characters reaches the browser limit after 64 emoji, even though the server accepts 128.
Code

src/templates/pad.html[635]

+                  <input type="text" id="myusernameedit" maxlength="128" disabled="disabled" data-l10n-id="pad.userlist.entername">
Evidence
The two inputs set a numeric maxlength of 128, whereas the server explicitly counts code points with
Array.from and its test accepts 128 emoji.

src/templates/pad.html[635-635]
src/static/js/pad_userlist.ts[142-148]
src/node/db/AuthorManager.ts[42-49]
src/tests/backend/specs/authorNameCap.ts[84-89]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The browser's UTF-16-based maxlength prevents users from entering names that are valid under the server's 128-code-point cap.
## Fix Focus Areas
- src/templates/pad.html[635-635]
- src/static/js/pad_userlist.ts[142-148]
## Recommended Fix
Replace the mismatched native limit with input handling that caps names at 128 Unicode code points in both fields, while leaving the server sanitizer as the authoritative check.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Authors see a name others never receive 🐞 Bug ≡ Correctness
Description
handleUserInfoUpdate truncates the name before broadcasting and storing it, but the submitting
client is not sent the normalized value. When a configured or programmatically assigned name exceeds
128 code points, the client keeps showing its original name while other clients receive the
shortened one.
Code

src/node/handler/PadMessageHandler.ts[870]

+  name = authorManager.sanitizeAuthorName(name);
Evidence
The configured username is assigned directly to local state and the input, and notifyChangeName
sends that same value. The server changes the value for storage and broadcasts only to other
clients.

src/static/js/pad.ts[139-151]
src/static/js/pad.ts[943-948]
src/static/js/pad.ts[960-963]
src/node/handler/PadMessageHandler.ts[866-899]
src/static/js/pad_userlist.ts[614-620]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Server-side truncation leaves clients that supply names programmatically displaying a different name from the stored and broadcast value.
## Fix Focus Areas
- src/node/handler/PadMessageHandler.ts[866-899]
- src/static/js/pad.ts[943-948]
- src/static/js/pad.ts[960-963]
## Recommended Fix
Make the submitting client's name reflect the effective sanitized value, including for configured names that bypass input maxlength; either normalize before local assignment and submission or return the server's effective name and apply it locally.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can import rules and skills only from the repositories your team follows

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@JohnMcLear
JohnMcLear merged commit e50f9bd into develop Nov 11, 2026
24 of 34 checks passed
@JohnMcLear
JohnMcLear deleted the ghsa-w4w9-author-name-cap branch November 11, 2026 15:46
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