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.ts — test.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:
- Document the limitation in guard/NarrowedBy docs
- Consider runtime accessor pattern instead of type-level narrowing for class getters
- 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.
Summary
Two framework issues discovered during the Unbound bot migration need upstream attention.
Issue 1: ReDoS risk in
component.tsdynamic RegExp (CWE-1333)Severity: Security
Found by: Semgrep pre-migration scan
Fix available:
framework/fixesbranch on Unbound repo (commits36edc09,ea3db35)parseComponentId()constructs aRegExpfrom 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_PATTERNallowlist (/^[a-zA-Z0-9_:.-]+$/) that validates the inner pattern before regex construction. Only alphanumerics, dashes, underscores, dots, and:parammarkers are permitted. ThrowsAppErrorwith codeERR_COMPONENT_PATTERNfor invalid characters.Also added
nosemgrepannotation on thenew RegExp()call with a safety comment explaining why the dynamic regex is safe post-validation.Files changed:
src/core/sparks/component.ts— validation + safety commentssrc/core/sparks/component.test.ts—test.eachfor rejected characters (|,(,),[,],+,*)Issue 2:
NarrowedBycannot narrow class gettersSeverity: Type system limitation (no runtime impact)
No code fix — documentation/awareness only
TypeScript intersection types cannot override class getters. When
inCachedGuildguard narrowsBaseInteraction, theguildproperty (a getter on the class) producesGuild & (Guild | null)instead of the expectedGuild. This means code after the guard still seesguildas potentially null.Workaround: Use non-null assertion (
interaction.guild!) with abiome-ignorecomment referencing this issue.Upstream options:
Found during the Unbound bot migration (Domains 0–10). Ready to cherry-pick from the
framework/fixesbranch for Issue 1.