@@ -270,6 +270,7 @@ func ScanDirs(projectDir, userDir string, extraDirs []string) *ScanResult {
270270}
271271
272272// scanDir reads all SKILL.md files in a single skill directory.
273+ // Symlinks are refused — they could redirect reads to arbitrary files.
273274func scanDir (dir string ) []Skill {
274275 entries , err := os .ReadDir (dir )
275276 if err != nil {
@@ -281,6 +282,11 @@ func scanDir(dir string) []Skill {
281282 if ! e .IsDir () {
282283 continue
283284 }
285+ // Refuse symlink entries — a symlinked skill directory could
286+ // redirect reads to arbitrary paths.
287+ if e .Type ()& os .ModeSymlink != 0 {
288+ continue
289+ }
284290 skillPath := filepath .Join (dir , e .Name (), "SKILL.md" )
285291 s := parseSkillFile (skillPath )
286292 if s == nil {
@@ -308,7 +314,14 @@ const FenceEnd = "╚═══ END SKILL — resume core identity ═══╝"
308314// FormatAsContext formats a skill's body for injection into the system prompt.
309315// The skill is wrapped in protective fences that tell the model this content
310316// is external guidance, lower priority than core identity.
317+ // The body is sanitized to prevent fence breakout — any embedded FenceEnd
318+ // markers are replaced so they can't close the outer fence prematurely.
311319func FormatAsContext (s Skill ) string {
320+ // Sanitize body: replace any embedded FenceEnd marker to prevent
321+ // fence breakout attacks where a skill contains the closing fence
322+ // as part of its content.
323+ body := strings .ReplaceAll (s .Body , FenceEnd , "[FENCE-END-MARKER-REMOVED]" )
324+
312325 var b strings.Builder
313326 b .WriteString (FenceBegin )
314327 b .WriteString ("\n ## Skill: " )
@@ -320,8 +333,8 @@ func FormatAsContext(s Skill) string {
320333 b .WriteString ("0" )
321334 }
322335 b .WriteString (")\n \n " )
323- b .WriteString (s . Body )
324- if ! strings .HasSuffix (s . Body , "\n " ) {
336+ b .WriteString (body )
337+ if ! strings .HasSuffix (body , "\n " ) {
325338 b .WriteString ("\n " )
326339 }
327340 b .WriteString (FenceEnd )
0 commit comments