Repository navigation
Audit fixes 2026-07-14: import/share XSS, data integrity, validation - #23
Merged
Merged
Conversation
…rity) Closes #22. Read-only audit (codex) + PO line-by-line review. (#12 publish localStorage hook left as-is: deliberate owner test hook, server-authoritative.) Security (XSS-via-import/share): - meta.surface + photoShape now allowlisted like their siblings, and the body class is escAttr-escaped (hostile imported/shared meta can no longer inject a body attribute) - invalid custom accent falls back to a canonical palette color; only #rrggbb reaches CSS (was returned unchanged -> CSS injection) - imported image data URLs validated (MIME + size + base64 + magic bytes) and escAttr-escaped before entering the preview srcdoc - email links split across data attributes, assembled on click; no complete address in source, text, or a single attribute Data integrity + robustness: - page IDs use crypto.randomUUID(); duplicate stored IDs migrated on load (was length-based -> create/delete/create collision + data loss) - new complete SiteData runtime decoder validates/defaults arrays, sections, items, images, meta; applied to both saved-state load and file import (was version+name only -> links:null / links:{} crashed on load/import) - import fully replaces the draft incl lang/favicon; clears absent optionals - history: structural changes always snapshot; only same-control text edits coalesce (was 800ms blanket coalescing -> undo dropped a typed name) - persistence returns success/failure; unsaved warning shown on quota failure - AA guard fits foregrounds against both bg and surface; rejects impossible custom surface - QR enforces the version-40 byte limit with a friendly error (was uncaught throw) - OG long names wrap + grapheme-truncate below 36px (was clipped) 175 tests pass (was 157; added hostile image/look fixtures, DOM-security, decoder, history, OG, contrast, QR coverage; happy-dom dev dep for parsed-DOM assertions). typecheck passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TmgNzbG2MaXd1ckGxmuEfu
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #22. codex audit + PO line-by-line review of every fix. #12 (publish localStorage hook) left as-is — deliberate owner test hook, server rejects independently (verified).
Security (XSS via imported/shared page JSON)
meta.surface+photoShapeallowlisted like siblings; body classescAttr-escaped#rrggbbto CSSData integrity + robustness
crypto.randomUUID(); dup IDs migrated on load (was length-based → collision/data-loss)SiteDatadecoder for saved-state load and file import (was version+name only →.forEachcrash)Verification (ran locally)
types.tsunioncard|flat|bordered|tinted; photoShape ==circle|rounded|square— no regressionvalidImageDataUrlchecks MIME + size + base64 + JPEG/PNG magic bytesNote
Email links now require JS (activation script) to assemble the address — a deliberate trade for scraper resistance. Generated pages are browser-viewed; acceptable.