You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(security): add injection character validation to all purl type validators (#16)
* fix(test): increase timeout for network-dependent purlExists tests
The conda and docker purlExists tests make real HTTP requests to external
registries. The conda test was timing out on CI at the default 10s limit.
Increase timeout to 30s for both network-calling tests.
* fix(test): reduce timeout to 15s
* feat(security): add injection character validation to all purl type validators
Add containsInjectionCharacters() checks to all 28 per-type validators,
rejecting shell/URL metacharacters (|, &, ;, `, $, <, >, (, ), {, }, #,
\, space, tab, newline, CR) in name and namespace components.
Previously only vscode-extension had these checks. Now every ecosystem
type validates against injection characters while respecting the purl
spec (which allows special characters in the generic type via
percent-encoding — so checks are per-type, not in the base validator).
- Enhanced 19 existing validators with injection checks
- Added new validate functions to 6 types (docker, github, gitlab,
bitbucket, hex, pypi) that previously only had normalize
- Registered all new validators in purl-type.ts
- Cocoapods: replaced \s regex with containsInjectionCharacters
(subsumes whitespace + adds shell metachar detection)
- npm/pub: already covered by URL-encoding and [a-z0-9_] checks
- Version strings intentionally NOT checked (Python epoch ! and
Maven space/& are legitimate)
- 47 new tests covering all types
* refactor(security): centralize injection validation, harden scanner, add PurlInjectionError
Architecture improvements:
- Default validator in purl-type.ts now runs injection checks for all
registered types — security is opt-out, not opt-in. Unregistered types
(used by purl spec tests) bypass the default, preserving spec compliance.
- New shared validateNoInjectionByType() helper in validate.ts eliminates
6-line injection check boilerplate from 26 per-type validators.
- Per-type validators now only contain ecosystem-specific rules.
Hardened scanner (containsInjectionCharacters):
- Added single quote (') and double quote (") detection — prevents
quote-breaking attacks in shell, SQL, and URL contexts
- Added full C0 control character range (0x00-0x1f) — catches ESC
(terminal escape sequences), BEL, vertical tab, form feed, and all
other control chars used for log/terminal injection
- Added DEL (0x7f) detection — control character used in terminal attacks
- Extracted isInjectionCharCode() for the core detection logic
- Added findInjectionCharCode() returning the offending char code
- Added formatInjectionChar() for human-readable error labels
New PurlInjectionError class:
- Subclass of PurlError — catchable as either type for flexible handling
- Exposes charCode, component, and purlType properties for programmatic
inspection by security tooling
- Error messages include the specific character found, e.g.:
'maven "namespace" component contains injection character ";" (0x3b)'
- Control characters formatted as hex: '0x1b' (not the raw ESC byte)
* fix(security): freeze PurlInjectionError, use primordials, add unit tests
- Freeze PurlInjectionError instances (ObjectFreeze in constructor) and
prototype — prevents property tampering on caught error objects
- Replace raw String.fromCharCode, Number.prototype.toString, and
String.prototype.padStart with captured primordials
(StringFromCharCode, NumberPrototypeToString, StringPrototypePadStart)
- Add unit tests verifying frozen instance, frozen prototype, and
rejection of property writes/additions on error objects
* fix: replace 8 raw built-in calls with captured primordials
- validate.ts: Array.isArray → ArrayIsArray, Object.keys → ObjectKeys
- normalize.ts: Object.entries → ObjectEntries
- vscode-extension.ts: JSON.stringify → JSONStringify
- gem.ts: Array.isArray → ArrayIsArray
- npm.ts: new Set() → new SetCtor() (2 instances)
- primordials.ts: add NumberPrototypeToString, StringFromCharCode,
StringPrototypePadStart exports
0 commit comments