fix(agents): reject pathless media and direct file URLs

This commit is contained in:
4gray committed 2026-09-21 04:33:33 +02:00
1 parent 47cfc1ba4a
commit 802d3dc43c
3 files changed
+17 -1

No files matched your search

+2 -1
View File
@@ -65,7 +65,8 @@ Inline iframe srcdoc documents are traversed too, with their own fragment anchor
The first active HTML base href sets reference resolution, including nested srcdoc bases.
Resolved file URLs use native filesystem conversion, including Windows drive paths.
Explicit srcset attributes must contain at least one parsed candidate.
Image and media references require nonempty targets that resolve to files, not directories.
Image and media references require a nonempty path that resolves to a file, not a directory.
Direct file URLs are rejected; use portable repository-relative paths.
Image references check file existence without interpreting image fragments as
Markdown headings; document links keep anchor checks even when sharing a target.
HTML video, audio, source and track `src` assets and video posters use the same
+4
View File
@@ -41,6 +41,8 @@ async function validateReference(
) {
if (unresolvedReference !== undefined)
return `${source}: unresolved Markdown reference "${unresolvedReference}"`;
if (/^file:/iu.test(target))
return `${source}: use a repository-relative path instead of a file URL: ${target}`;
if (image && !target) return `${source}: empty media target`;
let resolvedBasePath;
if (bases?.length) {
@@ -68,6 +70,8 @@ async function validateReference(
} catch {
return `${source}: malformed local link: ${target}`;
}
if (image && !path && !resolvedBasePath)
return `${source}: media target requires a path: ${target}`;
if (embeddedAnchors && !path && !image)
return !anchor || embeddedAnchors.includes(anchor)
? undefined
@@ -1586,3 +1586,14 @@ for (const extension of ['pdf', 'rst', 'adoc', 'markdown', 'docm', 'latex']) {
);
});
}
for (const markup of [
'![logo](#missing)',
'<img src="?v=1">',
'[Guide](file:///tmp/missing.md)',
'<a href="file:///etc/hosts">Guide</a>',
]) {
test(`nonportable or pathless target is rejected: ${markup}`, async (t) => {
assert.ok((await diagnostics(t, { 'AGENTS.md': markup })).length > 0);
});
}