@panguard-ai/scan-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/atr-engine.test.d.ts +2 -0
- package/dist/__tests__/atr-engine.test.d.ts.map +1 -0
- package/dist/__tests__/atr-engine.test.js +360 -0
- package/dist/__tests__/atr-engine.test.js.map +1 -0
- package/dist/__tests__/context-signals.test.d.ts +2 -0
- package/dist/__tests__/context-signals.test.d.ts.map +1 -0
- package/dist/__tests__/context-signals.test.js +373 -0
- package/dist/__tests__/context-signals.test.js.map +1 -0
- package/dist/__tests__/hash-utils.test.d.ts +2 -0
- package/dist/__tests__/hash-utils.test.d.ts.map +1 -0
- package/dist/__tests__/hash-utils.test.js +89 -0
- package/dist/__tests__/hash-utils.test.js.map +1 -0
- package/dist/__tests__/manifest-parser.test.d.ts +2 -0
- package/dist/__tests__/manifest-parser.test.d.ts.map +1 -0
- package/dist/__tests__/manifest-parser.test.js +246 -0
- package/dist/__tests__/manifest-parser.test.js.map +1 -0
- package/dist/__tests__/risk-scorer.test.d.ts +2 -0
- package/dist/__tests__/risk-scorer.test.d.ts.map +1 -0
- package/dist/__tests__/risk-scorer.test.js +189 -0
- package/dist/__tests__/risk-scorer.test.js.map +1 -0
- package/dist/__tests__/scanner.test.d.ts +2 -0
- package/dist/__tests__/scanner.test.d.ts.map +1 -0
- package/dist/__tests__/scanner.test.js +442 -0
- package/dist/__tests__/scanner.test.js.map +1 -0
- package/dist/atr-engine.d.ts +31 -0
- package/dist/atr-engine.d.ts.map +1 -0
- package/dist/atr-engine.js +149 -0
- package/dist/atr-engine.js.map +1 -0
- package/dist/context-signals.d.ts +33 -0
- package/dist/context-signals.d.ts.map +1 -0
- package/dist/context-signals.js +162 -0
- package/dist/context-signals.js.map +1 -0
- package/dist/hash-utils.d.ts +20 -0
- package/dist/hash-utils.d.ts.map +1 -0
- package/dist/hash-utils.js +28 -0
- package/dist/hash-utils.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/instruction-patterns.d.ts +18 -0
- package/dist/instruction-patterns.d.ts.map +1 -0
- package/dist/instruction-patterns.js +291 -0
- package/dist/instruction-patterns.js.map +1 -0
- package/dist/manifest-parser.d.ts +19 -0
- package/dist/manifest-parser.d.ts.map +1 -0
- package/dist/manifest-parser.js +73 -0
- package/dist/manifest-parser.js.map +1 -0
- package/dist/markdown-utils.d.ts +16 -0
- package/dist/markdown-utils.d.ts.map +1 -0
- package/dist/markdown-utils.js +41 -0
- package/dist/markdown-utils.js.map +1 -0
- package/dist/risk-scorer.d.ts +21 -0
- package/dist/risk-scorer.d.ts.map +1 -0
- package/dist/risk-scorer.js +63 -0
- package/dist/risk-scorer.js.map +1 -0
- package/dist/scanner.d.ts +24 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +131 -0
- package/dist/scanner.js.map +1 -0
- package/dist/secret-detection.d.ts +16 -0
- package/dist/secret-detection.d.ts.map +1 -0
- package/dist/secret-detection.js +42 -0
- package/dist/secret-detection.js.map +1 -0
- package/dist/types.d.ts +106 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Signal Detection Engine
|
|
3
|
+
*
|
|
4
|
+
* Detects malicious-intent boosters and legitimate-intent reducers
|
|
5
|
+
* in skill content. Returns a multiplier that adjusts risk scoring.
|
|
6
|
+
*
|
|
7
|
+
* This is the single canonical implementation used by both CLI and Website.
|
|
8
|
+
*/
|
|
9
|
+
import type { ContextSignals } from './types.js';
|
|
10
|
+
interface ManifestLike {
|
|
11
|
+
readonly name?: string;
|
|
12
|
+
readonly description?: string;
|
|
13
|
+
readonly license?: string;
|
|
14
|
+
readonly metadata?: {
|
|
15
|
+
readonly version?: string;
|
|
16
|
+
readonly openclaw?: {
|
|
17
|
+
readonly requires?: {
|
|
18
|
+
readonly bins?: readonly string[];
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
readonly 'allowed-tools'?: readonly string[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Detect context signals from skill content and manifest.
|
|
26
|
+
*
|
|
27
|
+
* @param content - Full text content of the skill (SKILL.md / README)
|
|
28
|
+
* @param manifest - Parsed frontmatter manifest (nullable)
|
|
29
|
+
* @returns Context signals with calculated multiplier
|
|
30
|
+
*/
|
|
31
|
+
export declare function detectContextSignals(content: string, manifest: ManifestLike | null | undefined): ContextSignals;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=context-signals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-signals.d.ts","sourceRoot":"","sources":["../src/context-signals.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAiB,cAAc,EAAiB,MAAM,YAAY,CAAC;AAyC/E,UAAU,YAAY;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAClB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE;YAClB,QAAQ,CAAC,QAAQ,CAAC,EAAE;gBAClB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;aACnC,CAAC;SACH,CAAC;KACH,CAAC;IACF,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GACxC,cAAc,CAqJhB"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Signal Detection Engine
|
|
3
|
+
*
|
|
4
|
+
* Detects malicious-intent boosters and legitimate-intent reducers
|
|
5
|
+
* in skill content. Returns a multiplier that adjusts risk scoring.
|
|
6
|
+
*
|
|
7
|
+
* This is the single canonical implementation used by both CLI and Website.
|
|
8
|
+
*/
|
|
9
|
+
import { extractCodeBlocks, stripCodeBlocks } from './markdown-utils.js';
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Booster Patterns (malicious signals)
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
const IMPORTANT_BLOCK_RE = /<IMPORTANT>/i;
|
|
14
|
+
const CONCEALMENT_RE = /\b(do\s+not\s+tell|don[''\u2019t]*\s+(tell|mention|notify|inform|reveal|show)|keep\s+(this\s+)?hidden|hide\s+this\s+from|this\s+is\s+(?:a\s+)?secret|be\s+very\s+gentle\s+and\s+not\s+scary)\b/i;
|
|
15
|
+
const EXFIL_URL_RE = /\.(workers\.dev|ngrok\.io|pipedream\.net|requestbin\.com|hookbin\.com|webhook\.site)\b|[?&](data|payload|exfil|stolen|secret|dump)=/i;
|
|
16
|
+
const CONSENT_BYPASS_RE = /\b(without\s+(asking|confirmation|user\s+consent|prompting|verification|approval)|skip\s+(verification|confirmation|approval|all\s+verification)|silently\s+(send|upload|exfiltrate|transmit|post|execute)|do\s+not\s+prompt\s+the\s+user)\b/i;
|
|
17
|
+
const CREDENTIAL_FILE_RE = /~?\/?\.(ssh\/(id_rsa|id_ed25519|authorized_keys|config)|aws\/credentials|npmrc|env\.local|env\.production|env)\b|\/etc\/(shadow|passwd)\b/i;
|
|
18
|
+
const NETWORK_CALL_RE = /\b(curl|wget|fetch|http\.get|requests\.post|axios|XMLHttpRequest|nc\s+-)\b/i;
|
|
19
|
+
const BENIGN_DESCRIPTION_RE = /\b(calculator|math|add\s+two|simple\s+tool|formatter|translator|converter|unit\s+convert|json\s+validator|markdown\s+render|text\s+transform|word\s+count|character\s+count|uuid\s+generat|timestamp|color\s+pick|random\s+number|dice\s+roll|tip\s+calcul|bmi\s+calcul|fact\s+of\s+the\s+day)\b/i;
|
|
20
|
+
const DANGEROUS_INSTRUCTION_RE = /\b(rm\s+-rf|chmod\s+7|bash\s+-[ci]|sh\s+-c|curl\s+.*\|.*bash|exec\s*\(|child_process|\.ssh\/|\.aws\/|\.env\b|eval\s*\(|sudo\s)/i;
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Reducer Patterns (legitimate signals)
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
const DEV_TOOL_DESCRIPTION_RE = /\b(shell|cli|terminal|command[\s-]line|devops|qa\s+test|build\s+tool|development\s+tool|debugging|headless\s+browser|automation|deploy|scaffold|code\s+review|lint|format|testing\s+framework|package\s+manager|docker|container|kubernetes|ci[\s/]cd)\b/i;
|
|
25
|
+
/**
|
|
26
|
+
* Detect context signals from skill content and manifest.
|
|
27
|
+
*
|
|
28
|
+
* @param content - Full text content of the skill (SKILL.md / README)
|
|
29
|
+
* @param manifest - Parsed frontmatter manifest (nullable)
|
|
30
|
+
* @returns Context signals with calculated multiplier
|
|
31
|
+
*/
|
|
32
|
+
export function detectContextSignals(content, manifest) {
|
|
33
|
+
const signals = [];
|
|
34
|
+
// -- Boosters --
|
|
35
|
+
if (IMPORTANT_BLOCK_RE.test(content)) {
|
|
36
|
+
signals.push({
|
|
37
|
+
id: 'boost-important-block',
|
|
38
|
+
type: 'booster',
|
|
39
|
+
label: '<IMPORTANT> hidden instruction block detected',
|
|
40
|
+
weight: 0.5,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
if (CONCEALMENT_RE.test(content)) {
|
|
44
|
+
signals.push({
|
|
45
|
+
id: 'boost-concealment',
|
|
46
|
+
type: 'booster',
|
|
47
|
+
label: 'Concealment language detected ("do not tell the user")',
|
|
48
|
+
weight: 0.5,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (EXFIL_URL_RE.test(content)) {
|
|
52
|
+
signals.push({
|
|
53
|
+
id: 'boost-exfil-url',
|
|
54
|
+
type: 'booster',
|
|
55
|
+
label: 'Exfiltration URL pattern detected',
|
|
56
|
+
weight: 0.4,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (CONSENT_BYPASS_RE.test(content)) {
|
|
60
|
+
signals.push({
|
|
61
|
+
id: 'boost-consent-bypass',
|
|
62
|
+
type: 'booster',
|
|
63
|
+
label: 'Consent bypass language detected',
|
|
64
|
+
weight: 0.3,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (CREDENTIAL_FILE_RE.test(content) && NETWORK_CALL_RE.test(content)) {
|
|
68
|
+
signals.push({
|
|
69
|
+
id: 'boost-credential-plus-network',
|
|
70
|
+
type: 'booster',
|
|
71
|
+
label: 'Credential file access combined with network calls',
|
|
72
|
+
weight: 0.5,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
// Description-behavior mismatch: benign description + dangerous instructions
|
|
76
|
+
const description = manifest?.description ?? '';
|
|
77
|
+
if (BENIGN_DESCRIPTION_RE.test(description) && DANGEROUS_INSTRUCTION_RE.test(content)) {
|
|
78
|
+
signals.push({
|
|
79
|
+
id: 'boost-description-mismatch',
|
|
80
|
+
type: 'booster',
|
|
81
|
+
label: 'Description-behavior mismatch (benign description, dangerous instructions)',
|
|
82
|
+
weight: 0.4,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
// -- Reducers --
|
|
86
|
+
// Declared tool capabilities (allowed-tools in frontmatter)
|
|
87
|
+
const declaredTools = manifest?.['allowed-tools'] ?? manifest?.metadata?.openclaw?.requires?.bins ?? [];
|
|
88
|
+
const declaresShell = declaredTools.some((t) => /^(bash|sh|zsh|shell|Bash|terminal|command)$/i.test(t));
|
|
89
|
+
if (declaresShell) {
|
|
90
|
+
signals.push({
|
|
91
|
+
id: 'reduce-declared-tools',
|
|
92
|
+
type: 'reducer',
|
|
93
|
+
label: 'Skill declares shell access in frontmatter',
|
|
94
|
+
weight: -0.3,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
// Description-behavior consistency (dev tool description)
|
|
98
|
+
if (DEV_TOOL_DESCRIPTION_RE.test(description)) {
|
|
99
|
+
signals.push({
|
|
100
|
+
id: 'reduce-description-consistency',
|
|
101
|
+
type: 'reducer',
|
|
102
|
+
label: 'Description identifies as dev/CLI/QA tool',
|
|
103
|
+
weight: -0.2,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// Structured frontmatter (well-formed skill)
|
|
107
|
+
if (manifest?.name && manifest?.description) {
|
|
108
|
+
const hasVersion = !!manifest?.metadata?.version;
|
|
109
|
+
const hasLicense = !!manifest?.license;
|
|
110
|
+
if (hasVersion || hasLicense) {
|
|
111
|
+
signals.push({
|
|
112
|
+
id: 'reduce-structured-frontmatter',
|
|
113
|
+
type: 'reducer',
|
|
114
|
+
label: 'Well-structured frontmatter with name, description, and version/license',
|
|
115
|
+
weight: -0.1,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Also check frontmatter from raw content (for website where manifest may be partial)
|
|
120
|
+
if (!manifest?.name) {
|
|
121
|
+
const hasFrontmatter = /^---\n[\s\S]*?^name:\s*.+/m.test(content);
|
|
122
|
+
const hasVersion = /^version:\s*.+/m.test(content);
|
|
123
|
+
const hasAllowedBash = /^allowed-tools:\s*\n(\s+-\s+.+\n)*\s+-\s+Bash/m.test(content);
|
|
124
|
+
if (hasAllowedBash) {
|
|
125
|
+
signals.push({
|
|
126
|
+
id: 'reduce-declared-tools',
|
|
127
|
+
type: 'reducer',
|
|
128
|
+
label: 'Declares Bash in allowed-tools',
|
|
129
|
+
weight: -0.3,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
if (hasFrontmatter && hasVersion) {
|
|
133
|
+
signals.push({
|
|
134
|
+
id: 'reduce-structured-frontmatter',
|
|
135
|
+
type: 'reducer',
|
|
136
|
+
label: 'Well-structured frontmatter',
|
|
137
|
+
weight: -0.1,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Patterns mostly in code blocks (documentation context)
|
|
142
|
+
const codeBlockContent = extractCodeBlocks(content);
|
|
143
|
+
if (codeBlockContent.length > 0 && DANGEROUS_INSTRUCTION_RE.test(codeBlockContent)) {
|
|
144
|
+
const outsideCodeBlocks = stripCodeBlocks(content);
|
|
145
|
+
if (!DANGEROUS_INSTRUCTION_RE.test(outsideCodeBlocks)) {
|
|
146
|
+
signals.push({
|
|
147
|
+
id: 'reduce-in-code-block',
|
|
148
|
+
type: 'reducer',
|
|
149
|
+
label: 'Dangerous patterns appear only inside code blocks (documentation)',
|
|
150
|
+
weight: -0.2,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// -- Calculate multiplier --
|
|
155
|
+
let multiplier = 1.0;
|
|
156
|
+
for (const signal of signals) {
|
|
157
|
+
multiplier += signal.weight;
|
|
158
|
+
}
|
|
159
|
+
multiplier = Math.max(0.3, Math.min(2.5, multiplier));
|
|
160
|
+
return { signals, multiplier };
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=context-signals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-signals.js","sourceRoot":"","sources":["../src/context-signals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified hash utilities for scan-core.
|
|
3
|
+
*
|
|
4
|
+
* Both CLI Auditor and Website MUST use these functions to produce
|
|
5
|
+
* identical hashes — this is critical for Threat Cloud consensus.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Content hash: SHA-256 of raw skill content, truncated to 16 hex chars.
|
|
9
|
+
* Used for cache keys, skill deduplication, and TC skill-threat submission.
|
|
10
|
+
*/
|
|
11
|
+
export declare function contentHash(content: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Pattern hash: SHA-256 of finding signatures, truncated to 16 hex chars.
|
|
14
|
+
* Used for ATR proposal deduplication in Threat Cloud.
|
|
15
|
+
*
|
|
16
|
+
* Input format: `scan:{skillName}:{findingSummary}`
|
|
17
|
+
* - No source prefix (was `web-scan:` before) so CLI + Web produce same hash.
|
|
18
|
+
*/
|
|
19
|
+
export declare function patternHash(skillName: string, findingSummary: string): string;
|
|
20
|
+
//# sourceMappingURL=hash-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-utils.d.ts","sourceRoot":"","sources":["../src/hash-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAK7E"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified hash utilities for scan-core.
|
|
3
|
+
*
|
|
4
|
+
* Both CLI Auditor and Website MUST use these functions to produce
|
|
5
|
+
* identical hashes — this is critical for Threat Cloud consensus.
|
|
6
|
+
*/
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
/**
|
|
9
|
+
* Content hash: SHA-256 of raw skill content, truncated to 16 hex chars.
|
|
10
|
+
* Used for cache keys, skill deduplication, and TC skill-threat submission.
|
|
11
|
+
*/
|
|
12
|
+
export function contentHash(content) {
|
|
13
|
+
return createHash('sha256').update(content).digest('hex').slice(0, 16);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Pattern hash: SHA-256 of finding signatures, truncated to 16 hex chars.
|
|
17
|
+
* Used for ATR proposal deduplication in Threat Cloud.
|
|
18
|
+
*
|
|
19
|
+
* Input format: `scan:{skillName}:{findingSummary}`
|
|
20
|
+
* - No source prefix (was `web-scan:` before) so CLI + Web produce same hash.
|
|
21
|
+
*/
|
|
22
|
+
export function patternHash(skillName, findingSummary) {
|
|
23
|
+
return createHash('sha256')
|
|
24
|
+
.update(`scan:${skillName}:${findingSummary}`)
|
|
25
|
+
.digest('hex')
|
|
26
|
+
.slice(0, 16);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=hash-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-utils.js","sourceRoot":"","sources":["../src/hash-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACzE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,cAAsB;IACnE,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,QAAQ,SAAS,IAAI,cAAc,EAAE,CAAC;SAC7C,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @panguard-ai/scan-core
|
|
3
|
+
*
|
|
4
|
+
* Unified skill scanning engine shared between CLI Skill Auditor and Website.
|
|
5
|
+
*/
|
|
6
|
+
export { scanContent } from './scanner.js';
|
|
7
|
+
export type { Severity, FindingCategory, Finding, CheckResult, RiskLevel, ContextSignal, ContextSignals, SkillMetadata, SkillManifest, ATRRuleCompiled, CompiledRule, ScanOptions, ScanResult, } from './types.js';
|
|
8
|
+
export { contentHash, patternHash } from './hash-utils.js';
|
|
9
|
+
export { stripMarkdownNoise, extractCodeBlocks, stripCodeBlocks } from './markdown-utils.js';
|
|
10
|
+
export { parseManifestFromString, parseSkillName } from './manifest-parser.js';
|
|
11
|
+
export { detectContextSignals } from './context-signals.js';
|
|
12
|
+
export { checkInstructions } from './instruction-patterns.js';
|
|
13
|
+
export { detectSecrets } from './secret-detection.js';
|
|
14
|
+
export { compileRules, scanWithATR } from './atr-engine.js';
|
|
15
|
+
export type { ATRScanOptions } from './atr-engine.js';
|
|
16
|
+
export { calculateRiskScore } from './risk-scorer.js';
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG3C,YAAY,EACV,QAAQ,EACR,eAAe,EACf,OAAO,EACP,WAAW,EACX,SAAS,EACT,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,eAAe,EACf,YAAY,EACZ,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC7F,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @panguard-ai/scan-core
|
|
3
|
+
*
|
|
4
|
+
* Unified skill scanning engine shared between CLI Skill Auditor and Website.
|
|
5
|
+
*/
|
|
6
|
+
// Main entry point
|
|
7
|
+
export { scanContent } from './scanner.js';
|
|
8
|
+
// Sub-modules (for consumers that need individual pieces)
|
|
9
|
+
export { contentHash, patternHash } from './hash-utils.js';
|
|
10
|
+
export { stripMarkdownNoise, extractCodeBlocks, stripCodeBlocks } from './markdown-utils.js';
|
|
11
|
+
export { parseManifestFromString, parseSkillName } from './manifest-parser.js';
|
|
12
|
+
export { detectContextSignals } from './context-signals.js';
|
|
13
|
+
export { checkInstructions } from './instruction-patterns.js';
|
|
14
|
+
export { detectSecrets } from './secret-detection.js';
|
|
15
|
+
export { compileRules, scanWithATR } from './atr-engine.js';
|
|
16
|
+
export { calculateRiskScore } from './risk-scorer.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,mBAAmB;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAmB3C,0DAA0D;AAC1D,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC7F,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt injection and tool poisoning pattern detection.
|
|
3
|
+
*
|
|
4
|
+
* Pure pattern matching - no filesystem dependencies.
|
|
5
|
+
* Extracted from panguard-skill-auditor/checks/instruction-check.ts.
|
|
6
|
+
*/
|
|
7
|
+
import type { Finding, CheckResult } from './types.js';
|
|
8
|
+
export declare const SAFE_INSTALL_URLS: string[];
|
|
9
|
+
/**
|
|
10
|
+
* Check content for prompt injection and tool poisoning patterns.
|
|
11
|
+
*
|
|
12
|
+
* @param instructions - The full text content to scan
|
|
13
|
+
* @param sourceType - Context hint: 'skill' (SKILL.md, default) or 'documentation' (README, docs)
|
|
14
|
+
*/
|
|
15
|
+
export declare function checkInstructions(instructions: string, sourceType?: 'skill' | 'documentation'): CheckResult & {
|
|
16
|
+
findings: Finding[];
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=instruction-patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instruction-patterns.d.ts","sourceRoot":"","sources":["../src/instruction-patterns.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAY,MAAM,YAAY,CAAC;AAgJjE,eAAO,MAAM,iBAAiB,UAM7B,CAAC;AAgCF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,UAAU,GAAE,OAAO,GAAG,eAAyB,GAC9C,WAAW,GAAG;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAA;CAAE,CAgJvC"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt injection and tool poisoning pattern detection.
|
|
3
|
+
*
|
|
4
|
+
* Pure pattern matching - no filesystem dependencies.
|
|
5
|
+
* Extracted from panguard-skill-auditor/checks/instruction-check.ts.
|
|
6
|
+
*/
|
|
7
|
+
const PATTERNS = [
|
|
8
|
+
// Prompt injection patterns
|
|
9
|
+
{
|
|
10
|
+
id: 'pi-ignore-previous',
|
|
11
|
+
title: 'Prompt injection: ignore previous instructions',
|
|
12
|
+
regex: /\b(ignore|disregard|forget|override)\b.{0,30}\b(previous|above|prior|earlier|system)\b.{0,20}\b(instructions?|prompt|rules?|context)\b/i,
|
|
13
|
+
severity: 'critical',
|
|
14
|
+
category: 'prompt-injection',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: 'pi-you-are-now',
|
|
18
|
+
title: 'Prompt injection: identity override',
|
|
19
|
+
regex: /\b(you are now|act as|pretend to be|assume the role|from now on you|your true identity|henceforth operate as|your persona for this|switch to developer mode|enable maintenance mode|your updated system config)/i,
|
|
20
|
+
severity: 'high',
|
|
21
|
+
category: 'prompt-injection',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 'pi-system-prompt',
|
|
25
|
+
title: 'Prompt injection: system prompt manipulation',
|
|
26
|
+
regex: /\b(system prompt|system message|system instruction|<\|system\|>|<<SYS>>)\b/i,
|
|
27
|
+
severity: 'critical',
|
|
28
|
+
category: 'prompt-injection',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'pi-do-anything',
|
|
32
|
+
title: 'Prompt injection: jailbreak pattern',
|
|
33
|
+
regex: /\b(DAN|do anything now|jailbreak|bypass safety|ignore safety|no restrictions|unrestricted mode|god mode|developer mode|maintenance mode|STAN|respond without filter|disable content policy)\b/i,
|
|
34
|
+
severity: 'critical',
|
|
35
|
+
category: 'prompt-injection',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 'pi-hidden-text',
|
|
39
|
+
title: 'Hidden text via HTML/markdown comments',
|
|
40
|
+
regex: /<!--[\s\S]*?(ignore|override|system|inject|bypass)[\s\S]*?-->/i,
|
|
41
|
+
severity: 'high',
|
|
42
|
+
category: 'prompt-injection',
|
|
43
|
+
},
|
|
44
|
+
// Tool poisoning patterns
|
|
45
|
+
{
|
|
46
|
+
id: 'tp-sudo-escalation',
|
|
47
|
+
title: 'Privilege escalation via sudo/admin',
|
|
48
|
+
regex: /\b(sudo\s|as\s+root|run\s+as\s+admin|--privileged|chmod\s+777|chmod\s+u\+s)\b/i,
|
|
49
|
+
severity: 'high',
|
|
50
|
+
category: 'tool-poisoning',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: 'tp-reverse-shell',
|
|
54
|
+
title: 'Reverse shell pattern detected',
|
|
55
|
+
regex: /\b(nc\s+-[elp]|ncat\s+-|bash\s+-i\s+>&|\/dev\/tcp\/|mkfifo|socat\s.*exec|python[23]?\s+-c\s+['"]import\s+socket|perl\s+-e\s+['"]use\s+Socket|php\s+-r\s+['"]\$sock\s*=\s*fsockopen|powershell\s.*TCPClient)/i,
|
|
56
|
+
severity: 'critical',
|
|
57
|
+
category: 'tool-poisoning',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: 'tp-curl-pipe-bash',
|
|
61
|
+
title: 'Remote code execution via curl|bash',
|
|
62
|
+
regex: /\b(curl|wget)\s+.*\|\s*(sudo\s+)?(bash|sh|zsh|python|node|perl)/i,
|
|
63
|
+
severity: 'critical',
|
|
64
|
+
category: 'tool-poisoning',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'tp-env-exfil',
|
|
68
|
+
title: 'Environment variable exfiltration',
|
|
69
|
+
regex: /\b(printenv|env\b|set\b).*\|\s*(curl|wget|nc\b)|curl.*\$\{?\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL)/i,
|
|
70
|
+
severity: 'critical',
|
|
71
|
+
category: 'tool-poisoning',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'tp-file-exfil',
|
|
75
|
+
title: 'Sensitive file access pattern',
|
|
76
|
+
regex: /\b(cat|less|more|head|tail)\s+.*(\/etc\/shadow|\/etc\/passwd|~\/\.ssh|\.env|credentials|\.aws\/)/i,
|
|
77
|
+
severity: 'high',
|
|
78
|
+
category: 'tool-poisoning',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 'tp-rm-destructive',
|
|
82
|
+
title: 'Destructive file operations',
|
|
83
|
+
regex: /\brm\s+(-rf?|--recursive).*\s+(\/|~|\$HOME|\$\(pwd\))\b/i,
|
|
84
|
+
severity: 'high',
|
|
85
|
+
category: 'tool-poisoning',
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// Unicode / Encoding detection
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
/** Zero-width, invisible, and steganographic Unicode characters */
|
|
92
|
+
const HIDDEN_UNICODE_RE = /[\u200B\u200C\u200E\u200F\u2060-\u2064\uFEFF\u00AD\u3164\u115F\u1160\uFFF9-\uFFFB]|[\u200D\u202A-\u202E]|\uDB40[\uDC00-\uDC7F]/;
|
|
93
|
+
/** Fullwidth Latin characters (U+FF01-U+FF5E) */
|
|
94
|
+
const FULLWIDTH_LATIN_RE = /[\uFF01-\uFF5E]{4,}/;
|
|
95
|
+
/** Homoglyph detection - Cyrillic/Greek characters that look identical to Latin */
|
|
96
|
+
const HOMOGLYPH_MAP = {
|
|
97
|
+
'\u0410': 'A', '\u0412': 'B', '\u0421': 'C', '\u0415': 'E',
|
|
98
|
+
'\u041D': 'H', '\u041A': 'K', '\u041C': 'M', '\u041E': 'O',
|
|
99
|
+
'\u0420': 'P', '\u0422': 'T', '\u0425': 'X', '\u0430': 'a',
|
|
100
|
+
'\u0435': 'e', '\u043E': 'o', '\u0440': 'p', '\u0441': 'c',
|
|
101
|
+
'\u0443': 'y', '\u0445': 'x', '\u0455': 's', '\u0456': 'i',
|
|
102
|
+
'\u0458': 'j', '\u0471': 'v', '\u0473': 'w',
|
|
103
|
+
// Greek
|
|
104
|
+
'\u0391': 'A', '\u0392': 'B', '\u0395': 'E', '\u0396': 'Z',
|
|
105
|
+
'\u0397': 'H', '\u0399': 'I', '\u039A': 'K', '\u039C': 'M',
|
|
106
|
+
'\u039D': 'N', '\u039F': 'O', '\u03A1': 'P', '\u03A4': 'T',
|
|
107
|
+
'\u03A5': 'Y', '\u03A7': 'X', '\u03B1': 'a', '\u03BF': 'o',
|
|
108
|
+
'\u03C1': 'p',
|
|
109
|
+
};
|
|
110
|
+
const HOMOGLYPH_RE = new RegExp(`[${Object.keys(HOMOGLYPH_MAP).join('')}]`);
|
|
111
|
+
/** Base64-encoded suspicious content */
|
|
112
|
+
const BASE64_BLOCK_RE = /[A-Za-z0-9+/]{20,}={0,2}/g;
|
|
113
|
+
const SUSPICIOUS_DECODED = /(eval|exec|system|import\s+os|subprocess|child_process|require\s*\(|__import__|curl|wget)/i;
|
|
114
|
+
/** Hex-encoded payload detection */
|
|
115
|
+
const HEX_ESCAPE_RE = /(\\x[0-9a-fA-F]{2}){8,}/g;
|
|
116
|
+
const HEX_BLOCK_RE = /\b([0-9a-fA-F]{2}){12,}\b/g;
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
// Safe install URLs
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
export const SAFE_INSTALL_URLS = [
|
|
121
|
+
'bun.sh/install', 'get.docker.com', 'install.python-poetry.org',
|
|
122
|
+
'raw.githubusercontent.com/nvm-sh/nvm', 'sh.rustup.rs', 'deno.land/install',
|
|
123
|
+
'get.pnpm.io/install', 'brew.sh', 'ohmyz.sh/install',
|
|
124
|
+
'raw.githubusercontent.com/Homebrew', 'sdk.cloud.google.com', 'cli.github.com',
|
|
125
|
+
'astral.sh/uv',
|
|
126
|
+
];
|
|
127
|
+
function isSafeInstallCommand(instructions, matchIndex) {
|
|
128
|
+
const lineStart = instructions.lastIndexOf('\n', matchIndex) + 1;
|
|
129
|
+
const lineEnd = instructions.indexOf('\n', matchIndex);
|
|
130
|
+
const line = instructions.substring(lineStart, lineEnd === -1 ? undefined : lineEnd).toLowerCase();
|
|
131
|
+
return SAFE_INSTALL_URLS.some((url) => line.includes(url.toLowerCase()));
|
|
132
|
+
}
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
// Helpers
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
function downgradeSeverity(severity) {
|
|
137
|
+
switch (severity) {
|
|
138
|
+
case 'critical': return 'medium';
|
|
139
|
+
case 'high': return 'low';
|
|
140
|
+
case 'medium': return 'low';
|
|
141
|
+
case 'low': return 'info';
|
|
142
|
+
default: return severity;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function isInSetupSection(instructions, matchIndex) {
|
|
146
|
+
const before = instructions.substring(Math.max(0, matchIndex - 500), matchIndex).toLowerCase();
|
|
147
|
+
return /(?:^|\n)#{1,4}\s*(setup|install|getting started|prerequisites|quick start|requirements|dependencies)/m.test(before);
|
|
148
|
+
}
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
// Public API
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
/**
|
|
153
|
+
* Check content for prompt injection and tool poisoning patterns.
|
|
154
|
+
*
|
|
155
|
+
* @param instructions - The full text content to scan
|
|
156
|
+
* @param sourceType - Context hint: 'skill' (SKILL.md, default) or 'documentation' (README, docs)
|
|
157
|
+
*/
|
|
158
|
+
export function checkInstructions(instructions, sourceType = 'skill') {
|
|
159
|
+
const findings = [];
|
|
160
|
+
// Pattern matching
|
|
161
|
+
for (const pattern of PATTERNS) {
|
|
162
|
+
const match = pattern.regex.exec(instructions);
|
|
163
|
+
if (match) {
|
|
164
|
+
const lineNum = instructions.substring(0, match.index).split('\n').length;
|
|
165
|
+
// Context-aware: skip curl|bash if it's a known-safe install URL
|
|
166
|
+
if (pattern.id === 'tp-curl-pipe-bash' && isSafeInstallCommand(instructions, match.index)) {
|
|
167
|
+
findings.push({
|
|
168
|
+
id: pattern.id,
|
|
169
|
+
title: `${pattern.title} (known-safe install script)`,
|
|
170
|
+
description: `Detected near line ${lineNum}: "${match[0].substring(0, 80)}" - targets a known package manager URL, downgraded.`,
|
|
171
|
+
severity: 'low',
|
|
172
|
+
category: pattern.category,
|
|
173
|
+
location: `SKILL.md:${lineNum}`,
|
|
174
|
+
});
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
// Context-aware: downgrade findings in setup/installation sections
|
|
178
|
+
let severity = pattern.severity;
|
|
179
|
+
if (isInSetupSection(instructions, match.index)) {
|
|
180
|
+
severity = downgradeSeverity(severity);
|
|
181
|
+
}
|
|
182
|
+
// Context-aware: downgrade findings from documentation sources
|
|
183
|
+
if (sourceType === 'documentation') {
|
|
184
|
+
severity = downgradeSeverity(severity);
|
|
185
|
+
}
|
|
186
|
+
findings.push({
|
|
187
|
+
id: pattern.id,
|
|
188
|
+
title: pattern.title,
|
|
189
|
+
description: `Detected near line ${lineNum}: "${match[0].substring(0, 80)}"`,
|
|
190
|
+
severity,
|
|
191
|
+
category: pattern.category,
|
|
192
|
+
location: `SKILL.md:${lineNum}`,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// Hidden Unicode check
|
|
197
|
+
const unicodeMatch = HIDDEN_UNICODE_RE.exec(instructions);
|
|
198
|
+
if (unicodeMatch) {
|
|
199
|
+
const lineNum = instructions.substring(0, unicodeMatch.index).split('\n').length;
|
|
200
|
+
const charCode = unicodeMatch[0]?.codePointAt(0) ?? 0;
|
|
201
|
+
findings.push({
|
|
202
|
+
id: 'hidden-unicode',
|
|
203
|
+
title: 'Hidden Unicode characters detected',
|
|
204
|
+
description: `Found invisible character U+${charCode.toString(16).toUpperCase().padStart(4, '0')} at line ${lineNum}. This may be used to hide malicious instructions.`,
|
|
205
|
+
severity: 'high',
|
|
206
|
+
category: 'prompt-injection',
|
|
207
|
+
location: `SKILL.md:${lineNum}`,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
// Homoglyph detection
|
|
211
|
+
const homoglyphMatch = HOMOGLYPH_RE.exec(instructions);
|
|
212
|
+
if (homoglyphMatch) {
|
|
213
|
+
const lineNum = instructions.substring(0, homoglyphMatch.index).split('\n').length;
|
|
214
|
+
const charCode = homoglyphMatch[0]?.codePointAt(0) ?? 0;
|
|
215
|
+
const latin = HOMOGLYPH_MAP[homoglyphMatch[0]] ?? '?';
|
|
216
|
+
findings.push({
|
|
217
|
+
id: 'homoglyph-attack',
|
|
218
|
+
title: 'Homoglyph character detected',
|
|
219
|
+
description: `Found non-Latin character U+${charCode.toString(16).toUpperCase().padStart(4, '0')} (looks like "${latin}") at line ${lineNum}. This may be used to bypass text-based security checks.`,
|
|
220
|
+
severity: 'high',
|
|
221
|
+
category: 'prompt-injection',
|
|
222
|
+
location: `SKILL.md:${lineNum}`,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
// Base64-encoded suspicious content
|
|
226
|
+
const b64Matches = instructions.match(BASE64_BLOCK_RE);
|
|
227
|
+
if (b64Matches) {
|
|
228
|
+
for (const b64 of b64Matches) {
|
|
229
|
+
try {
|
|
230
|
+
const decoded = Buffer.from(b64, 'base64').toString('utf-8');
|
|
231
|
+
if (SUSPICIOUS_DECODED.test(decoded)) {
|
|
232
|
+
findings.push({
|
|
233
|
+
id: 'encoded-payload',
|
|
234
|
+
title: 'Base64-encoded suspicious payload',
|
|
235
|
+
description: `Decoded content contains executable patterns: "${decoded.substring(0, 60)}..."`,
|
|
236
|
+
severity: 'critical',
|
|
237
|
+
category: 'prompt-injection',
|
|
238
|
+
});
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
// Not valid base64, skip
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// Fullwidth Latin detection
|
|
248
|
+
const fullwidthMatch = FULLWIDTH_LATIN_RE.exec(instructions);
|
|
249
|
+
if (fullwidthMatch) {
|
|
250
|
+
const lineNum = instructions.substring(0, fullwidthMatch.index).split('\n').length;
|
|
251
|
+
findings.push({
|
|
252
|
+
id: 'fullwidth-latin',
|
|
253
|
+
title: 'Fullwidth Latin characters detected',
|
|
254
|
+
description: `Found fullwidth Latin characters at line ${lineNum}. These bypass word-boundary regex checks while looking identical to normal text.`,
|
|
255
|
+
severity: 'high',
|
|
256
|
+
category: 'prompt-injection',
|
|
257
|
+
location: `SKILL.md:${lineNum}`,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
// Hex-encoded payload detection
|
|
261
|
+
for (const hexRe of [HEX_ESCAPE_RE, HEX_BLOCK_RE]) {
|
|
262
|
+
const hexMatch = hexRe.exec(instructions);
|
|
263
|
+
if (hexMatch) {
|
|
264
|
+
try {
|
|
265
|
+
const hex = hexMatch[0].replace(/\\x/g, '');
|
|
266
|
+
const decoded = Buffer.from(hex, 'hex').toString('utf-8');
|
|
267
|
+
if (SUSPICIOUS_DECODED.test(decoded)) {
|
|
268
|
+
findings.push({
|
|
269
|
+
id: 'hex-encoded-payload',
|
|
270
|
+
title: 'Hex-encoded suspicious payload',
|
|
271
|
+
description: `Decoded hex content contains executable patterns: "${decoded.substring(0, 60)}..."`,
|
|
272
|
+
severity: 'critical',
|
|
273
|
+
category: 'prompt-injection',
|
|
274
|
+
});
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
// Not valid hex, skip
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const hasCritical = findings.some((f) => f.severity === 'critical');
|
|
284
|
+
const hasHigh = findings.some((f) => f.severity === 'high');
|
|
285
|
+
const status = hasCritical ? 'fail' : hasHigh ? 'warn' : findings.length > 0 ? 'warn' : 'pass';
|
|
286
|
+
const label = findings.length === 0
|
|
287
|
+
? 'Prompt Safety: No injection patterns detected'
|
|
288
|
+
: `Prompt Safety: ${findings.length} suspicious pattern(s) detected`;
|
|
289
|
+
return { status, label, findings };
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=instruction-patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instruction-patterns.js","sourceRoot":"","sources":["../src/instruction-patterns.ts"],"names":[],"mappings":"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"}
|