From a2990e8697a8049c4c90ced7b34719cc13565d1d Mon Sep 17 00:00:00 2001 From: Taarik <147209483+taarikashenafi@users.noreply.github.com> Date: Wed, 24 Jun 2026 13:20:36 -0500 Subject: [PATCH 1/5] Add redactUrl function to sanitize URLs This function helps in sanitizing URLs by removing sensitive query strings and fragments. --- src/utils/redact-url.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/utils/redact-url.ts diff --git a/src/utils/redact-url.ts b/src/utils/redact-url.ts new file mode 100644 index 0000000..f2a6624 --- /dev/null +++ b/src/utils/redact-url.ts @@ -0,0 +1,15 @@ +// Strips the query string and fragment from a URL so potentially sensitive +// values (signed-CDN tokens, session ids, user identifiers) are not forwarded +// to the model context or written to CI logs. Origin + path are preserved for +// debuggability. Inputs that don't parse as URLs are returned with anything +// after '?' or '#' dropped as a fallback. +export function redactUrl(url: string): string { + try { + const u = new URL(url) + u.search = '' + u.hash = '' + return u.toString() + } catch { + return url.split(/[?#]/)[0] ?? url + } +} From af413d29f9f457847ecf6d89fbd3be11037e0f1a Mon Sep 17 00:00:00 2001 From: Taarik <147209483+taarikashenafi@users.noreply.github.com> Date: Wed, 24 Jun 2026 13:24:52 -0500 Subject: [PATCH 2/5] Redact URLs in error messages for security Updated error logging to redact URLs for improved privacy. --- src/rules/alt-text-quality.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/rules/alt-text-quality.ts b/src/rules/alt-text-quality.ts index 8cf3825..32f231d 100644 --- a/src/rules/alt-text-quality.ts +++ b/src/rules/alt-text-quality.ts @@ -5,6 +5,7 @@ import {createJudge} from '../judges/index.js' import type {JudgeAltText, JudgeVerdict} from '../judges/index.js' import type {Rule, RuleContext, RuleResult, ImageRecord} from '../types.js' import {loadImageAsDataUrl} from '../utils/load-image-data-url.js' +import {redactUrl} from '../utils/redact-url.js' // Lazily build the judge so missing tokens surface only when the rule actually // runs @@ -47,7 +48,7 @@ function buildContextString(image: ImageRecord, pageUrl: string): string { if (image.pageTitle) parts.push(`Page title: ${JSON.stringify(image.pageTitle)}`) if (image.sectionHeading) parts.push(`Nearest heading above the image: ${JSON.stringify(image.sectionHeading)}`) parts.push(`Image HTML: ${sanitizeImageHtml(image.outerHTML)}`) - if (image.inLink) parts.push(`The image is inside a link with href="${image.inLink.href}".`) + if (image.inLink) parts.push(`The image is inside a link with href="${redactUrl(image.inLink.href)}".`) if (image.inButton) parts.push('The image is inside a button (or role="button" element).') if (image.figcaption) parts.push(`Adjacent figcaption: ${JSON.stringify(image.figcaption)}`) if (image.nearbyText) parts.push(`Surrounding body text: ${JSON.stringify(image.nearbyText)}`) @@ -102,7 +103,7 @@ export const altTextQuality: Rule = { try { dataUrl = await loadImageAsDataUrl(resolved) } catch (err) { - console.error(`[alt-text-quality] failed to load ${resolved}:`, err) + console.error(`[alt-text-quality] failed to load ${redactUrl(resolved)}:`, err) continue } @@ -116,7 +117,7 @@ export const altTextQuality: Rule = { naturalHeight: image.naturalHeight, }) } catch (err) { - console.error(`[alt-text-quality] judge failed for ${resolved}:`, err) + console.error(`[alt-text-quality] judge failed for ${redactUrl(resolved)}:`, err) continue } From 1be1ef49ce64a50def18c3f4bc38a19613eb5461 Mon Sep 17 00:00:00 2001 From: Taarik <147209483+taarikashenafi@users.noreply.github.com> Date: Wed, 24 Jun 2026 13:26:20 -0500 Subject: [PATCH 3/5] Add unit tests for redactUrl function --- tests/unit/redact-url.test.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/unit/redact-url.test.ts diff --git a/tests/unit/redact-url.test.ts b/tests/unit/redact-url.test.ts new file mode 100644 index 0000000..427c317 --- /dev/null +++ b/tests/unit/redact-url.test.ts @@ -0,0 +1,17 @@ +import {describe, it, expect} from 'vitest' +import {redactUrl} from '../../src/utils/redact-url.js' + +describe('redactUrl', () => { + it('strips the query string', () => { + expect(redactUrl('https://cdn.example.com/img.png?sig=secret123')).toBe('https://cdn.example.com/img.png') + }) + it('strips the fragment', () => { + expect(redactUrl('https://example.com/page#section')).toBe('https://example.com/page') + }) + it('leaves a clean URL unchanged', () => { + expect(redactUrl('https://example.com/img.png')).toBe('https://example.com/img.png') + }) + it('falls back gracefully on non-URL input', () => { + expect(redactUrl('not a url?x=1')).toBe('not a url') + }) +}) From 5bfdaa3fc31a038a1f8b4574e2059740a1070314 Mon Sep 17 00:00:00 2001 From: taarikashenafi Date: Wed, 24 Jun 2026 17:29:11 -0500 Subject: [PATCH 4/5] Scrub query/fragment from error messages; add href redaction test --- src/rules/alt-text-quality.ts | 6 ++++-- tests/unit/alt-text-quality.test.ts | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/rules/alt-text-quality.ts b/src/rules/alt-text-quality.ts index 32f231d..5fe6e50 100644 --- a/src/rules/alt-text-quality.ts +++ b/src/rules/alt-text-quality.ts @@ -103,7 +103,8 @@ export const altTextQuality: Rule = { try { dataUrl = await loadImageAsDataUrl(resolved) } catch (err) { - console.error(`[alt-text-quality] failed to load ${redactUrl(resolved)}:`, err) + const msg = (err instanceof Error ? err.message : String(err)).replace(/([?#])[^\s]*/g, '$1…') + console.error(`[alt-text-quality] failed to load ${redactUrl(resolved)}: ${redactUrl(msg)}`) continue } @@ -117,7 +118,8 @@ export const altTextQuality: Rule = { naturalHeight: image.naturalHeight, }) } catch (err) { - console.error(`[alt-text-quality] judge failed for ${redactUrl(resolved)}:`, err) + const msg = (err instanceof Error ? err.message : String(err)).replace(/([?#])[^\s]*/g, '$1…') + console.error(`[alt-text-quality] judge failed for ${redactUrl(resolved)}: ${redactUrl(msg)}`) continue } diff --git a/tests/unit/alt-text-quality.test.ts b/tests/unit/alt-text-quality.test.ts index d179fa8..ba0d13a 100644 --- a/tests/unit/alt-text-quality.test.ts +++ b/tests/unit/alt-text-quality.test.ts @@ -125,4 +125,20 @@ describe('alt-text-quality', () => { expect(context).toContain('src="(omitted)"') expect(context).toContain('srcset="(omitted)"') }) + + it('redacts query/fragment from the link href in the judge context', async () => { + const fake = new FakeJudge(() => verdict()) + __setJudge(fake) + await run([ + makeImage({ + src: DATA_URL, + alt: 'a dog', + inLink: {href: 'https://example.com/page?sig=secret123#frag'}, + }), + ]) + const context = fake.calls[0]!.context + expect(context).not.toContain('sig=secret123') + expect(context).not.toContain('#frag') + expect(context).toContain('https://example.com/page') + }) }) From c3b9a46722470ff108e36bbf16357634e60237a7 Mon Sep 17 00:00:00 2001 From: taarikashenafi Date: Tue, 30 Jun 2026 18:03:27 -0500 Subject: [PATCH 5/5] Use redactUrl directly on error message instead of inline regex --- src/rules/alt-text-quality.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/rules/alt-text-quality.ts b/src/rules/alt-text-quality.ts index 5fe6e50..3e86bee 100644 --- a/src/rules/alt-text-quality.ts +++ b/src/rules/alt-text-quality.ts @@ -103,8 +103,7 @@ export const altTextQuality: Rule = { try { dataUrl = await loadImageAsDataUrl(resolved) } catch (err) { - const msg = (err instanceof Error ? err.message : String(err)).replace(/([?#])[^\s]*/g, '$1…') - console.error(`[alt-text-quality] failed to load ${redactUrl(resolved)}: ${redactUrl(msg)}`) + console.error(`[alt-text-quality] failed to load ${redactUrl(resolved)}: ${redactUrl(String(err))}`) continue } @@ -118,8 +117,7 @@ export const altTextQuality: Rule = { naturalHeight: image.naturalHeight, }) } catch (err) { - const msg = (err instanceof Error ? err.message : String(err)).replace(/([?#])[^\s]*/g, '$1…') - console.error(`[alt-text-quality] judge failed for ${redactUrl(resolved)}: ${redactUrl(msg)}`) + console.error(`[alt-text-quality] judge failed for ${redactUrl(resolved)}: ${redactUrl(String(err))}`) continue }