Skip to content

Backport: ReDoS fix + NarrowedBy getter limitation #33

@UniquePixels

Description

@UniquePixels

Summary

Two framework issues discovered during the Unbound bot migration need upstream attention.

Issue 1: ReDoS risk in component.ts dynamic RegExp (CWE-1333)

Severity: Security
Found by: Semgrep pre-migration scan
Fix available: framework/fixes branch on Unbound repo (commits 36edc09, ea3db35)

parseComponentId() constructs a RegExp from user-provided component ID patterns without validating the input characters. A malicious or malformed pattern containing quantifiers, alternation, or nested groups could cause catastrophic backtracking.

Fix: Added SAFE_PATTERN allowlist (/^[a-zA-Z0-9_:.-]+$/) that validates the inner pattern before regex construction. Only alphanumerics, dashes, underscores, dots, and :param markers are permitted. Throws AppError with code ERR_COMPONENT_PATTERN for invalid characters.

Also added nosemgrep annotation on the new RegExp() call with a safety comment explaining why the dynamic regex is safe post-validation.

Files changed:

  • src/core/sparks/component.ts — validation + safety comments
  • src/core/sparks/component.test.tstest.each for rejected characters (|, (, ), [, ], +, *)

Issue 2: NarrowedBy cannot narrow class getters

Severity: Type system limitation (no runtime impact)
No code fix — documentation/awareness only

TypeScript intersection types cannot override class getters. When inCachedGuild guard narrows BaseInteraction, the guild property (a getter on the class) produces Guild & (Guild | null) instead of the expected Guild. This means code after the guard still sees guild as potentially null.

Workaround: Use non-null assertion (interaction.guild!) with a biome-ignore comment referencing this issue.

Upstream options:

  1. Document the limitation in guard/NarrowedBy docs
  2. Consider runtime accessor pattern instead of type-level narrowing for class getters
  3. Accept as known TS limitation

Found during the Unbound bot migration (Domains 0–10). Ready to cherry-pick from the framework/fixes branch for Issue 1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions