Skip to content

fix(reliability): bound hyperlink target validation before URL parsing #181

Description

@seonghobae

Current authoritative state

Protected shipped truth is exact main@3b38ead2d00f44eb578d0689087b9293b3dabe1e. The original unbounded hyperlink-target pre-URL-parser defect is repaired on consolidated Draft PR #176 / branch fix/public-markdown-resource-options-175, the sole active writer for the overlapping SafeLink/serialization surface and explicit closer of #181. At this issue synchronization the exact Draft head is 68aa1ed4f08e2c65826dccb02ca8f3e2da3a9407; live PR/head and independently resolved protected main remain lifecycle authority.

Implemented active-PR contract

The framework-neutral shared policy exposes SafeLinkValidationOptions.maxHrefBytes, defaulting to 65,536 UTF-8 bytes with a hard caller-selected maximum of 1,048,576 bytes. A string target is rejected by an obvious UTF-16 code-unit lower bound before full UTF-8 allocation, then exact UTF-8 byte length is checked before HTTP(S) reaches new URL(href). Oversize input uses payload-redacted SafeLinkHrefError code input_too_large; malformed resource configuration normalizes to invalid_configuration.

The single policy source continues to permit in-bound HTTP(S), mailto, tel, document-relative, query-only and fragment targets while rejecting protocol-relative targets, executable/local/unknown schemes, embedded credentials, backslashes, literal whitespace/control characters and malformed absolute URLs. validateSafeLinkHref() and predicate-style isSafeLinkHref() share the same implementation, and existing editor/serializer callers consume the default policy rather than duplicating it.

Runtime option inspection fails closed on unsupported containers/keys/property shapes and invalid ceilings. JavaScript Proxy meta-object reflection may execute Proxy traps under language semantics; thrown/private values are normalized rather than echoed. The implementation adds no network fetch, transport, persistence, tenancy, credentials, model/provider, authorization, durable audit, deployment, migration or retention authority.

Verification / integration boundary

#176 carries executable SafeLink resource-bound, malformed-configuration, URL-parser preflight, accepted/rejected-target, editor/serializer integration, package/browser/Office and coverage tests. Current exact-head workflows, formal reviews, review threads, ancestry and live base must be refetched before lifecycle action; predecessor evidence does not transfer.

Keep this issue open until #176 integrates under then-live protected-main governance. #176 remains Draft/unmerged while #118 owns exact protected v0.6.0 publication/provenance acceptance. Do not create or revive a competing SafeLink writer, weaken gates, force-push/destructively rebase, move protected main, or represent this active-PR behavior as shipped.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: apiAPI, protocol, event, or external contractarea: authAuthentication, authorization, identity, or tenant isolationarea: ci-cdCI, GitHub Actions, checks, release, or supply chainarea: dataDatabase, schema, migration, ETL, or lineagepriority: mediumNormal-priority or P2 workstatus: triagedOpen issue has an organization taxonomy assignmenttype: bugDefect or incorrect behavior

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions