Skip to content

Commit 0cd9178

Browse files
Copilothotlong
andcommitted
Add URL validation to ActionRunner and improve accessibility in field widgets
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 70c314e commit 0cd9178

File tree

3 files changed

+21
-1
lines changed

3 files changed

+21
-1
lines changed

packages/core/src/actions/ActionRunner.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,21 @@ export class ActionRunner {
122122
const nav = action.navigate || action;
123123
const to = this.evaluator.evaluate(nav.to) as string;
124124

125+
// Validate URL to prevent javascript: or data: schemes
126+
const isValidUrl = typeof to === 'string' && (
127+
to.startsWith('http://') ||
128+
to.startsWith('https://') ||
129+
to.startsWith('/') ||
130+
to.startsWith('./')
131+
);
132+
133+
if (!isValidUrl) {
134+
return {
135+
success: false,
136+
error: 'Invalid URL scheme. Only http://, https://, and relative URLs are allowed.'
137+
};
138+
}
139+
125140
if (nav.external) {
126141
window.open(to, '_blank', 'noopener,noreferrer');
127142
} else {

packages/fields/src/widgets/LookupField.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ export function LookupField({ value, onChange, field, readonly }: FieldWidgetPro
108108
onClick={() => handleRemove(opt?.value)}
109109
className="ml-1 hover:text-destructive"
110110
type="button"
111+
aria-label={`Remove ${opt?.[displayField] || opt?.label}`}
111112
>
112113
<X className="size-3" />
113114
</button>

packages/fields/src/widgets/TextAreaField.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ export function TextAreaField({ value, onChange, field, readonly, errorMessage,
2828
aria-invalid={!!errorMessage}
2929
/>
3030
{maxLength && (
31-
<div className="absolute bottom-2 right-2 text-xs text-gray-400">
31+
<div
32+
className="absolute bottom-2 right-2 text-xs text-gray-400"
33+
aria-live="polite"
34+
aria-label={`Character count: ${(value || '').length} of ${maxLength}`}
35+
>
3236
{(value || '').length}/{maxLength}
3337
</div>
3438
)}

0 commit comments

Comments
 (0)