fix(skills): stop flagging remote markdown documentation links in skill audit#8190
Conversation
β¦ll audit The skill security audit blocked any http/https/mailto markdown link whose target ended in `.md`/`.markdown`, reporting "remote markdown links are blocked". This was a false positive: the loader never fetches these URLs at audit/load time β they pass through as prompt text, and any later fetch stays governed by normal tool/network policy. A `.md` suffix also doesn't reliably indicate Markdown content (many docs sites serve HTML at `.md` routes), so the check silently degraded legitimate skills (e.g. Cloudinary, Sanity) that cite many such URLs. Remove only that branch so the http/https/mailto arm returns without a finding. All structural checks are preserved: unsupported schemes, unsafe/absolute local paths, script-like link targets, and broken same-skill references. Adds regression tests covering remote .md/.markdown/mailto links passing clean and unsupported schemes (javascript:/file:) still being rejected. Closes zeroclaw-labs#6714
Audacity88
left a comment
There was a problem hiding this comment.
Thanks @IftekharUddin. I reviewed the live PR state at 6b704db, the linked #6714 acceptance comments, the one-file skills/audit.rs diff, the surrounding audit and skill-loading code, and the public CI/check status. I did not run local Cargo for this review-only pass; I relied on the PR's reported validation, green public CI, and source review.
π’ What looks good β The cleanup preserves the skill-audit boundary
This matches the policy boundary accepted in #6714. The audit still handles local structure: unsupported URL schemes continue to be rejected, unsafe local paths and script-like link targets still route through the existing checks, and same-skill-root Markdown references still get resolved and validated. The change removes only the false-positive branch for remote http / https / mailto documentation links that happen to end in .md or .markdown.
The regression coverage is also pointed at the right risks. One test proves remote documentation links now audit clean, and the other proves javascript: and file: Markdown links still produce unsupported-scheme findings. I also checked the surrounding skill-loading path: these Markdown links are read as prompt text, not fetched by the audit or loader, so later network access remains a tool-policy decision rather than a load-time side effect.
Approving β the implementation preserves the structural audit boundary accepted in #6714, the regression tests cover the right risks, and all visible CI checks pass.
WareWolf-MoonWall
left a comment
There was a problem hiding this comment.
Review β PR #8190 fix(skills): stop flagging remote markdown documentation links in skill audit
Author: IftekharUddin
Head SHA: 6b704db
Verdict: --approve
CI: 18/18 passing β
Active blocking reviews: None. Audacity88 approved (Member).
I reviewed the diff at 6b704db, the surrounding audit_markdown_link_target function in
crates/zeroclaw-runtime/src/skills/audit.rs (local source, lines 235β337), the test suite,
and the PR's security claims against the audit architecture. The fix is minimal, targeted, and
correct. Security analysis below.
π’ The security boundary is correctly preserved
The core question for this PR is whether removing the .md-suffix check on http/https/mailto
links creates a bypass path for executable remote content. It does not, for the following
reasons verified against the local source:
-
No load-time fetch occurs. The audit function inspects link targets as strings. The
loader never performs an HTTP request for markdown links inSKILL.mdβ they are read as
prompt text. This is confirmed by the absence of anyreqwestcall in theskills/audit.rs
code path and by the existingskills/reqwest use (install-bundle download only, unrelated
to audit). -
Structural checks are unaffected. The scheme guard immediately below the removed branch
still catchesjavascript:,file:,data:, and all other non-http(s)/mailto schemes with
an "unsupported URL scheme" finding. Thehas_script_suffixcheck,looks_like_absolute_path
check, and same-skill-root file existence check all operate only on the local-path branch
(after the earlyreturn) and are untouched. -
The
.mdsuffix is not a reliable content-type signal. As the PR correctly notes,
many documentation hosting platforms (Cloudinary, Sanity, GitHub Pages) serve HTML at.md
routes. The check was not providing a meaningful security guarantee. -
Downstream fetch remains tool-policy gated. If an agent later follows a link from
skill prompt text, that action goes through the normal tool/network policy (domain guard,
SSRF check, allowlist). The audit layer is not the right place to police post-load fetches.
π’ Regression coverage covers the right risks
audit_allows_remote_markdown_documentation_links: proveshttps://cloudinary.com/...transformation_reference.md,
http://example.com/docs/schema.markdown, andmailto:support@example.comall audit clean.
Usestempfile::tempdir()(hermetic, no network). βaudit_still_rejects_unsupported_url_schemes: provesjavascript:alert(1)and
file:///etc/passwd.mdstill produce exactly two "unsupported URL scheme in markdown link"
findings. Covers the exact bypass scenario the PR risks. β
The two tests together pin the boundary: safe-for-prompt-text http/https/mailto links pass,
and scheme-dangerous links still fail. This is the right regression shape.
π’ Validation evidence is comprehensive
cargo test --workspace --locked β 9456 passed, 0 failed, 67 test binaries, including both
new tests. cargo fmt, cargo clippy -D warnings both clean. Full workspace run is above and
beyond the minimum required.
π΅ Suggestion β The has_markdown_suffix helper is now unreferenced at the URL branch
has_markdown_suffix is still used in the local-path branch (line ~282: checks whether a
relative path link points to a .md file before attempting to canonicalize it). The PR body
correctly confirms "has_markdown_suffix is still referenced elsewhere (no dead code)" β the
local-path branch is the surviving caller. Just confirming this is consistent with the local
source.
Template completeness
| Section | Status |
|---|---|
| Summary | β |
| Validation Evidence | β (full workspace test run) |
| Security & Privacy | β (removal of check explained and justified) |
| Compatibility | β |
| Rollback | β |
| No AI trailers | β |
| No bare string literals | β |
Summary
masteraudit_markdown_link_targetflagged anyhttp/https/mailtomarkdown link whose target ended in.md/.markdownwithremote markdown links are blocked. This is a false positive β the loader never fetches those URLs at audit/load time; they pass through as prompt text, and any later fetch stays gated by the existing tool/network policy..mdsuffix does not reliably indicate Markdown (e.g. Cloudinary serves HTML at.mdroutes), so the check carried no load-bearing security while silently downgrading or skipping real marketplace skills (cloudinary-transformationscites ~40 such docs links; Sanity skills similarly).http/https/mailtoarm early-returns with no finding. The early return is kept deliberately β dropping the whole arm would route these links into theunsupported URL schemefinding instead..md/.markdown/mailtolinks audit clean, and unsupported schemes (javascript:/file:) are still rejected.crates/zeroclaw-runtime/src/skills/audit.rs..mddoc URLs now load; every other audit finding is unchanged β unsupported URL schemes, absolute/unsafe local paths, script-suffix links, and broken same-skill-root references all still fire.Validation Evidence (required)
Commands run and tail output:
cargo fmt --all -- --checkβ exit 0 (no diff).cargo clippy --all-targets -- -D warningsβ exit 0, no warnings (all crates):cargo test(root crate, mirrorsdev/ci.sh'scargo test --locked) β 903 passed, 0 failed:cargo test -p zeroclaw-runtime --lib(the changed crate β the rootcargo testabove does not reach it) β 2347 passed, 0 failed, including the two new tests:cargo test --workspace --locked(every member crate, comprehensive) β 9456 passed, 0 failed across all 67 test binaries; both new audit tests included.Beyond CI β what I manually verified: Confirmed
has_markdown_suffixis still referenced elsewhere (no dead code); confirmed the markdown-link regex still capturesjavascript:/file://targets so the unsupported-scheme check keeps firing (the new test asserts exactly two such findings); confirmed via grep that no other skills load/audit path fetches remote markdown β the onlyreqwestuse underskills/downloads the install bundle, which is unrelated. Not verified: live end-to-end install of a Cloudinary/Sanity skill (no network/marketplace access in this environment); the audit-level behavior is covered by the unit tests above.If any command was intentionally skipped, why: None skipped.
Security & Privacy Impact (required)
example.comand amailto:support@example.complaceholder.Context: although this touches the security audit, the removed check provided no load-bearing security (no load-time fetch occurs, and a
.mdsuffix is not an authoritative content-type signal). All structural audit guarantees are preserved.Compatibility (required)
.mddocumentation URLs now load successfully; no action required.Rollback
Low risk:
git revert <merge sha>fully restores prior behavior.git revert <merge sha>remote markdown links are blocked by skill security audit (<url>)finding reappearing in skill audit output /zeroclaw skills list, or skills with.mddoc links being downgraded/skipped again.Note on labels: issue #6714 carries
risk: high, but this change removes a single conditional branch with no cross-crate blast radius; suggestedrisk: low,size: S, scopeskills/runtime/security. Deferring to maintainers for the final label set.