fix(agent): skip symlink escapes when listing skill supporting files - #68711
fangliquanflq wants to merge 7 commits into
Conversation
Directory symlinks under scripts/references/templates/assets were followed by rglob, leaking host paths into slash-skill invocation messages. Skip redirected dirs and require resolved paths stay inside the skill tree.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for pursuing a narrow fix for a real slash-skill path-disclosure problem.
Problems
- The new fallback guard is bypassed whenever
linked_filesis populated:agent/skill_commands.py:278-284copies those entries unchanged before the guarded fallback.tools/skills_tool.py:1414-1450buildslinked_filesby scanningreferences/,templates/,assets/, andscripts/without a resolved-path boundary check. A redirectedscripts/containingpayload.py, for example, remains listed in the invocation message. - The new
id_rsafixture attests/agent/test_skill_commands.py:768only exercises the fallback because the scripts linked-file scanner accepts only*.py,*.sh,*.bash,*.js,*.ts, and*.rb(tools/skills_tool.py:1447-1450).
Suggested changes
- Filter
linked_filesat the same resolved-root boundary, and harden its producer intools/skills_tool.py. - Add redirected-directory tests using recognized linked-file extensions and verify both slash invocation output and
skill_viewdiscovery stay inside the skill root.
This is an automated hermes-sweeper review.
|
Addressed the sweeper review in 220e6ad and a969ae3. Both skill_view discovery and slash invocation now enforce resolved containment within the skill root. The regression coverage uses recognized payload.py and secret.md files, checks stale linked_files at the consumer boundary, preserves safe in-root directory links, and includes Windows-only junction coverage. Targeted validation completed with 154 passing tests and one Windows-only skip on this non-Windows runner. |
|
suggesting changes The patch closes the direct linked-file and activation-message symlink escapes and preserves safe in-root redirects, but the missing-file fallback still enumerates skill contents without containment checks. An external symlink can therefore remain visible in the available-files response when a nonexistent support file is requested.
Security evidence:
Not checked:
Signed: GPT-5.6-luna-max in Codex |
|
Addressed the remaining supporting-file fallback bypass in de14438. Missing-file inventory and slash/preload fallback discovery now share containment-aware traversal, prune external redirects and junction cycles, and preserve safe in-root redirects. Added real Windows junction-cycle coverage and avoided decoding localized mklink output.\n\nValidation:\n- security-focused symlink/junction scope: 11 passed\n- junction regression scope after the test-only cleanup: 2 passed\n- complete related-file run: 67 passed; 3 pre-existing Windows path/inline-shell assertions failed outside this change |
fix(agent): skip symlink escapes when listing skill supporting files
|
What does this PR do?
When building slash-skill invocation messages,
_build_skill_messagefalls back toPath.rglobunderreferences//templates//scripts//assets/. It only skipped file symlinks, so a directory symlink (or junction) could walk host paths and inject filenames + absolute paths into the agent context.Skip redirected supporting dirs, and require each listed file's resolved path to stay inside the skill tree.
Related Issue
N/A (found via local bug hunt; related incomplete prior attempts: #6693, #6952)
Type of Change
Changes Made
agent/skill_commands.py: skip symlink/junction supporting dirs;resolve().is_relative_to(skill_root)gate on enumerated filestests/agent/test_skill_commands.py: regression tests for top-level and nested directory symlink escapesHow to Test
scripts/run_tests.sh tests/agent/test_skill_commands.py::TestSkillDirectoryHeader -qscripts/is a directory symlink to a secret dir; invoke/skill-nameand confirmid_rsa(etc.) is not listed under supporting filesscripts/run.jsstill shows supporting-file hintsChecklist
Code
TestSkillDirectoryHeader)Documentation & Housekeeping
cli-config.yaml.example— N/ACONTRIBUTING.md/AGENTS.md— N/A