Summary
The color attribute on the <capture-eye> element is passed directly to this.style.setProperty('--primary-color', this._color) at src/modal/modal.ts line 637 without any input validation. This occurs before the hex pattern check at line 652, which only guards the hover color calculation — the primary color is already injected.
Vulnerability Details
Attack Surface:
The color attribute is an HTML attribute set by integrators and can be controlled via:
- Direct HTML:
<capture-eye color="red; --injected: value" ...>
- JavaScript:
element.setAttribute('color', 'malicious value')
- CMS widget settings (WordPress Elementor, Wix, etc.)
Vulnerable Code Path:
// src/modal/modal.ts:635-667
private updateModalColor() {
// Line 637: Injected BEFORE any validation
this.style.setProperty('--primary-color', this._color);
// Lines 652-654: Validation only guards hover color, not primary
const hexPattern = /^#[0-9a-fA-F]{6}$/;
if (!hexPattern.test(hoverColor)) {
return; // Only exits hover color calc, primary already set
}
}
Attack Vectors:
- CSS variable contamination:
color="red; --modal-content: none" — could hide modal elements
- CSS property injection through browsers that allow semicolons in custom property values
- UI spoofing — inject colors that mimic trusted UI patterns
Root Cause:
color property declared at src/capture-eye.ts line 44-45 as plain String with no validation
- No sanitization between attribute ingestion and CSS variable injection
- Validation at line 652 only checks the canvas-normalized value for hover color calculation, not the raw input
Impact
- CSS injection can hide/alter UI elements, potentially enabling phishing overlays
- Data exfiltration via CSS side channels (e.g.,
url() in custom properties)
- Affects all integration surfaces: direct HTML, WordPress, Wix, Elementor
Suggested Fix
Add color validation before setProperty:
private isValidColor(color: string): boolean {
const patterns = [
/^#[0-9a-fA-F]{3}$/, // #FFF
/^#[0-9a-fA-F]{6}$/, // #FFFFFF
/^#[0-9a-fA-F]{8}$/, // #FFFFFF00
/^rgb\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*\)$/,
/^rgba\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*[\d.]+\s*\)$/,
];
const namedColors = [
'red','blue','green','black','white','orange','yellow',
'purple','pink','gray','grey','cyan','magenta','transparent'
];
const trimmed = color.trim().toLowerCase();
return patterns.some(p => p.test(trimmed)) || namedColors.includes(trimmed);
}
private updateModalColor() {
if (!this._color || !this.isValidColor(this._color)) {
this.style.setProperty('--primary-color', '');
this.style.setProperty('--hover-color', '');
return;
}
this.style.setProperty('--primary-color', this._color);
// ... rest of hover color calc
}
Also move the canvas-based validation before setProperty to ensure a defense-in-depth approach.
Summary
The
colorattribute on the<capture-eye>element is passed directly tothis.style.setProperty('--primary-color', this._color)atsrc/modal/modal.tsline 637 without any input validation. This occurs before the hex pattern check at line 652, which only guards the hover color calculation — the primary color is already injected.Vulnerability Details
Attack Surface:
The
colorattribute is an HTML attribute set by integrators and can be controlled via:<capture-eye color="red; --injected: value" ...>element.setAttribute('color', 'malicious value')Vulnerable Code Path:
Attack Vectors:
color="red; --modal-content: none"— could hide modal elementsRoot Cause:
colorproperty declared atsrc/capture-eye.tsline 44-45 as plainStringwith no validationImpact
url()in custom properties)Suggested Fix
Add color validation before
setProperty:Also move the canvas-based validation before
setPropertyto ensure a defense-in-depth approach.