( skill: Skill, filePath: string, metadataSummary: string, llmContext: LlmCallContext, logger: LoggerLike, options: Required<FoundationScanConfig>, )
| 581 | } |
| 582 | |
| 583 | async function scanSkillFile( |
| 584 | skill: Skill, |
| 585 | filePath: string, |
| 586 | metadataSummary: string, |
| 587 | llmContext: LlmCallContext, |
| 588 | logger: LoggerLike, |
| 589 | options: Required<FoundationScanConfig>, |
| 590 | ): Promise<Warning | null> { |
| 591 | try { |
| 592 | const content = fs.readFileSync(filePath, "utf-8"); |
| 593 | const contentHash = calculateContentHash(content); |
| 594 | |
| 595 | if (TRUSTED_FILE_HASHES.has(contentHash)) { |
| 596 | logger?.info(`[FoundationScan] trusted hash hit: skill=${skill.name ?? "(unknown)"}, file=${filePath}`); |
| 597 | return null; |
| 598 | } |
| 599 | |
| 600 | if (options.detectMaliciousSkills.ruleBasedDetection) { |
| 601 | const ruleDetection = detectByRules(content); |
| 602 | if (ruleDetection?.blocked) { |
| 603 | logger?.warn(`[FoundationScan] RuleBased detection blocked: skill=${skill.name ?? "(unknown)"}, file=${filePath}, reason=${ruleDetection.reason}`); |
| 604 | return createMaliciousWarning(`Skill: ${skill.name}\nFile: ${filePath}\nReason: ${ruleDetection.reason}`); |
| 605 | } |
| 606 | } |
| 607 | |
| 608 | if (options.detectMaliciousSkills.semanticDetection) { |
| 609 | logger?.info(`[FoundationScan] SemanticBased detection: skill=${skill.name ?? "(unknown)"}, file=${filePath}`); |
| 610 | let semanticDetection: Detection | null = null; |
| 611 | if (metadataSummary) { |
| 612 | logger?.info(`[FoundationScan] SemanticBased detection: using API with metadata summary (length=${metadataSummary.length})`); |
| 613 | const detectionResult = await detectSkillContentRisk( |
| 614 | skill, |
| 615 | metadataSummary, |
| 616 | filePath, |
| 617 | content, |
| 618 | llmContext, |
| 619 | logger, |
| 620 | options.detectMaliciousSkills.maxContentLength, |
| 621 | ); |
| 622 | if (detectionResult) { |
| 623 | logger?.info(`[FoundationScan] SemanticBased detection result - aligned=${detectionResult.aligned}, malicious=${detectionResult.malicious}, reason=${detectionResult.reason.substring(0, 200)}...`); |
| 624 | } else { |
| 625 | logger?.warn(`[FoundationScan] SemanticBased detection: API returned null, assuming benign`); |
| 626 | } |
| 627 | if (detectionResult?.malicious || detectionResult?.aligned === false) { |
| 628 | const issueType = detectionResult?.malicious ? "MALICIOUS CONTENT" : "MISALIGNED CONTENT"; |
| 629 | const detailedReason = detectionResult?.reason || "Content judged as potentially harmful or misaligned"; |
| 630 | semanticDetection = { |
| 631 | blocked: true, |
| 632 | reason: `[FILE ANALYSIS] ${issueType} detected in skill file.\n` + |
| 633 | `📋 Skill: ${skill.name}\n` + |
| 634 | `📄 File: ${filePath}\n` + |
| 635 | `⚠️ Detection Type: ${detectionResult?.malicious ? 'Malicious Intent' : 'Capability Misalignment'} (Semantic Analysis)\n` + |
| 636 | `🔍 Specific Reason: ${detailedReason}\n` + |
| 637 | `💡 Impact: ${detectionResult?.malicious ? 'This file may attempt to perform unauthorized or harmful actions.' : 'This file deviates from the skill\'s intended capability.'}` |
| 638 | }; |
| 639 | } |
| 640 | } else { |
no test coverage detected